8
8
package org .hibernate .models .internal ;
9
9
10
10
import java .lang .annotation .Annotation ;
11
- import java .lang .reflect .Constructor ;
12
- import java .lang .reflect .InvocationTargetException ;
11
+ import java .lang .invoke .MethodHandle ;
12
+ import java .lang .invoke .MethodHandles ;
13
+ import java .lang .invoke .MethodType ;
13
14
import java .util .Collections ;
14
15
import java .util .List ;
15
16
import java .util .Map ;
26
27
* does not collect annotations from the annotation class as we never care about
27
28
* meta-annotations in these cases.
28
29
*
30
+ * @implNote There are a few cases in Hibernate ORM e.g. where we do care about meta-annotations,
31
+ * but those are handled specially there.
32
+ *
29
33
* @author Steve Ebersole
30
34
*/
31
35
public class OrmAnnotationDescriptor <A extends Annotation , C extends A > extends AbstractAnnotationDescriptor <A > {
32
36
private final Class <C > concreteClass ;
33
37
private final List <AttributeDescriptor <?>> attributeDescriptors ;
34
38
35
- private DynamicCreator <A ,C > dynamicCreator ;
36
- private JdkCreator <A ,C > jdkCreator ;
39
+ private final DynamicCreator <A ,C > dynamicCreator ;
40
+ private final JdkCreator <A ,C > jdkCreator ;
37
41
private JandexCreator <A ,C > jandexCreator ;
38
42
39
43
public OrmAnnotationDescriptor (
@@ -55,6 +59,9 @@ public OrmAnnotationDescriptor(
55
59
56
60
this .concreteClass = concreteClass ;
57
61
this .attributeDescriptors = AnnotationDescriptorBuilding .extractAttributeDescriptors ( annotationType );
62
+
63
+ this .dynamicCreator = new DynamicCreator <>( annotationType , concreteClass );
64
+ this .jdkCreator = new JdkCreator <>( annotationType , concreteClass );
58
65
}
59
66
60
67
@ Override
@@ -66,17 +73,11 @@ public OrmAnnotationDescriptor(
66
73
67
74
@ Override
68
75
public C createUsage (SourceModelBuildingContext context ) {
69
- if ( dynamicCreator == null ) {
70
- dynamicCreator = new DynamicCreator <>( getAnnotationType (), concreteClass );
71
- }
72
76
return dynamicCreator .createUsage ( context );
73
77
}
74
78
75
79
@ Override
76
80
public C createUsage (A jdkAnnotation , SourceModelBuildingContext context ) {
77
- if ( jdkCreator == null ) {
78
- jdkCreator = new JdkCreator <>( getAnnotationType (), concreteClass );
79
- }
80
81
return jdkCreator .createUsage ( jdkAnnotation , context );
81
82
}
82
83
@@ -99,93 +100,105 @@ public String toString() {
99
100
}
100
101
101
102
public static class DynamicCreator <A extends Annotation , C extends A > {
102
- private final Constructor <C > constructor ;
103
+ private final MethodHandle constructor ;
104
+ private final Class <C > concreteClass ;
103
105
104
106
public DynamicCreator (Class <A > annotationType , Class <C > concreteClass ) {
105
- this ( resolveConstructor ( concreteClass ) );
107
+ this ( resolveConstructor ( concreteClass ), concreteClass );
106
108
}
107
109
108
- private static <A extends Annotation , C extends A > Constructor < C > resolveConstructor (Class <C > concreteClass ) {
110
+ private static <A extends Annotation , C extends A > MethodHandle resolveConstructor (Class <C > concreteClass ) {
109
111
try {
110
- return concreteClass .getDeclaredConstructor ( SourceModelBuildingContext .class );
112
+ final MethodType methodType = MethodType .methodType ( void .class , SourceModelBuildingContext .class );
113
+ return MethodHandles .publicLookup ().findConstructor ( concreteClass , methodType );
111
114
}
112
- catch (NoSuchMethodException e ) {
113
- throw new RuntimeException ( e );
115
+ catch (Exception e ) {
116
+ throw new MethodResolutionException ( "Unable to locate default-variant constructor for `" + concreteClass . getName () + "`" , e );
114
117
}
115
118
}
116
119
117
- public DynamicCreator (Constructor <C > constructor ) {
120
+ public DynamicCreator (MethodHandle constructor , Class <C > concreteClass ) {
118
121
this .constructor = constructor ;
122
+ this .concreteClass = concreteClass ;
119
123
}
120
124
121
125
public C createUsage (SourceModelBuildingContext context ) {
122
126
try {
123
- return constructor .newInstance ( context );
127
+ //noinspection unchecked
128
+ return (C ) constructor .invoke ( context );
124
129
}
125
- catch (InvocationTargetException | InstantiationException | IllegalAccessException e ) {
126
- throw new RuntimeException ( e );
130
+ catch (Throwable e ) {
131
+ throw new MethodInvocationException ( "Unable to invoke default-variant constructor for `" + concreteClass . getName () + "`" , e );
127
132
}
128
133
}
129
134
}
130
135
131
136
public static class JdkCreator <A extends Annotation , C extends A > {
132
- private final Constructor <C > constructor ;
137
+ private final MethodHandle constructor ;
138
+ private final Class <C > concreteClass ;
133
139
134
140
public JdkCreator (Class <A > annotationType , Class <C > concreteClass ) {
135
- this ( resolveConstructor ( annotationType , concreteClass ) );
141
+ this ( resolveConstructor ( annotationType , concreteClass ), concreteClass );
136
142
}
137
143
138
- private static <A extends Annotation , C extends A > Constructor < C > resolveConstructor (
144
+ private static <A extends Annotation , C extends A > MethodHandle resolveConstructor (
139
145
Class <A > annotationType ,
140
146
Class <C > concreteClass ) {
141
147
try {
142
- return concreteClass .getDeclaredConstructor ( annotationType , SourceModelBuildingContext .class );
148
+ final MethodType methodType = MethodType .methodType ( void .class , annotationType , SourceModelBuildingContext .class );
149
+ return MethodHandles .publicLookup ().findConstructor ( concreteClass , methodType );
143
150
}
144
- catch (NoSuchMethodException e ) {
145
- throw new RuntimeException ( e );
151
+ catch (Exception e ) {
152
+ throw new MethodResolutionException ( "Unable to locate JDK-variant constructor for `" + concreteClass . getName () + "`" , e );
146
153
}
147
154
}
148
155
149
- public JdkCreator (Constructor <C > constructor ) {
156
+ public JdkCreator (MethodHandle constructor , Class <C > concreteClass ) {
150
157
this .constructor = constructor ;
158
+ this .concreteClass = concreteClass ;
151
159
}
152
160
153
161
public C createUsage (A jdkAnnotation , SourceModelBuildingContext context ) {
154
162
try {
155
- return constructor .newInstance ( jdkAnnotation , context );
163
+ //noinspection unchecked
164
+ return (C ) constructor .invoke ( jdkAnnotation , context );
156
165
}
157
- catch (InvocationTargetException | InstantiationException | IllegalAccessException e ) {
158
- throw new RuntimeException ( e );
166
+ catch (Throwable e ) {
167
+ throw new MethodInvocationException ( "Unable to invoke JDK-variant constructor for `" + concreteClass . getName () + "`" , e );
159
168
}
160
169
}
161
170
}
162
171
163
172
public static class JandexCreator <A extends Annotation , C extends A > {
164
- private final Constructor <C > constructor ;
173
+ private final MethodHandle constructor ;
174
+ private final Class <C > concreteClass ;
165
175
166
176
public JandexCreator (Class <C > concreteClass ) {
167
- this ( resolveConstructor ( concreteClass ) );
177
+ this ( resolveConstructor ( concreteClass ), concreteClass );
168
178
}
169
179
170
- private static <A extends Annotation , C extends A > Constructor < C > resolveConstructor (Class <C > concreteClass ) {
180
+ private static <A extends Annotation , C extends A > MethodHandle resolveConstructor (Class <C > concreteClass ) {
171
181
try {
172
- return concreteClass .getDeclaredConstructor ( AnnotationInstance .class , SourceModelBuildingContext .class );
182
+ final MethodType methodType = MethodType .methodType ( void .class , AnnotationInstance .class , SourceModelBuildingContext .class );
183
+ return MethodHandles .publicLookup ().findConstructor ( concreteClass , methodType );
173
184
}
174
- catch (NoSuchMethodException e ) {
175
- throw new RuntimeException ( e );
185
+ catch (Exception e ) {
186
+ throw new MethodResolutionException ( "Unable to locate Jandex-variant constructor for `" + concreteClass . getName () + "`" , e );
176
187
}
177
188
}
178
189
179
- public JandexCreator (Constructor <C > constructor ) {
190
+ public JandexCreator (MethodHandle constructor , Class <C > concreteClass ) {
180
191
this .constructor = constructor ;
192
+ this .concreteClass = concreteClass ;
181
193
}
182
194
183
195
public C createUsage (AnnotationInstance jandexAnnotation , SourceModelBuildingContext context ) {
184
196
try {
185
- return constructor .newInstance ( jandexAnnotation , context );
197
+ //noinspection unchecked
198
+ return (C ) constructor .invoke ( jandexAnnotation , context );
186
199
}
187
- catch (InvocationTargetException | InstantiationException | IllegalAccessException e ) {
188
- throw new RuntimeException ( e );
200
+ catch (Throwable e ) {
201
+ throw new MethodInvocationException ( "Unable to invoke Jandex-variant constructor for `" + concreteClass . getName () + "`" , e );
189
202
}
190
203
}
191
204
}
0 commit comments