@@ -70,9 +70,19 @@ public abstract class BeanUtils {
70
70
private static final Set <Class <?>> unknownEditorTypes =
71
71
Collections .newSetFromMap (new ConcurrentReferenceHashMap <>(64 ));
72
72
73
- private static final boolean kotlinPresent =
74
- ClassUtils .isPresent ("kotlin.Unit" , BeanUtils .class .getClassLoader ());
75
-
73
+ @ Nullable
74
+ private static Class <?> kotlinMetadata ;
75
+
76
+ static {
77
+ try {
78
+ kotlinMetadata = ClassUtils .forName ("kotlin.Metadata" , BeanUtils .class .getClassLoader ());
79
+ }
80
+ catch (ClassNotFoundException ex ) {
81
+ // Kotlin API not available - no special support for Kotlin class instantiation
82
+ kotlinMetadata = null ;
83
+ }
84
+ }
85
+
76
86
77
87
/**
78
88
* Convenience method to instantiate a class using its no-arg constructor.
@@ -115,7 +125,7 @@ public static <T> T instantiateClass(Class<T> clazz) throws BeanInstantiationExc
115
125
throw new BeanInstantiationException (clazz , "Specified class is an interface" );
116
126
}
117
127
try {
118
- Constructor <T > ctor = (kotlinPresent && isKotlinClass (clazz ) ?
128
+ Constructor <T > ctor = (isKotlinClass (clazz ) ?
119
129
KotlinDelegate .findPrimaryConstructor (clazz ) : clazz .getDeclaredConstructor ());
120
130
if (ctor == null ) {
121
131
throw new BeanInstantiationException (clazz , "No default constructor found" );
@@ -152,8 +162,8 @@ public static <T> T instantiateClass(Class<?> clazz, Class<T> assignableTo) thro
152
162
* non-accessible (that is, non-public) constructor, and supports Kotlin classes
153
163
* with optional parameters and default values.
154
164
* @param ctor the constructor to instantiate
155
- * @param args the constructor arguments to apply (use null for unspecified parameter
156
- * if needed for Kotlin classes with optional parameters and default values)
165
+ * @param args the constructor arguments to apply (use {@code null} for an unspecified
166
+ * parameter if needed for Kotlin classes with optional parameters and default values)
157
167
* @return the new instance
158
168
* @throws BeanInstantiationException if the bean cannot be instantiated
159
169
* @see Constructor#newInstance
@@ -162,7 +172,8 @@ public static <T> T instantiateClass(Constructor<T> ctor, Object... args) throws
162
172
Assert .notNull (ctor , "Constructor must not be null" );
163
173
try {
164
174
ReflectionUtils .makeAccessible (ctor );
165
- return (kotlinPresent && isKotlinClass (ctor .getDeclaringClass ()) ? KotlinDelegate .instantiateClass (ctor , args ) : ctor .newInstance (args ));
175
+ return (isKotlinClass (ctor .getDeclaringClass ()) ?
176
+ KotlinDelegate .instantiateClass (ctor , args ) : ctor .newInstance (args ));
166
177
}
167
178
catch (InstantiationException ex ) {
168
179
throw new BeanInstantiationException (ctor , "Is it an abstract class?" , ex );
@@ -329,8 +340,7 @@ else if (!method.isBridge() && targetMethod.getParameterCount() == numParams) {
329
340
@ Nullable
330
341
public static <T > Constructor <T > findPrimaryConstructor (Class <T > clazz ) {
331
342
Assert .notNull (clazz , "Class must not be null" );
332
- Constructor <T > ctor = null ;
333
- if (kotlinPresent && isKotlinClass (clazz )) {
343
+ if (isKotlinClass (clazz )) {
334
344
return KotlinDelegate .findPrimaryConstructor (clazz );
335
345
}
336
346
else {
@@ -699,13 +709,10 @@ private static void copyProperties(Object source, Object target, @Nullable Class
699
709
/**
700
710
* Return true if the specified class is a Kotlin one.
701
711
*/
712
+ @ SuppressWarnings ("unchecked" )
702
713
private static boolean isKotlinClass (Class <?> clazz ) {
703
- for (Annotation annotation : clazz .getDeclaredAnnotations ()) {
704
- if (annotation .annotationType ().getName ().equals ("kotlin.Metadata" )) {
705
- return true ;
706
- }
707
- }
708
- return false ;
714
+ return (kotlinMetadata != null &&
715
+ clazz .getDeclaredAnnotation ((Class <? extends Annotation >) kotlinMetadata ) != null );
709
716
}
710
717
711
718
@@ -717,7 +724,8 @@ private static class KotlinDelegate {
717
724
/**
718
725
* Return the Java constructor corresponding to the Kotlin primary constructor if any.
719
726
* @param clazz the {@link Class} of the Kotlin class
720
- * @see <a href="http://kotlinlang.org/docs/reference/classes.html#constructors">http://kotlinlang.org/docs/reference/classes.html#constructors</a>
727
+ * @see <a href="http://kotlinlang.org/docs/reference/classes.html#constructors">
728
+ * http://kotlinlang.org/docs/reference/classes.html#constructors</a>
721
729
*/
722
730
@ Nullable
723
731
public static <T > Constructor <T > findPrimaryConstructor (Class <T > clazz ) {
@@ -726,7 +734,8 @@ public static <T> Constructor<T> findPrimaryConstructor(Class<T> clazz) {
726
734
return null ;
727
735
}
728
736
Constructor <T > constructor = ReflectJvmMapping .getJavaConstructor (primaryConstructor );
729
- Assert .notNull (constructor , "Can't get the Java constructor corresponding to the Kotlin primary constructor of " + clazz .getName ());
737
+ Assert .notNull (constructor ,
738
+ () -> "Failed to find Java constructor corresponding to Kotlin primary constructor: " + clazz .getName ());
730
739
return constructor ;
731
740
}
732
741
@@ -735,14 +744,16 @@ public static <T> Constructor<T> findPrimaryConstructor(Class<T> clazz) {
735
744
* @param ctor the constructor of the Kotlin class to instantiate
736
745
* @param args the constructor arguments to apply (use null for unspecified parameter if needed)
737
746
*/
738
- public static <T > T instantiateClass (Constructor <T > ctor , Object ... args ) throws IllegalAccessException , InvocationTargetException , InstantiationException {
747
+ public static <T > T instantiateClass (Constructor <T > ctor , Object ... args )
748
+ throws IllegalAccessException , InvocationTargetException , InstantiationException {
749
+
739
750
KFunction <T > kotlinConstructor = ReflectJvmMapping .getKotlinFunction (ctor );
740
751
if (kotlinConstructor == null ) {
741
752
return ctor .newInstance (args );
742
753
}
743
754
List <KParameter > parameters = kotlinConstructor .getParameters ();
744
755
Map <KParameter , Object > argParameters = new HashMap <>(parameters .size ());
745
- Assert .isTrue (args .length <= parameters .size (),
756
+ Assert .isTrue (args .length <= parameters .size (),
746
757
"The number of provided arguments should be less of equals than the number of constructor parameters" );
747
758
for (int i = 0 ; i < args .length ; i ++) {
748
759
if (!(parameters .get (i ).isOptional () && (args [i ] == null ))) {
0 commit comments