Skip to content

Commit 3a093da

Browse files
committed
#80 - Investigate use of MethodHandles instead of Constructor and Method references
1 parent 02c1f2a commit 3a093da

File tree

6 files changed

+75
-49
lines changed

6 files changed

+75
-49
lines changed

hibernate-models-jandex/src/main/java/org/hibernate/models/jandex/internal/JandexValueHelper.java

+1-2
Original file line numberDiff line numberDiff line change
@@ -60,8 +60,7 @@ public static <V> V extractOptionalValue(
6060
SourceModelBuildingContext modelContext) {
6161
final AnnotationValue value = usage.value( attributeDescriptor.getName() );
6262
if ( value == null ) {
63-
//noinspection unchecked
64-
return (V) attributeDescriptor.getAttributeMethod().getDefaultValue();
63+
return attributeDescriptor.getDefaultValue();
6564
}
6665

6766
return modelContext.as( JandexModelContext.class )

hibernate-models/src/main/java/org/hibernate/models/internal/AnnotationUsageHelper.java

+1-2
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@
1414
import org.hibernate.models.spi.AnnotationDescriptor;
1515
import org.hibernate.models.spi.AttributeDescriptor;
1616
import org.hibernate.models.spi.SourceModelBuildingContext;
17-
import org.hibernate.models.spi.SourceModelContext;
1817

1918
/**
2019
* @see AnnotationHelper
@@ -206,7 +205,7 @@ private static <A extends Annotation> boolean nameMatches(
206205
AnnotationDescriptor<A> descriptor,
207206
String matchValue,
208207
String attributeToMatch,
209-
SourceModelContext modelContext) {
208+
SourceModelBuildingContext modelContext) {
210209
final AttributeDescriptor<String> attributeDescriptor = descriptor.getAttribute( attributeToMatch );
211210
final String usageName = AnnotationHelper.extractValue( annotationUsage, attributeDescriptor );
212211
return matchValue.equals( usageName );

hibernate-models/src/main/java/org/hibernate/models/internal/AttributeDescriptorImpl.java

+6
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,12 @@ public ValueTypeDescriptor<T> getTypeDescriptor() {
5050
return typeDescriptor;
5151
}
5252

53+
@Override
54+
public T getDefaultValue() {
55+
//noinspection unchecked
56+
return (T) method.getDefaultValue();
57+
}
58+
5359
@Override
5460
public Method getAttributeMethod() {
5561
return method;

hibernate-models/src/main/java/org/hibernate/models/internal/OrmAnnotationDescriptor.java

+54-40
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,14 @@
55
package org.hibernate.models.internal;
66

77
import java.lang.annotation.Annotation;
8-
import java.lang.reflect.Constructor;
9-
import java.lang.reflect.InvocationTargetException;
8+
import java.lang.invoke.MethodHandle;
9+
import java.lang.invoke.MethodHandles;
10+
import java.lang.invoke.MethodType;
1011
import java.util.Collections;
1112
import java.util.List;
1213
import java.util.Map;
1314

15+
import org.hibernate.models.ModelsException;
1416
import org.hibernate.models.spi.AnnotationDescriptor;
1517
import org.hibernate.models.spi.AttributeDescriptor;
1618
import org.hibernate.models.spi.MutableAnnotationDescriptor;
@@ -22,6 +24,9 @@
2224
* does not collect annotations from the annotation class as we never care about
2325
* meta-annotations in these cases.
2426
*
27+
* @implNote There are a few cases in Hibernate ORM e.g. where we do care about meta-annotations,
28+
* but those are handled specially there.
29+
*
2530
* @author Steve Ebersole
2631
*/
2732
public class OrmAnnotationDescriptor<A extends Annotation, C extends A>
@@ -30,8 +35,8 @@ public class OrmAnnotationDescriptor<A extends Annotation, C extends A>
3035
private final Class<C> concreteClass;
3136
private final List<AttributeDescriptor<?>> attributeDescriptors;
3237

33-
private DynamicCreator<A,C> dynamicCreator;
34-
private JdkCreator<A,C> jdkCreator;
38+
private final DynamicCreator<A,C> dynamicCreator;
39+
private final JdkCreator<A,C> jdkCreator;
3540
private DeTypedCreator<A,C> deTypedCreator;
3641

3742
public OrmAnnotationDescriptor(
@@ -53,6 +58,9 @@ public OrmAnnotationDescriptor(
5358

5459
this.concreteClass = concreteClass;
5560
this.attributeDescriptors = AnnotationDescriptorBuilding.extractAttributeDescriptors( annotationType );
61+
62+
this.dynamicCreator = new DynamicCreator<>( annotationType, concreteClass );
63+
this.jdkCreator = new JdkCreator<>( annotationType, concreteClass );
5664
}
5765

5866
@Override
@@ -69,17 +77,11 @@ public Class<C> getMutableAnnotationType() {
6977

7078
@Override
7179
public C createUsage(SourceModelBuildingContext context) {
72-
if ( dynamicCreator == null ) {
73-
dynamicCreator = new DynamicCreator<>( getAnnotationType(), concreteClass );
74-
}
7580
return dynamicCreator.createUsage( context );
7681
}
7782

7883
@Override
7984
public C createUsage(A jdkAnnotation, SourceModelBuildingContext context) {
80-
if ( jdkCreator == null ) {
81-
jdkCreator = new JdkCreator<>( getAnnotationType(), concreteClass );
82-
}
8385
return jdkCreator.createUsage( jdkAnnotation, context );
8486
}
8587

@@ -102,93 +104,105 @@ public String toString() {
102104
}
103105

104106
public static class DynamicCreator<A extends Annotation, C extends A> {
105-
private final Constructor<C> constructor;
107+
private final MethodHandle constructor;
108+
private final Class<C> concreteClass;
106109

107110
public DynamicCreator(Class<A> annotationType, Class<C> concreteClass) {
108-
this( resolveConstructor( concreteClass ) );
111+
this( resolveConstructor( concreteClass ), concreteClass );
109112
}
110113

111-
private static <A extends Annotation, C extends A> Constructor<C> resolveConstructor(Class<C> concreteClass) {
114+
private static <A extends Annotation, C extends A> MethodHandle resolveConstructor(Class<C> concreteClass) {
112115
try {
113-
return concreteClass.getDeclaredConstructor( SourceModelBuildingContext.class );
116+
final MethodType methodType = MethodType.methodType( void.class, SourceModelBuildingContext.class );
117+
return MethodHandles.publicLookup().findConstructor( concreteClass, methodType );
114118
}
115-
catch (NoSuchMethodException e) {
116-
throw new RuntimeException( e );
119+
catch (Exception e) {
120+
throw new ModelsException( "Unable to locate default-variant constructor for `" + concreteClass.getName() + "`", e );
117121
}
118122
}
119123

120-
public DynamicCreator(Constructor<C> constructor) {
124+
public DynamicCreator(MethodHandle constructor, Class<C> concreteClass) {
121125
this.constructor = constructor;
126+
this.concreteClass = concreteClass;
122127
}
123128

124129
public C createUsage(SourceModelBuildingContext context) {
125130
try {
126-
return constructor.newInstance( context );
131+
//noinspection unchecked
132+
return (C) constructor.invoke( context );
127133
}
128-
catch (InvocationTargetException | InstantiationException | IllegalAccessException e) {
129-
throw new RuntimeException( e );
134+
catch (Throwable e) {
135+
throw new ModelsException( "Unable to invoke default-variant constructor for `" + concreteClass.getName() + "`", e );
130136
}
131137
}
132138
}
133139

134140
public static class JdkCreator<A extends Annotation, C extends A> {
135-
private final Constructor<C> constructor;
141+
private final MethodHandle constructor;
142+
private final Class<C> concreteClass;
136143

137144
public JdkCreator(Class<A> annotationType, Class<C> concreteClass) {
138-
this( resolveConstructor( annotationType, concreteClass ) );
145+
this( resolveConstructor( annotationType, concreteClass ), concreteClass );
139146
}
140147

141-
private static <A extends Annotation, C extends A> Constructor<C> resolveConstructor(
148+
private static <A extends Annotation, C extends A> MethodHandle resolveConstructor(
142149
Class<A> annotationType,
143150
Class<C> concreteClass) {
144151
try {
145-
return concreteClass.getDeclaredConstructor( annotationType, SourceModelBuildingContext.class );
152+
final MethodType methodType = MethodType.methodType( void.class, annotationType, SourceModelBuildingContext.class );
153+
return MethodHandles.publicLookup().findConstructor( concreteClass, methodType );
146154
}
147-
catch (NoSuchMethodException e) {
148-
throw new RuntimeException( e );
155+
catch (Exception e) {
156+
throw new ModelsException( "Unable to locate JDK-variant constructor for `" + concreteClass.getName() + "`", e );
149157
}
150158
}
151159

152-
public JdkCreator(Constructor<C> constructor) {
160+
public JdkCreator(MethodHandle constructor, Class<C> concreteClass) {
153161
this.constructor = constructor;
162+
this.concreteClass = concreteClass;
154163
}
155164

156165
public C createUsage(A jdkAnnotation, SourceModelBuildingContext context) {
157166
try {
158-
return constructor.newInstance( jdkAnnotation, context );
167+
//noinspection unchecked
168+
return (C) constructor.invoke( jdkAnnotation, context );
159169
}
160-
catch (InvocationTargetException | InstantiationException | IllegalAccessException e) {
161-
throw new RuntimeException( e );
170+
catch (Throwable e) {
171+
throw new ModelsException( "Unable to invoke JDK-variant constructor for `" + concreteClass.getName() + "`", e );
162172
}
163173
}
164174
}
165175

166176
public static class DeTypedCreator<A extends Annotation, C extends A> {
167-
private final Constructor<C> constructor;
177+
private final MethodHandle constructor;
178+
private final Class<C> concreteClass;
168179

169180
public DeTypedCreator(Class<A> annotationType, Class<C> concreteClass) {
170-
this( resolveConstructor( concreteClass ) );
181+
this( resolveConstructor( concreteClass ), concreteClass );
171182
}
172183

173-
private static <A extends Annotation, C extends A> Constructor<C> resolveConstructor(Class<C> concreteClass) {
184+
private static <A extends Annotation, C extends A> MethodHandle resolveConstructor(Class<C> concreteClass) {
174185
try {
175-
return concreteClass.getDeclaredConstructor( Map.class, SourceModelBuildingContext.class );
186+
final MethodType methodType = MethodType.methodType( void.class, Map.class, SourceModelBuildingContext.class );
187+
return MethodHandles.publicLookup().findConstructor( concreteClass, methodType );
176188
}
177-
catch (NoSuchMethodException e) {
178-
throw new RuntimeException( e );
189+
catch (Exception e) {
190+
throw new ModelsException( "Unable to locate Jandex-variant constructor for `" + concreteClass.getName() + "`", e );
179191
}
180192
}
181193

182-
public DeTypedCreator(Constructor<C> constructor) {
194+
public DeTypedCreator(MethodHandle constructor, Class<C> concreteClass) {
183195
this.constructor = constructor;
196+
this.concreteClass = concreteClass;
184197
}
185198

186199
public C createUsage(Map<String,?> attributeValues, SourceModelBuildingContext context) {
187200
try {
188-
return constructor.newInstance( attributeValues, context );
201+
//noinspection unchecked
202+
return (C) constructor.invoke( attributeValues, context );
189203
}
190-
catch (InvocationTargetException | InstantiationException | IllegalAccessException e) {
191-
throw new RuntimeException( e );
204+
catch (Throwable e) {
205+
throw new ModelsException( "Unable to invoke Jandex-variant constructor for `" + concreteClass.getName() + "`", e );
192206
}
193207
}
194208
}

hibernate-models/src/main/java/org/hibernate/models/spi/AttributeDescriptor.java

+12-4
Original file line numberDiff line numberDiff line change
@@ -22,12 +22,20 @@ public interface AttributeDescriptor<T> {
2222
*/
2323
ValueTypeDescriptor<T> getTypeDescriptor();
2424

25+
/**
26+
* The attribute's type.
27+
*/
28+
default Class<T> getValueType() {
29+
return getTypeDescriptor().getValueType();
30+
}
31+
32+
/**
33+
* The attribute's defined default value, if one.
34+
*/
35+
T getDefaultValue();
36+
2537
/**
2638
* The attribute method.
2739
*/
2840
Method getAttributeMethod();
29-
30-
default boolean isMultiValued() {
31-
return getAttributeMethod().getReturnType().isArray();
32-
}
3341
}

version.txt

+1-1
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
1.0.0-SNAPSHOT
1+
1.0.0-METHOD-HANDLE

0 commit comments

Comments
 (0)