|
15 | 15 | import io.microsphere.reflect.ConstructorUtils; |
16 | 16 |
|
17 | 17 | import java.io.File; |
| 18 | +import java.lang.reflect.Method; |
18 | 19 | import java.lang.reflect.Modifier; |
19 | 20 | import java.math.BigDecimal; |
20 | 21 | import java.math.BigInteger; |
|
56 | 57 | import static io.microsphere.lang.function.Predicates.EMPTY_PREDICATE_ARRAY; |
57 | 58 | import static io.microsphere.logging.LoggerFactory.getLogger; |
58 | 59 | import static io.microsphere.net.URLUtils.resolveProtocol; |
| 60 | +import static io.microsphere.reflect.MethodUtils.findMethods; |
| 61 | +import static io.microsphere.reflect.MethodUtils.isOverridenObjectMethod; |
59 | 62 | import static io.microsphere.reflect.Modifier.isAnnotation; |
| 63 | +import static io.microsphere.reflect.Modifier.isBridge; |
| 64 | +import static io.microsphere.reflect.Modifier.isStatic; |
60 | 65 | import static io.microsphere.reflect.Modifier.isSynthetic; |
61 | 66 | import static io.microsphere.util.ArrayUtils.EMPTY_CLASS_ARRAY; |
62 | 67 | import static io.microsphere.util.ArrayUtils.isEmpty; |
|
73 | 78 | import static java.lang.Boolean.FALSE; |
74 | 79 | import static java.lang.Boolean.TRUE; |
75 | 80 | import static java.lang.reflect.Modifier.isAbstract; |
76 | | -import static java.lang.reflect.Modifier.isInterface; |
77 | 81 | import static java.util.Collections.addAll; |
78 | 82 | import static java.util.Collections.emptyList; |
79 | 83 | import static java.util.Collections.emptySet; |
@@ -415,6 +419,24 @@ public static boolean isAbstractClass(@Nullable Class<?> type) { |
415 | 419 | return isGeneralClass(type, TRUE); |
416 | 420 | } |
417 | 421 |
|
| 422 | + /** |
| 423 | + * Checks if the specified type is an interface. |
| 424 | + * |
| 425 | + * <h3>Example Usage</h3> |
| 426 | + * <pre>{@code |
| 427 | + * boolean result1 = ClassUtils.isInterface(List.class); // returns true |
| 428 | + * boolean result2 = ClassUtils.isInterface(String.class); // returns false |
| 429 | + * boolean result3 = ClassUtils.isInterface(null); // returns false |
| 430 | + * }</pre> |
| 431 | + * |
| 432 | + * @param type the type to check, may be {@code null} |
| 433 | + * @return {@code true} if the specified type is an interface, {@code false} otherwise |
| 434 | + * @see Class#isInterface() |
| 435 | + */ |
| 436 | + public static boolean isInterface(@Nullable Class<?> type) { |
| 437 | + return type != null && type.isInterface(); |
| 438 | + } |
| 439 | + |
418 | 440 | /** |
419 | 441 | * Checks if the specified type is a general class. |
420 | 442 | * <p> |
@@ -467,7 +489,7 @@ protected static boolean isGeneralClass(@Nullable Class<?> type, @Nullable Boole |
467 | 489 | int mod = type.getModifiers(); |
468 | 490 | if (isAnnotation(mod) |
469 | 491 | || io.microsphere.reflect.Modifier.isEnum(mod) |
470 | | - || isInterface(mod) |
| 492 | + || io.microsphere.reflect.Modifier.isInterface(mod) |
471 | 493 | || isSynthetic(mod) |
472 | 494 | || isPrimitive(type) |
473 | 495 | || isArray(type)) { |
@@ -617,6 +639,55 @@ public static boolean isLambdaClass(@Nullable Class<?> type) { |
617 | 639 | return isSyntheticClass(type) && getTypeName(type).contains("$$Lambda/"); |
618 | 640 | } |
619 | 641 |
|
| 642 | + |
| 643 | + /** |
| 644 | + * Checks if the specified class is a functional interface. |
| 645 | + * <p> |
| 646 | + * A functional interface is an interface that has exactly one abstract method. |
| 647 | + * This method returns {@code true} if the given class is an interface and has exactly one abstract method, |
| 648 | + * or if it is annotated with {@link FunctionalInterface}. It returns {@code false} otherwise, including for |
| 649 | + * non-interface classes or interfaces with more than one abstract method. It also returns {@code false} if |
| 650 | + * the class is {@code null}. |
| 651 | + * </p> |
| 652 | + * |
| 653 | + * <h3>Example Usage</h3> |
| 654 | + * <pre>{@code |
| 655 | + * @FunctionalInterface |
| 656 | + * interface MyFunctionalInterface { |
| 657 | + * void doSomething(); |
| 658 | + * } |
| 659 | + * |
| 660 | + * boolean result1 = ClassUtils.isFunctionalInterface(MyFunctionalInterface.class); // returns true |
| 661 | + * boolean result2 = ClassUtils.isFunctionalInterface(Runnable.class); // returns true |
| 662 | + * boolean result3 = ClassUtils.isFunctionalInterface(List.class); // returns false (not a functional interface) |
| 663 | + * boolean result4 = ClassUtils.isFunctionalInterface(null); // returns false |
| 664 | + * }</pre> |
| 665 | + * |
| 666 | + * @param type the class to check, may be {@code null} |
| 667 | + * @return {@code true} if the specified class is a functional interface, {@code false} otherwise |
| 668 | + */ |
| 669 | + public static boolean isFunctionalInterface(@Nullable Class<?> type) { |
| 670 | + if (!isInterface(type)) { |
| 671 | + return false; |
| 672 | + } |
| 673 | + |
| 674 | + // Trusted by the Java compiler, if the interface is annotated with @FunctionalInterface, it is a functional interface. |
| 675 | + if (type.isAnnotationPresent(FunctionalInterface.class)) { |
| 676 | + return true; |
| 677 | + } |
| 678 | + |
| 679 | + List<Method> methods = findMethods(type, false, true, method -> { |
| 680 | + int modifiers = method.getModifiers(); |
| 681 | + if (isStatic(modifiers) || isOverridenObjectMethod(method) || isBridge(modifiers) || isSynthetic(modifiers) |
| 682 | + || method.isDefault()) { |
| 683 | + return false; |
| 684 | + } |
| 685 | + return true; |
| 686 | + }); |
| 687 | + |
| 688 | + return methods.size() == 1; |
| 689 | + } |
| 690 | + |
620 | 691 | /** |
621 | 692 | * Checks if the specified class is a primitive type. |
622 | 693 | * <p> |
@@ -1104,7 +1175,7 @@ public static boolean arrayTypeEquals(@Nullable Class<?> oneArrayType, @Nullable |
1104 | 1175 | * </p> |
1105 | 1176 | * <p> |
1106 | 1177 | * Note: This method does <i>not</i> support the "[]" suffix notation for |
1107 | | - * primitive arrays; this is only supported by {@link #forName(String)}. |
| 1178 | + * primitive arrays; this is only supported by {@link Class#forName(String)}. |
1108 | 1179 | * </p> |
1109 | 1180 | * |
1110 | 1181 | * <h3>Example Usage</h3> |
|
0 commit comments