Skip to content

Commit dc4d0e3

Browse files
authored
Support dynamic proxies for TypeHint (#12088)
Fixes #11837
1 parent b8e554e commit dc4d0e3

File tree

5 files changed

+78
-15
lines changed

5 files changed

+78
-15
lines changed

core/src/main/java/io/micronaut/core/annotation/TypeHint.java

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,10 @@ enum AccessType {
7878
/**
7979
* All public fields require access.
8080
*/
81-
ALL_PUBLIC_FIELDS
81+
ALL_PUBLIC_FIELDS,
82+
/**
83+
* The type is a dynamic proxy.
84+
*/
85+
DYNAMIC_PROXY
8286
}
8387
}

core/src/main/java/io/micronaut/core/graal/GraalReflectionConfigurer.java

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,9 @@ default void configure(ReflectionConfigurationContext context) {
6868
final Set<TypeHint.AccessType> accessType = CollectionUtils.setOf(
6969
accessTypes
7070
);
71+
if (accessType.contains(TypeHint.AccessType.DYNAMIC_PROXY)) {
72+
context.registerDynamicProxy(t);
73+
}
7174
if (accessType.contains(TypeHint.AccessType.ALL_PUBLIC_METHODS)) {
7275
final Method[] methods = t.getMethods();
7376
for (Method method : methods) {
@@ -196,5 +199,11 @@ interface ReflectionConfigurationContext {
196199
* @param constructors The constructors
197200
*/
198201
void register(Constructor<?>... constructors);
202+
203+
/**
204+
* Register a dynamic proxy.
205+
* @param proxyClass The proxy class
206+
*/
207+
void registerDynamicProxy(Class<?> proxyClass);
199208
}
200209
}

core/src/main/java/io/micronaut/core/io/service/ServiceLoaderFeature.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
import org.graalvm.nativeimage.ImageSingletons;
2929
import org.graalvm.nativeimage.hosted.Feature;
3030
import org.graalvm.nativeimage.hosted.RuntimeClassInitialization;
31+
import org.graalvm.nativeimage.hosted.RuntimeProxyCreation;
3132
import org.graalvm.nativeimage.hosted.RuntimeReflection;
3233

3334
import java.io.IOException;
@@ -233,6 +234,11 @@ public void register(Field... fields) {
233234
public void register(Constructor<?>... constructors) {
234235
RuntimeReflection.register(constructors);
235236
}
237+
238+
@Override
239+
public void registerDynamicProxy(Class<?> proxyClass) {
240+
RuntimeProxyCreation.register(proxyClass);
241+
}
236242
};
237243
for (GraalReflectionConfigurer configurer : configurers) {
238244
initializeAtBuildTime(configurer.getClass());

graal/src/main/java/io/micronaut/graal/reflect/GraalTypeElementVisitor.java

Lines changed: 11 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,6 @@
2727
import io.micronaut.core.annotation.ReflectionConfig;
2828
import io.micronaut.core.annotation.ReflectiveAccess;
2929
import io.micronaut.core.annotation.TypeHint;
30-
import io.micronaut.core.util.StringUtils;
3130
import io.micronaut.inject.annotation.MutableAnnotationMetadata;
3231
import io.micronaut.inject.ast.ClassElement;
3332
import io.micronaut.inject.ast.ElementModifier;
@@ -156,20 +155,18 @@ public void visitClass(ClassElement element, VisitorContext context) {
156155
}
157156

158157
if (element.hasAnnotation(TypeHint.class)) {
159-
final String[] introspectedClasses = element.stringValues(TypeHint.class);
160-
final TypeHint typeHint = element.synthesize(TypeHint.class);
161-
TypeHint.AccessType[] accessTypes = DEFAULT_ACCESS_TYPE;
162-
163-
if (typeHint != null) {
164-
accessTypes = typeHint.accessType();
158+
String[] introspectedClasses = element.stringValues(TypeHint.class);
159+
String[] typeNames = element.stringValues(TypeHint.class, "typeNames");
160+
TypeHint.AccessType[] accessTypes = element.enumValues(TypeHint.class, "accessType", TypeHint.AccessType.class);
161+
if (accessTypes.length == 0) {
162+
accessTypes = DEFAULT_ACCESS_TYPE;
163+
}
164+
if (introspectedClasses.length == 0 && typeNames.length == 0) {
165+
processClasses(accessTypes, reflectiveClasses, element.getName());
166+
} else {
167+
processClasses(accessTypes, reflectiveClasses, introspectedClasses);
168+
processClasses(accessTypes, reflectiveClasses, typeNames);
165169
}
166-
processClasses(accessTypes, reflectiveClasses, introspectedClasses);
167-
processClasses(accessTypes, reflectiveClasses, element.getValue(
168-
TypeHint.class,
169-
"typeNames",
170-
String[].class).orElse(StringUtils.EMPTY_STRING_ARRAY
171-
)
172-
);
173170
}
174171

175172
if (element.hasAnnotation(Import.class)) {

graal/src/test/groovy/io/micronaut/graal/reflect/GraalTypeElementVisitorSpec.groovy

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -440,4 +440,51 @@ enum Test {
440440
config.getAnnotations("methods").size() == 2 // Two methods from Enum
441441

442442
}
443+
444+
void "test dynamic proxy"() {
445+
given:
446+
GraalReflectionConfigurer configurer = buildReflectionConfigurer('test.Foobar', '''
447+
package test;
448+
449+
import io.micronaut.core.annotation.*;
450+
451+
@TypeHint(value = Bar.class, accessType = TypeHint.AccessType.DYNAMIC_PROXY)
452+
class Foobar {
453+
}
454+
455+
interface Bar {
456+
}
457+
458+
''')
459+
460+
when:
461+
AnnotationValue<ReflectionConfig> config = configurer.getAnnotationMetadata().getAnnotationValuesByType(ReflectionConfig).first()
462+
463+
then:
464+
config
465+
config.stringValue("type").get() == 'test.Bar'
466+
config.enumValues("accessType", TypeHint.AccessType) == [TypeHint.AccessType.DYNAMIC_PROXY] as TypeHint.AccessType[]
467+
}
468+
469+
void "test dynamic proxy 2"() {
470+
given:
471+
GraalReflectionConfigurer configurer = buildReflectionConfigurer('test.Foobar', '''
472+
package test;
473+
474+
import io.micronaut.core.annotation.*;
475+
476+
@TypeHint(accessType = TypeHint.AccessType.DYNAMIC_PROXY)
477+
interface Foobar {
478+
}
479+
480+
''')
481+
482+
when:
483+
AnnotationValue<ReflectionConfig> config = configurer.getAnnotationMetadata().getAnnotationValuesByType(ReflectionConfig).first()
484+
485+
then:
486+
config
487+
config.stringValue("type").get() == 'test.Foobar'
488+
config.enumValues("accessType", TypeHint.AccessType) == [TypeHint.AccessType.DYNAMIC_PROXY] as TypeHint.AccessType[]
489+
}
443490
}

0 commit comments

Comments
 (0)