Allow target type of a cglib proxy to be visible
This commit updates the hints of a Cglib proxy's target type so that methods can be invoked and constructors can be introspected. The former is needed as a cglib proxy invokes the target type via reflection. As for that latter, this is required at least by Enhancer#filterConstructors. See gh-28954
This commit is contained in:
parent
c58c827291
commit
9a1b7c5e47
|
|
@ -43,6 +43,10 @@ class GeneratedClassHandler implements BiConsumer<String, byte[]> {
|
||||||
MemberCategory.INVOKE_DECLARED_METHODS,
|
MemberCategory.INVOKE_DECLARED_METHODS,
|
||||||
MemberCategory.DECLARED_FIELDS);
|
MemberCategory.DECLARED_FIELDS);
|
||||||
|
|
||||||
|
private static final Consumer<Builder> asCglibProxyTargetType = hint ->
|
||||||
|
hint.withMembers(MemberCategory.INTROSPECT_DECLARED_CONSTRUCTORS,
|
||||||
|
MemberCategory.INVOKE_DECLARED_METHODS);
|
||||||
|
|
||||||
private final RuntimeHints runtimeHints;
|
private final RuntimeHints runtimeHints;
|
||||||
|
|
||||||
private final GeneratedFiles generatedFiles;
|
private final GeneratedFiles generatedFiles;
|
||||||
|
|
@ -54,9 +58,18 @@ class GeneratedClassHandler implements BiConsumer<String, byte[]> {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void accept(String className, byte[] content) {
|
public void accept(String className, byte[] content) {
|
||||||
this.runtimeHints.reflection().registerType(TypeReference.of(className), asCglibProxy);
|
this.runtimeHints.reflection().registerType(TypeReference.of(className), asCglibProxy)
|
||||||
|
.registerType(TypeReference.of(getTargetTypeClassName(className)), asCglibProxyTargetType);
|
||||||
String path = className.replace(".", "/") + ".class";
|
String path = className.replace(".", "/") + ".class";
|
||||||
this.generatedFiles.addFile(Kind.CLASS, path, new ByteArrayResource(content));
|
this.generatedFiles.addFile(Kind.CLASS, path, new ByteArrayResource(content));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private String getTargetTypeClassName(String proxyClassName) {
|
||||||
|
int index = proxyClassName.indexOf("$$SpringCGLIB$$");
|
||||||
|
if (index == -1) {
|
||||||
|
throw new IllegalArgumentException("Failed to extract target type from " + proxyClassName);
|
||||||
|
}
|
||||||
|
return proxyClassName.substring(0, index);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -30,6 +30,7 @@ import org.springframework.core.io.InputStreamSource;
|
||||||
import org.springframework.core.testfixture.aot.generate.TestGenerationContext;
|
import org.springframework.core.testfixture.aot.generate.TestGenerationContext;
|
||||||
|
|
||||||
import static org.assertj.core.api.Assertions.assertThat;
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
|
import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tests for {@link GeneratedClassHandler}.
|
* Tests for {@link GeneratedClassHandler}.
|
||||||
|
|
@ -50,8 +51,8 @@ class GeneratedClassHandlerTests {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void handlerGenerateRuntimeHints() {
|
void handlerGenerateRuntimeHintsForProxy() {
|
||||||
String className = "com.example.Test$$Proxy$$1";
|
String className = "com.example.Test$$SpringCGLIB$$0";
|
||||||
this.handler.accept(className, TEST_CONTENT);
|
this.handler.accept(className, TEST_CONTENT);
|
||||||
assertThat(RuntimeHintsPredicates.reflection().onType(TypeReference.of(className))
|
assertThat(RuntimeHintsPredicates.reflection().onType(TypeReference.of(className))
|
||||||
.withMemberCategories(MemberCategory.INVOKE_DECLARED_CONSTRUCTORS,
|
.withMemberCategories(MemberCategory.INVOKE_DECLARED_CONSTRUCTORS,
|
||||||
|
|
@ -59,14 +60,31 @@ class GeneratedClassHandlerTests {
|
||||||
.accepts(this.generationContext.getRuntimeHints());
|
.accepts(this.generationContext.getRuntimeHints());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void handlerGenerateRuntimeHintsForTargetType() {
|
||||||
|
String className = "com.example.Test$$SpringCGLIB$$0";
|
||||||
|
this.handler.accept(className, TEST_CONTENT);
|
||||||
|
assertThat(RuntimeHintsPredicates.reflection().onType(TypeReference.of("com.example.Test"))
|
||||||
|
.withMemberCategories(MemberCategory.INTROSPECT_DECLARED_CONSTRUCTORS,
|
||||||
|
MemberCategory.INVOKE_DECLARED_METHODS))
|
||||||
|
.accepts(this.generationContext.getRuntimeHints());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void handlerFailsWithInvalidProxyClassName() {
|
||||||
|
String className = "com.example.Test$$AnotherProxy$$0";
|
||||||
|
assertThatIllegalArgumentException().isThrownBy(() -> this.handler.accept(className, TEST_CONTENT))
|
||||||
|
.withMessageContaining("Failed to extract target type");
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void handlerRegisterGeneratedClass() throws IOException {
|
void handlerRegisterGeneratedClass() throws IOException {
|
||||||
String className = "com.example.Test$$Proxy$$1";
|
String className = "com.example.Test$$SpringCGLIB$$0";
|
||||||
this.handler.accept(className, TEST_CONTENT);
|
this.handler.accept(className, TEST_CONTENT);
|
||||||
InMemoryGeneratedFiles generatedFiles = this.generationContext.getGeneratedFiles();
|
InMemoryGeneratedFiles generatedFiles = this.generationContext.getGeneratedFiles();
|
||||||
assertThat(generatedFiles.getGeneratedFiles(Kind.SOURCE)).isEmpty();
|
assertThat(generatedFiles.getGeneratedFiles(Kind.SOURCE)).isEmpty();
|
||||||
assertThat(generatedFiles.getGeneratedFiles(Kind.RESOURCE)).isEmpty();
|
assertThat(generatedFiles.getGeneratedFiles(Kind.RESOURCE)).isEmpty();
|
||||||
String expectedPath = "com/example/Test$$Proxy$$1.class";
|
String expectedPath = "com/example/Test$$SpringCGLIB$$0.class";
|
||||||
assertThat(generatedFiles.getGeneratedFiles(Kind.CLASS)).containsOnlyKeys(expectedPath);
|
assertThat(generatedFiles.getGeneratedFiles(Kind.CLASS)).containsOnlyKeys(expectedPath);
|
||||||
assertContent(generatedFiles.getGeneratedFiles(Kind.CLASS).get(expectedPath), TEST_CONTENT);
|
assertContent(generatedFiles.getGeneratedFiles(Kind.CLASS).get(expectedPath), TEST_CONTENT);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue