1
1
/*
2
- * Copyright 2002-2022 the original author or authors.
2
+ * Copyright 2002-2024 the original author or authors.
3
3
*
4
4
* Licensed under the Apache License, Version 2.0 (the "License");
5
5
* you may not use this file except in compliance with the License.
44
44
45
45
/**
46
46
* Miscellaneous {@code java.lang.Class} utility methods.
47
- * Mainly for internal use within the framework.
47
+ *
48
+ * <p>Mainly for internal use within the framework.
48
49
*
49
50
* @author Juergen Hoeller
50
51
* @author Keith Donald
@@ -243,7 +244,7 @@ public static ClassLoader overrideThreadContextClassLoader(@Nullable ClassLoader
243
244
* style (e.g. "java.lang.Thread.State" instead of "java.lang.Thread$State").
244
245
* @param name the name of the Class
245
246
* @param classLoader the class loader to use
246
- * (may be {@code null}, which indicates the default class loader)
247
+ * (can be {@code null}, which indicates the default class loader)
247
248
* @return a class instance for the supplied name
248
249
* @throws ClassNotFoundException if the class was not found
249
250
* @throws LinkageError if the class file could not be loaded
@@ -314,7 +315,7 @@ public static Class<?> forName(String name, @Nullable ClassLoader classLoader)
314
315
* the exceptions thrown in case of class loading failure.
315
316
* @param className the name of the Class
316
317
* @param classLoader the class loader to use
317
- * (may be {@code null}, which indicates the default class loader)
318
+ * (can be {@code null}, which indicates the default class loader)
318
319
* @return a class instance for the supplied name
319
320
* @throws IllegalArgumentException if the class name was not resolvable
320
321
* (that is, the class could not be found or the class file could not be loaded)
@@ -348,7 +349,7 @@ public static Class<?> resolveClassName(String className, @Nullable ClassLoader
348
349
* one of its dependencies is not present or cannot be loaded.
349
350
* @param className the name of the class to check
350
351
* @param classLoader the class loader to use
351
- * (may be {@code null} which indicates the default class loader)
352
+ * (can be {@code null} which indicates the default class loader)
352
353
* @return whether the specified class is present (including all of its
353
354
* superclasses and interfaces)
354
355
* @throws IllegalStateException if the corresponding class is resolvable but
@@ -375,7 +376,7 @@ public static boolean isPresent(String className, @Nullable ClassLoader classLoa
375
376
* Check whether the given class is visible in the given ClassLoader.
376
377
* @param clazz the class to check (typically an interface)
377
378
* @param classLoader the ClassLoader to check against
378
- * (may be {@code null} in which case this method will always return {@code true})
379
+ * (can be {@code null} in which case this method will always return {@code true})
379
380
*/
380
381
public static boolean isVisible (Class <?> clazz , @ Nullable ClassLoader classLoader ) {
381
382
if (classLoader == null ) {
@@ -399,7 +400,7 @@ public static boolean isVisible(Class<?> clazz, @Nullable ClassLoader classLoade
399
400
* i.e. whether it is loaded by the given ClassLoader or a parent of it.
400
401
* @param clazz the class to analyze
401
402
* @param classLoader the ClassLoader to potentially cache metadata in
402
- * (may be {@code null} which indicates the system class loader)
403
+ * (can be {@code null} which indicates the system class loader)
403
404
*/
404
405
public static boolean isCacheSafe (Class <?> clazz , @ Nullable ClassLoader classLoader ) {
405
406
Assert .notNull (clazz , "Class must not be null" );
@@ -539,9 +540,10 @@ public static Class<?> resolvePrimitiveIfNecessary(Class<?> clazz) {
539
540
* Check if the right-hand side type may be assigned to the left-hand side
540
541
* type, assuming setting by reflection. Considers primitive wrapper
541
542
* classes as assignable to the corresponding primitive types.
542
- * @param lhsType the target type
543
- * @param rhsType the value type that should be assigned to the target type
544
- * @return if the target type is assignable from the value type
543
+ * @param lhsType the target type (left-hand side (LHS) type)
544
+ * @param rhsType the value type (right-hand side (RHS) type) that should
545
+ * be assigned to the target type
546
+ * @return {@code true} if {@code rhsType} is assignable to {@code lhsType}
545
547
* @see TypeUtils#isAssignable(java.lang.reflect.Type, java.lang.reflect.Type)
546
548
*/
547
549
public static boolean isAssignable (Class <?> lhsType , Class <?> rhsType ) {
@@ -662,7 +664,7 @@ public static String classNamesToString(Class<?>... classes) {
662
664
* in the given collection.
663
665
* <p>Basically like {@code AbstractCollection.toString()}, but stripping
664
666
* the "class "/"interface " prefix before every class name.
665
- * @param classes a Collection of Class objects (may be {@code null})
667
+ * @param classes a Collection of Class objects (can be {@code null})
666
668
* @return a String of form "[com.foo.Bar, com.foo.Baz]"
667
669
* @see java.util.AbstractCollection#toString()
668
670
*/
@@ -717,7 +719,7 @@ public static Class<?>[] getAllInterfacesForClass(Class<?> clazz) {
717
719
* <p>If the class itself is an interface, it gets returned as sole interface.
718
720
* @param clazz the class to analyze for interfaces
719
721
* @param classLoader the ClassLoader that the interfaces need to be visible in
720
- * (may be {@code null} when accepting all declared interfaces)
722
+ * (can be {@code null} when accepting all declared interfaces)
721
723
* @return all interfaces that the given object implements as an array
722
724
*/
723
725
public static Class <?>[] getAllInterfacesForClass (Class <?> clazz , @ Nullable ClassLoader classLoader ) {
@@ -752,7 +754,7 @@ public static Set<Class<?>> getAllInterfacesForClassAsSet(Class<?> clazz) {
752
754
* <p>If the class itself is an interface, it gets returned as sole interface.
753
755
* @param clazz the class to analyze for interfaces
754
756
* @param classLoader the ClassLoader that the interfaces need to be visible in
755
- * (may be {@code null} when accepting all declared interfaces)
757
+ * (can be {@code null} when accepting all declared interfaces)
756
758
* @return all interfaces that the given object implements as a Set
757
759
*/
758
760
public static Set <Class <?>> getAllInterfacesForClassAsSet (Class <?> clazz , @ Nullable ClassLoader classLoader ) {
@@ -866,9 +868,9 @@ public static boolean isLambdaClass(Class<?> clazz) {
866
868
/**
867
869
* Check whether the given object is a CGLIB proxy.
868
870
* @param object the object to check
869
- * @see #isCglibProxyClass(Class)
870
871
* @see org.springframework.aop.support.AopUtils#isCglibProxy(Object)
871
872
* @deprecated as of 5.2, in favor of custom (possibly narrower) checks
873
+ * such as for a Spring AOP proxy
872
874
*/
873
875
@ Deprecated
874
876
public static boolean isCglibProxy (Object object ) {
@@ -878,8 +880,9 @@ public static boolean isCglibProxy(Object object) {
878
880
/**
879
881
* Check whether the specified class is a CGLIB-generated class.
880
882
* @param clazz the class to check
881
- * @see #isCglibProxyClassName(String )
883
+ * @see #getUserClass(Class )
882
884
* @deprecated as of 5.2, in favor of custom (possibly narrower) checks
885
+ * or simply a check for containing {@link #CGLIB_CLASS_SEPARATOR}
883
886
*/
884
887
@ Deprecated
885
888
public static boolean isCglibProxyClass (@ Nullable Class <?> clazz ) {
@@ -889,7 +892,9 @@ public static boolean isCglibProxyClass(@Nullable Class<?> clazz) {
889
892
/**
890
893
* Check whether the specified class name is a CGLIB-generated class.
891
894
* @param className the class name to check
895
+ * @see #CGLIB_CLASS_SEPARATOR
892
896
* @deprecated as of 5.2, in favor of custom (possibly narrower) checks
897
+ * or simply a check for containing {@link #CGLIB_CLASS_SEPARATOR}
893
898
*/
894
899
@ Deprecated
895
900
public static boolean isCglibProxyClassName (@ Nullable String className ) {
@@ -913,6 +918,7 @@ public static Class<?> getUserClass(Object instance) {
913
918
* class, but the original class in case of a CGLIB-generated subclass.
914
919
* @param clazz the class to check
915
920
* @return the user-defined class
921
+ * @see #CGLIB_CLASS_SEPARATOR
916
922
*/
917
923
public static Class <?> getUserClass (Class <?> clazz ) {
918
924
if (clazz .getName ().contains (CGLIB_CLASS_SEPARATOR )) {
@@ -1065,7 +1071,7 @@ public static String getQualifiedMethodName(Method method) {
1065
1071
* fully qualified interface/class name + "." + method name.
1066
1072
* @param method the method
1067
1073
* @param clazz the clazz that the method is being invoked on
1068
- * (may be {@code null} to indicate the method's declaring class)
1074
+ * (can be {@code null} to indicate the method's declaring class)
1069
1075
* @return the qualified name of the method
1070
1076
* @since 4.3.4
1071
1077
*/
@@ -1146,7 +1152,7 @@ public static boolean hasMethod(Class<?> clazz, String methodName, Class<?>... p
1146
1152
* @param clazz the clazz to analyze
1147
1153
* @param methodName the name of the method
1148
1154
* @param paramTypes the parameter types of the method
1149
- * (may be {@code null} to indicate any signature)
1155
+ * (can be {@code null} to indicate any signature)
1150
1156
* @return the method (never {@code null})
1151
1157
* @throws IllegalStateException if the method has not been found
1152
1158
* @see Class#getMethod
@@ -1185,7 +1191,7 @@ else if (candidates.isEmpty()) {
1185
1191
* @param clazz the clazz to analyze
1186
1192
* @param methodName the name of the method
1187
1193
* @param paramTypes the parameter types of the method
1188
- * (may be {@code null} to indicate any signature)
1194
+ * (can be {@code null} to indicate any signature)
1189
1195
* @return the method, or {@code null} if not found
1190
1196
* @see Class#getMethod
1191
1197
*/
@@ -1261,26 +1267,27 @@ public static boolean hasAtLeastOneMethodWithName(Class<?> clazz, String methodN
1261
1267
/**
1262
1268
* Given a method, which may come from an interface, and a target class used
1263
1269
* in the current reflective invocation, find the corresponding target method
1264
- * if there is one. E.g. the method may be {@code IFoo.bar()} and the
1265
- * target class may be {@code DefaultFoo}. In this case, the method may be
1270
+ * if there is one — for example, the method may be {@code IFoo.bar()},
1271
+ * and the target class may be {@code DefaultFoo}. In this case, the method may be
1266
1272
* {@code DefaultFoo.bar()}. This enables attributes on that method to be found.
1267
1273
* <p><b>NOTE:</b> In contrast to {@link org.springframework.aop.support.AopUtils#getMostSpecificMethod},
1268
1274
* this method does <i>not</i> resolve bridge methods automatically.
1269
1275
* Call {@link org.springframework.core.BridgeMethodResolver#findBridgedMethod}
1270
- * if bridge method resolution is desirable (e.g. for obtaining metadata from
1271
- * the original method definition) .
1272
- * <p><b>NOTE:</b> Since Spring 3.1.1, if Java security settings disallow reflective
1273
- * access (e.g. calls to {@code Class#getDeclaredMethods} etc, this implementation
1274
- * will fall back to returning the originally provided method.
1276
+ * if bridge method resolution is desirable — for example, to obtain
1277
+ * metadata from the original method definition.
1278
+ * <p><b>NOTE:</b> If Java security settings disallow reflective access —
1279
+ * for example, calls to {@code Class#getDeclaredMethods}, etc. — this
1280
+ * implementation will fall back to returning the originally provided method.
1275
1281
* @param method the method to be invoked, which may come from an interface
1276
1282
* @param targetClass the target class for the current invocation
1277
- * (may be {@code null} or may not even implement the method)
1283
+ * (can be {@code null} or may not even implement the method)
1278
1284
* @return the specific target method, or the original method if the
1279
1285
* {@code targetClass} does not implement it
1280
1286
* @see #getInterfaceMethodIfPossible(Method, Class)
1281
1287
*/
1282
1288
public static Method getMostSpecificMethod (Method method , @ Nullable Class <?> targetClass ) {
1283
- if (targetClass != null && targetClass != method .getDeclaringClass () && isOverridable (method , targetClass )) {
1289
+ if (targetClass != null && targetClass != method .getDeclaringClass () &&
1290
+ (isOverridable (method , targetClass ) || !method .getDeclaringClass ().isAssignableFrom (targetClass ))) {
1284
1291
try {
1285
1292
if (Modifier .isPublic (method .getModifiers ())) {
1286
1293
try {
0 commit comments