{@code ResolvableTypes} may be obtained from {@link #forField(Field) fields}, 52 | * {@link #forMethodParameter(Method, int) method parameters}, 53 | * {@link #forMethodReturnType(Method) method returns} or 54 | * {@link #forClass(Class) classes}. Most methods on this class will themselves return 55 | * {@link ResolvableType ResolvableTypes}, allowing easy navigation. For example: 56 | *
57 | * private HashMap<Integer, List<String>> myMap; 58 | * 59 | * public void example() { 60 | * ResolvableType t = ResolvableType.forField(getClass().getDeclaredField("myMap")); 61 | * t.getSuperType(); // AbstractMap<Integer, List<String>> 62 | * t.asMap(); // Map<Integer, List<String>> 63 | * t.getGeneric(0).resolve(); // Integer 64 | * t.getGeneric(1).resolve(); // List 65 | * t.getGeneric(1); // List<String> 66 | * t.resolveGeneric(1, 0); // String 67 | * } 68 | *69 | * 70 | * @author Phillip Webb 71 | * @author Juergen Hoeller 72 | * @author Stephane Nicoll 73 | * @since 4.0 74 | * @see #forField(Field) 75 | * @see #forMethodParameter(Method, int) 76 | * @see #forMethodReturnType(Method) 77 | * @see #forConstructorParameter(Constructor, int) 78 | * @see #forClass(Class) 79 | * @see #forType(Type) 80 | * @see #forInstance(Object) 81 | * @see ResolvableTypeProvider 82 | */ 83 | @SuppressWarnings("serial") 84 | public class ResolvableType implements Serializable { 85 | 86 | /** 87 | * {@code ResolvableType} returned when no value is available. {@code NONE} is used 88 | * in preference to {@code null} so that multiple method calls can be safely chained. 89 | */ 90 | public static final ResolvableType NONE = new ResolvableType(EmptyType.INSTANCE, null, null, 0); 91 | 92 | private static final ResolvableType[] EMPTY_TYPES_ARRAY = new ResolvableType[0]; 93 | 94 | private static final ConcurrentReferenceHashMap
Attempts to follow the same rules as the Java compiler, considering
270 | * whether both the {@link #resolve() resolved} {@code Class} is
271 | * {@link Class#isAssignableFrom(Class) assignable from} the given type
272 | * as well as whether all {@link #getGenerics() generics} are assignable.
273 | * @param other the type to be checked against (as a {@code ResolvableType})
274 | * @return {@code true} if the specified other type can be assigned to this
275 | * {@code ResolvableType}; {@code false} otherwise
276 | */
277 | public boolean isAssignableFrom(ResolvableType other) {
278 | return isAssignableFrom(other, null);
279 | }
280 |
281 | private boolean isAssignableFrom(ResolvableType other, @Nullable Map Note: The resulting {@link ResolvableType} instance may not be {@link Serializable}.
463 | * @see #getInterfaces()
464 | */
465 | public ResolvableType getSuperType() {
466 | Class> resolved = resolve();
467 | if (resolved == null || resolved.getGenericSuperclass() == null) {
468 | return NONE;
469 | }
470 | ResolvableType superType = this.superType;
471 | if (superType == null) {
472 | superType = forType(resolved.getGenericSuperclass(), this);
473 | this.superType = superType;
474 | }
475 | return superType;
476 | }
477 |
478 | /**
479 | * Return a {@link ResolvableType} array representing the direct interfaces
480 | * implemented by this type. If this type does not implement any interfaces an
481 | * empty array is returned.
482 | * Note: The resulting {@link ResolvableType} instances may not be {@link Serializable}.
483 | * @see #getSuperType()
484 | */
485 | public ResolvableType[] getInterfaces() {
486 | Class> resolved = resolve();
487 | if (resolved == null) {
488 | return EMPTY_TYPES_ARRAY;
489 | }
490 | ResolvableType[] interfaces = this.interfaces;
491 | if (interfaces == null) {
492 | Type[] genericIfcs = resolved.getGenericInterfaces();
493 | interfaces = new ResolvableType[genericIfcs.length];
494 | for (int i = 0; i < genericIfcs.length; i++) {
495 | interfaces[i] = forType(genericIfcs[i], this);
496 | }
497 | this.interfaces = interfaces;
498 | }
499 | return interfaces;
500 | }
501 |
502 | /**
503 | * Return {@code true} if this type contains generic parameters.
504 | * @see #getGeneric(int...)
505 | * @see #getGenerics()
506 | */
507 | public boolean hasGenerics() {
508 | return (getGenerics().length > 0);
509 | }
510 |
511 | /**
512 | * Return {@code true} if this type contains unresolvable generics only,
513 | * that is, no substitute for any of its declared type variables.
514 | */
515 | boolean isEntirelyUnresolvable() {
516 | if (this == NONE) {
517 | return false;
518 | }
519 | ResolvableType[] generics = getGenerics();
520 | for (ResolvableType generic : generics) {
521 | if (!generic.isUnresolvableTypeVariable() && !generic.isWildcardWithoutBounds()) {
522 | return false;
523 | }
524 | }
525 | return true;
526 | }
527 |
528 | /**
529 | * Determine whether the underlying type has any unresolvable generics:
530 | * either through an unresolvable type variable on the type itself
531 | * or through implementing a generic interface in a raw fashion,
532 | * i.e. without substituting that interface's type variables.
533 | * The result will be {@code true} only in those two scenarios.
534 | */
535 | public boolean hasUnresolvableGenerics() {
536 | if (this == NONE) {
537 | return false;
538 | }
539 | ResolvableType[] generics = getGenerics();
540 | for (ResolvableType generic : generics) {
541 | if (generic.isUnresolvableTypeVariable() || generic.isWildcardWithoutBounds()) {
542 | return true;
543 | }
544 | }
545 | Class> resolved = resolve();
546 | if (resolved != null) {
547 | for (Type genericInterface : resolved.getGenericInterfaces()) {
548 | if (genericInterface instanceof Class) {
549 | if (forClass((Class>) genericInterface).hasGenerics()) {
550 | return true;
551 | }
552 | }
553 | }
554 | return getSuperType().hasUnresolvableGenerics();
555 | }
556 | return false;
557 | }
558 |
559 | /**
560 | * Determine whether the underlying type is a type variable that
561 | * cannot be resolved through the associated variable resolver.
562 | */
563 | private boolean isUnresolvableTypeVariable() {
564 | if (this.type instanceof TypeVariable) {
565 | if (this.variableResolver == null) {
566 | return true;
567 | }
568 | TypeVariable> variable = (TypeVariable>) this.type;
569 | ResolvableType resolved = this.variableResolver.resolveVariable(variable);
570 | if (resolved == null || resolved.isUnresolvableTypeVariable()) {
571 | return true;
572 | }
573 | }
574 | return false;
575 | }
576 |
577 | /**
578 | * Determine whether the underlying type represents a wildcard
579 | * without specific bounds (i.e., equal to {@code ? extends Object}).
580 | */
581 | private boolean isWildcardWithoutBounds() {
582 | if (this.type instanceof WildcardType) {
583 | WildcardType wt = (WildcardType) this.type;
584 | if (wt.getLowerBounds().length == 0) {
585 | Type[] upperBounds = wt.getUpperBounds();
586 | if (upperBounds.length == 0 || (upperBounds.length == 1 && Object.class == upperBounds[0])) {
587 | return true;
588 | }
589 | }
590 | }
591 | return false;
592 | }
593 |
594 | /**
595 | * Return a {@link ResolvableType} for the specified nesting level.
596 | * See {@link #getNested(int, Map)} for details.
597 | * @param nestingLevel the nesting level
598 | * @return the {@link ResolvableType} type, or {@code #NONE}
599 | */
600 | public ResolvableType getNested(int nestingLevel) {
601 | return getNested(nestingLevel, null);
602 | }
603 |
604 | /**
605 | * Return a {@link ResolvableType} for the specified nesting level.
606 | * The nesting level refers to the specific generic parameter that should be returned.
607 | * A nesting level of 1 indicates this type; 2 indicates the first nested generic;
608 | * 3 the second; and so on. For example, given {@code List The {@code typeIndexesPerLevel} map can be used to reference a specific generic
611 | * for the given level. For example, an index of 0 would refer to a {@code Map} key;
612 | * whereas, 1 would refer to the value. If the map does not contain a value for a
613 | * specific level the last generic will be used (e.g. a {@code Map} value).
614 | * Nesting levels may also apply to array types; for example given
615 | * {@code String[]}, a nesting level of 2 refers to {@code String}.
616 | * If a type does not {@link #hasGenerics() contain} generics the
617 | * {@link #getSuperType() supertype} hierarchy will be considered.
618 | * @param nestingLevel the required nesting level, indexed from 1 for the
619 | * current type, 2 for the first nested generic, 3 for the second and so on
620 | * @param typeIndexesPerLevel a map containing the generic index for a given
621 | * nesting level (may be {@code null})
622 | * @return a {@link ResolvableType} for the nested level, or {@link #NONE}
623 | */
624 | public ResolvableType getNested(int nestingLevel, @Nullable Map If no generic is available at the specified indexes {@link #NONE} is returned.
652 | * @param indexes the indexes that refer to the generic parameter
653 | * (may be omitted to return the first generic)
654 | * @return a {@link ResolvableType} for the specified generic, or {@link #NONE}
655 | * @see #hasGenerics()
656 | * @see #getGenerics()
657 | * @see #resolveGeneric(int...)
658 | * @see #resolveGenerics()
659 | */
660 | public ResolvableType getGeneric(@Nullable int... indexes) {
661 | ResolvableType[] generics = getGenerics();
662 | if (indexes == null || indexes.length == 0) {
663 | return (generics.length == 0 ? NONE : generics[0]);
664 | }
665 | ResolvableType generic = this;
666 | for (int index : indexes) {
667 | generics = generic.getGenerics();
668 | if (index < 0 || index >= generics.length) {
669 | return NONE;
670 | }
671 | generic = generics[index];
672 | }
673 | return generic;
674 | }
675 |
676 | /**
677 | * Return an array of {@link ResolvableType ResolvableTypes} representing the generic parameters of
678 | * this type. If no generics are available an empty array is returned. If you need to
679 | * access a specific generic consider using the {@link #getGeneric(int...)} method as
680 | * it allows access to nested generics and protects against
681 | * {@code IndexOutOfBoundsExceptions}.
682 | * @return an array of {@link ResolvableType ResolvableTypes} representing the generic parameters
683 | * (never {@code null})
684 | * @see #hasGenerics()
685 | * @see #getGeneric(int...)
686 | * @see #resolveGeneric(int...)
687 | * @see #resolveGenerics()
688 | */
689 | public ResolvableType[] getGenerics() {
690 | if (this == NONE) {
691 | return EMPTY_TYPES_ARRAY;
692 | }
693 | ResolvableType[] generics = this.generics;
694 | if (generics == null) {
695 | if (this.type instanceof Class) {
696 | Type[] typeParams = ((Class>) this.type).getTypeParameters();
697 | generics = new ResolvableType[typeParams.length];
698 | for (int i = 0; i < generics.length; i++) {
699 | generics[i] = ResolvableType.forType(typeParams[i], this);
700 | }
701 | }
702 | else if (this.type instanceof ParameterizedType) {
703 | Type[] actualTypeArguments = ((ParameterizedType) this.type).getActualTypeArguments();
704 | generics = new ResolvableType[actualTypeArguments.length];
705 | for (int i = 0; i < actualTypeArguments.length; i++) {
706 | generics[i] = forType(actualTypeArguments[i], this.variableResolver);
707 | }
708 | }
709 | else {
710 | generics = resolveType().getGenerics();
711 | }
712 | this.generics = generics;
713 | }
714 | return generics;
715 | }
716 |
717 | /**
718 | * Convenience method that will {@link #getGenerics() get} and
719 | * {@link #resolve() resolve} generic parameters.
720 | * @return an array of resolved generic parameters (the resulting array
721 | * will never be {@code null}, but it may contain {@code null} elements})
722 | * @see #getGenerics()
723 | * @see #resolve()
724 | */
725 | public Class>[] resolveGenerics() {
726 | ResolvableType[] generics = getGenerics();
727 | Class>[] resolvedGenerics = new Class>[generics.length];
728 | for (int i = 0; i < generics.length; i++) {
729 | resolvedGenerics[i] = generics[i].resolve();
730 | }
731 | return resolvedGenerics;
732 | }
733 |
734 | /**
735 | * Convenience method that will {@link #getGenerics() get} and {@link #resolve()
736 | * resolve} generic parameters, using the specified {@code fallback} if any type
737 | * cannot be resolved.
738 | * @param fallback the fallback class to use if resolution fails
739 | * @return an array of resolved generic parameters
740 | * @see #getGenerics()
741 | * @see #resolve()
742 | */
743 | public Class>[] resolveGenerics(Class> fallback) {
744 | ResolvableType[] generics = getGenerics();
745 | Class>[] resolvedGenerics = new Class>[generics.length];
746 | for (int i = 0; i < generics.length; i++) {
747 | resolvedGenerics[i] = generics[i].resolve(fallback);
748 | }
749 | return resolvedGenerics;
750 | }
751 |
752 | /**
753 | * Convenience method that will {@link #getGeneric(int...) get} and
754 | * {@link #resolve() resolve} a specific generic parameters.
755 | * @param indexes the indexes that refer to the generic parameter
756 | * (may be omitted to return the first generic)
757 | * @return a resolved {@link Class} or {@code null}
758 | * @see #getGeneric(int...)
759 | * @see #resolve()
760 | */
761 | @Nullable
762 | public Class> resolveGeneric(int... indexes) {
763 | return getGeneric(indexes).resolve();
764 | }
765 |
766 | /**
767 | * Resolve this type to a {@link java.lang.Class}, returning {@code null}
768 | * if the type cannot be resolved. This method will consider bounds of
769 | * {@link TypeVariable TypeVariables} and {@link WildcardType WildcardTypes} if
770 | * direct resolution fails; however, bounds of {@code Object.class} will be ignored.
771 | * If this method returns a non-null {@code Class} and {@link #hasGenerics()}
772 | * returns {@code false}, the given type effectively wraps a plain {@code Class},
773 | * allowing for plain {@code Class} processing if desirable.
774 | * @return the resolved {@link Class}, or {@code null} if not resolvable
775 | * @see #resolve(Class)
776 | * @see #resolveGeneric(int...)
777 | * @see #resolveGenerics()
778 | */
779 | @Nullable
780 | public Class> resolve() {
781 | return this.resolved;
782 | }
783 |
784 | /**
785 | * Resolve this type to a {@link java.lang.Class}, returning the specified
786 | * {@code fallback} if the type cannot be resolved. This method will consider bounds
787 | * of {@link TypeVariable TypeVariables} and {@link WildcardType WildcardTypes} if
788 | * direct resolution fails; however, bounds of {@code Object.class} will be ignored.
789 | * @param fallback the fallback class to use if resolution fails
790 | * @return the resolved {@link Class} or the {@code fallback}
791 | * @see #resolve()
792 | * @see #resolveGeneric(int...)
793 | * @see #resolveGenerics()
794 | */
795 | public Class> resolve(Class> fallback) {
796 | return (this.resolved != null ? this.resolved : fallback);
797 | }
798 |
799 | @Nullable
800 | private Class> resolveClass() {
801 | if (this.type == EmptyType.INSTANCE) {
802 | return null;
803 | }
804 | if (this.type instanceof Class) {
805 | return (Class>) this.type;
806 | }
807 | if (this.type instanceof GenericArrayType) {
808 | Class> resolvedComponent = getComponentType().resolve();
809 | return (resolvedComponent != null ? Array.newInstance(resolvedComponent, 0).getClass() : null);
810 | }
811 | return resolveType().resolve();
812 | }
813 |
814 | /**
815 | * Resolve this type by a single level, returning the resolved value or {@link #NONE}.
816 | * Note: The returned {@link ResolvableType} should only be used as an intermediary
817 | * as it cannot be serialized.
818 | */
819 | ResolvableType resolveType() {
820 | if (this.type instanceof ParameterizedType) {
821 | return forType(((ParameterizedType) this.type).getRawType(), this.variableResolver);
822 | }
823 | if (this.type instanceof WildcardType) {
824 | Type resolved = resolveBounds(((WildcardType) this.type).getUpperBounds());
825 | if (resolved == null) {
826 | resolved = resolveBounds(((WildcardType) this.type).getLowerBounds());
827 | }
828 | return forType(resolved, this.variableResolver);
829 | }
830 | if (this.type instanceof TypeVariable) {
831 | TypeVariable> variable = (TypeVariable>) this.type;
832 | // Try default variable resolution
833 | if (this.variableResolver != null) {
834 | ResolvableType resolved = this.variableResolver.resolveVariable(variable);
835 | if (resolved != null) {
836 | return resolved;
837 | }
838 | }
839 | // Fallback to bounds
840 | return forType(resolveBounds(variable.getBounds()), this.variableResolver);
841 | }
842 | return NONE;
843 | }
844 |
845 | @Nullable
846 | private Type resolveBounds(Type[] bounds) {
847 | if (bounds.length == 0 || bounds[0] == Object.class) {
848 | return null;
849 | }
850 | return bounds[0];
851 | }
852 |
853 | @Nullable
854 | private ResolvableType resolveVariable(TypeVariable> variable) {
855 | if (this.type instanceof TypeVariable) {
856 | return resolveType().resolveVariable(variable);
857 | }
858 | if (this.type instanceof ParameterizedType) {
859 | ParameterizedType parameterizedType = (ParameterizedType) this.type;
860 | Class> resolved = resolve();
861 | if (resolved == null) {
862 | return null;
863 | }
864 | TypeVariable>[] variables = resolved.getTypeParameters();
865 | for (int i = 0; i < variables.length; i++) {
866 | if (ObjectUtils.nullSafeEquals(variables[i].getName(), variable.getName())) {
867 | Type actualType = parameterizedType.getActualTypeArguments()[i];
868 | return forType(actualType, this.variableResolver);
869 | }
870 | }
871 | Type ownerType = parameterizedType.getOwnerType();
872 | if (ownerType != null) {
873 | return forType(ownerType, this.variableResolver).resolveVariable(variable);
874 | }
875 | }
876 | if (this.type instanceof WildcardType) {
877 | ResolvableType resolved = resolveType().resolveVariable(variable);
878 | if (resolved != null) {
879 | return resolved;
880 | }
881 | }
882 | if (this.variableResolver != null) {
883 | return this.variableResolver.resolveVariable(variable);
884 | }
885 | return null;
886 | }
887 |
888 |
889 | @Override
890 | public boolean equals(@Nullable Object other) {
891 | if (this == other) {
892 | return true;
893 | }
894 | if (!(other instanceof ResolvableType)) {
895 | return false;
896 | }
897 |
898 | ResolvableType otherType = (ResolvableType) other;
899 | if (!ObjectUtils.nullSafeEquals(this.type, otherType.type)) {
900 | return false;
901 | }
902 | if (this.typeProvider != otherType.typeProvider &&
903 | (this.typeProvider == null || otherType.typeProvider == null ||
904 | !ObjectUtils.nullSafeEquals(this.typeProvider.getType(), otherType.typeProvider.getType()))) {
905 | return false;
906 | }
907 | if (this.variableResolver != otherType.variableResolver &&
908 | (this.variableResolver == null || otherType.variableResolver == null ||
909 | !ObjectUtils.nullSafeEquals(this.variableResolver.getSource(), otherType.variableResolver.getSource()))) {
910 | return false;
911 | }
912 | if (!ObjectUtils.nullSafeEquals(this.componentType, otherType.componentType)) {
913 | return false;
914 | }
915 | return true;
916 | }
917 |
918 | @Override
919 | public int hashCode() {
920 | return (this.hash != null ? this.hash : calculateHashCode());
921 | }
922 |
923 | private int calculateHashCode() {
924 | int hashCode = ObjectUtils.nullSafeHashCode(this.type);
925 | if (this.typeProvider != null) {
926 | hashCode = 31 * hashCode + ObjectUtils.nullSafeHashCode(this.typeProvider.getType());
927 | }
928 | if (this.variableResolver != null) {
929 | hashCode = 31 * hashCode + ObjectUtils.nullSafeHashCode(this.variableResolver.getSource());
930 | }
931 | if (this.componentType != null) {
932 | hashCode = 31 * hashCode + ObjectUtils.nullSafeHashCode(this.componentType);
933 | }
934 | return hashCode;
935 | }
936 |
937 | /**
938 | * Adapts this {@link ResolvableType} to a {@link VariableResolver}.
939 | */
940 | @Nullable
941 | VariableResolver asVariableResolver() {
942 | if (this == NONE) {
943 | return null;
944 | }
945 | return new DefaultVariableResolver(this);
946 | }
947 |
948 | /**
949 | * Custom serialization support for {@link #NONE}.
950 | */
951 | private Object readResolve() {
952 | return (this.type == EmptyType.INSTANCE ? NONE : this);
953 | }
954 |
955 | /**
956 | * Return a String representation of this type in its fully resolved form
957 | * (including any generic parameters).
958 | */
959 | @Override
960 | public String toString() {
961 | if (isArray()) {
962 | return getComponentType() + "[]";
963 | }
964 | if (this.resolved == null) {
965 | return "?";
966 | }
967 | if (this.type instanceof TypeVariable) {
968 | TypeVariable> variable = (TypeVariable>) this.type;
969 | if (this.variableResolver == null || this.variableResolver.resolveVariable(variable) == null) {
970 | // Don't bother with variable boundaries for toString()...
971 | // Can cause infinite recursions in case of self-references
972 | return "?";
973 | }
974 | }
975 | if (hasGenerics()) {
976 | return this.resolved.getName() + '<' + StringUtils.arrayToDelimitedString(getGenerics(), ", ") + '>';
977 | }
978 | return this.resolved.getName();
979 | }
980 |
981 |
982 | // Factory methods
983 |
984 | /**
985 | * Return a {@link ResolvableType} for the specified {@link Class},
986 | * using the full generic type information for assignability checks.
987 | * For example: {@code ResolvableType.forClass(MyArrayList.class)}.
988 | * @param clazz the class to introspect ({@code null} is semantically
989 | * equivalent to {@code Object.class} for typical use cases here)
990 | * @return a {@link ResolvableType} for the specified class
991 | * @see #forClass(Class, Class)
992 | * @see #forClassWithGenerics(Class, Class...)
993 | */
994 | public static ResolvableType forClass(@Nullable Class> clazz) {
995 | return new ResolvableType(clazz);
996 | }
997 |
998 | /**
999 | * Return a {@link ResolvableType} for the specified {@link Class},
1000 | * doing assignability checks against the raw class only (analogous to
1001 | * {@link Class#isAssignableFrom}, which this serves as a wrapper for.
1002 | * For example: {@code ResolvableType.forRawClass(List.class)}.
1003 | * @param clazz the class to introspect ({@code null} is semantically
1004 | * equivalent to {@code Object.class} for typical use cases here)
1005 | * @return a {@link ResolvableType} for the specified class
1006 | * @since 4.2
1007 | * @see #forClass(Class)
1008 | * @see #getRawClass()
1009 | */
1010 | public static ResolvableType forRawClass(@Nullable Class> clazz) {
1011 | return new ResolvableType(clazz) {
1012 | @Override
1013 | public ResolvableType[] getGenerics() {
1014 | return EMPTY_TYPES_ARRAY;
1015 | }
1016 | @Override
1017 | public boolean isAssignableFrom(Class> other) {
1018 | return (clazz == null || ClassUtils.isAssignable(clazz, other));
1019 | }
1020 | @Override
1021 | public boolean isAssignableFrom(ResolvableType other) {
1022 | Class> otherClass = other.resolve();
1023 | return (otherClass != null && (clazz == null || ClassUtils.isAssignable(clazz, otherClass))
1024 | || otherClass.isAssignableFrom(clazz));
1025 | }
1026 | };
1027 | }
1028 |
1029 | /**
1030 | * Return a {@link ResolvableType} for the specified base type
1031 | * (interface or base class) with a given implementation class.
1032 | * For example: {@code ResolvableType.forClass(List.class, MyArrayList.class)}.
1033 | * @param baseType the base type (must not be {@code null})
1034 | * @param implementationClass the implementation class
1035 | * @return a {@link ResolvableType} for the specified base type backed by the
1036 | * given implementation class
1037 | * @see #forClass(Class)
1038 | * @see #forClassWithGenerics(Class, Class...)
1039 | */
1040 | public static ResolvableType forClass(Class> baseType, Class> implementationClass) {
1041 | Assert.notNull(baseType, "Base type must not be null");
1042 | ResolvableType asType = forType(implementationClass).as(baseType);
1043 | return (asType == NONE ? forType(baseType) : asType);
1044 | }
1045 |
1046 | /**
1047 | * Return a {@link ResolvableType} for the specified {@link Class} with pre-declared generics.
1048 | * @param clazz the class (or interface) to introspect
1049 | * @param generics the generics of the class
1050 | * @return a {@link ResolvableType} for the specific class and generics
1051 | * @see #forClassWithGenerics(Class, ResolvableType...)
1052 | */
1053 | public static ResolvableType forClassWithGenerics(Class> clazz, Class>... generics) {
1054 | Assert.notNull(clazz, "Class must not be null");
1055 | Assert.notNull(generics, "Generics array must not be null");
1056 | ResolvableType[] resolvableGenerics = new ResolvableType[generics.length];
1057 | for (int i = 0; i < generics.length; i++) {
1058 | resolvableGenerics[i] = forClass(generics[i]);
1059 | }
1060 | return forClassWithGenerics(clazz, resolvableGenerics);
1061 | }
1062 |
1063 | /**
1064 | * Return a {@link ResolvableType} for the specified {@link Class} with pre-declared generics.
1065 | * @param clazz the class (or interface) to introspect
1066 | * @param generics the generics of the class
1067 | * @return a {@link ResolvableType} for the specific class and generics
1068 | * @see #forClassWithGenerics(Class, Class...)
1069 | */
1070 | public static ResolvableType forClassWithGenerics(Class> clazz, ResolvableType... generics) {
1071 | Assert.notNull(clazz, "Class must not be null");
1072 | Assert.notNull(generics, "Generics array must not be null");
1073 | TypeVariable>[] variables = clazz.getTypeParameters();
1074 | Assert.isTrue(variables.length == generics.length, "Mismatched number of generics specified");
1075 |
1076 | Type[] arguments = new Type[generics.length];
1077 | for (int i = 0; i < generics.length; i++) {
1078 | ResolvableType generic = generics[i];
1079 | Type argument = (generic != null ? generic.getType() : null);
1080 | arguments[i] = (argument != null && !(argument instanceof TypeVariable) ? argument : variables[i]);
1081 | }
1082 |
1083 | ParameterizedType syntheticType = new SyntheticParameterizedType(clazz, arguments);
1084 | return forType(syntheticType, new TypeVariablesVariableResolver(variables, generics));
1085 | }
1086 |
1087 | /**
1088 | * Return a {@link ResolvableType} for the specified instance. The instance does not
1089 | * convey generic information but if it implements {@link ResolvableTypeProvider} a
1090 | * more precise {@link ResolvableType} can be used than the simple one based on
1091 | * the {@link #forClass(Class) Class instance}.
1092 | * @param instance the instance
1093 | * @return a {@link ResolvableType} for the specified instance
1094 | * @since 4.2
1095 | * @see ResolvableTypeProvider
1096 | */
1097 | public static ResolvableType forInstance(Object instance) {
1098 | Assert.notNull(instance, "Instance must not be null");
1099 | if (instance instanceof ResolvableTypeProvider) {
1100 | ResolvableType type = ((ResolvableTypeProvider) instance).getResolvableType();
1101 | if (type != null) {
1102 | return type;
1103 | }
1104 | }
1105 | return ResolvableType.forClass(instance.getClass());
1106 | }
1107 |
1108 | /**
1109 | * Return a {@link ResolvableType} for the specified {@link Field}.
1110 | * @param field the source field
1111 | * @return a {@link ResolvableType} for the specified field
1112 | * @see #forField(Field, Class)
1113 | */
1114 | public static ResolvableType forField(Field field) {
1115 | Assert.notNull(field, "Field must not be null");
1116 | return forType(null, new FieldTypeProvider(field), null);
1117 | }
1118 |
1119 | /**
1120 | * Return a {@link ResolvableType} for the specified {@link Field} with a given
1121 | * implementation.
1122 | * Use this variant when the class that declares the field includes generic
1123 | * parameter variables that are satisfied by the implementation class.
1124 | * @param field the source field
1125 | * @param implementationClass the implementation class
1126 | * @return a {@link ResolvableType} for the specified field
1127 | * @see #forField(Field)
1128 | */
1129 | public static ResolvableType forField(Field field, Class> implementationClass) {
1130 | Assert.notNull(field, "Field must not be null");
1131 | ResolvableType owner = forType(implementationClass).as(field.getDeclaringClass());
1132 | return forType(null, new FieldTypeProvider(field), owner.asVariableResolver());
1133 | }
1134 |
1135 | /**
1136 | * Return a {@link ResolvableType} for the specified {@link Field} with a given
1137 | * implementation.
1138 | * Use this variant when the class that declares the field includes generic
1139 | * parameter variables that are satisfied by the implementation type.
1140 | * @param field the source field
1141 | * @param implementationType the implementation type
1142 | * @return a {@link ResolvableType} for the specified field
1143 | * @see #forField(Field)
1144 | */
1145 | public static ResolvableType forField(Field field, @Nullable ResolvableType implementationType) {
1146 | Assert.notNull(field, "Field must not be null");
1147 | ResolvableType owner = (implementationType != null ? implementationType : NONE);
1148 | owner = owner.as(field.getDeclaringClass());
1149 | return forType(null, new FieldTypeProvider(field), owner.asVariableResolver());
1150 | }
1151 |
1152 | /**
1153 | * Return a {@link ResolvableType} for the specified {@link Field} with the
1154 | * given nesting level.
1155 | * @param field the source field
1156 | * @param nestingLevel the nesting level (1 for the outer level; 2 for a nested
1157 | * generic type; etc)
1158 | * @see #forField(Field)
1159 | */
1160 | public static ResolvableType forField(Field field, int nestingLevel) {
1161 | Assert.notNull(field, "Field must not be null");
1162 | return forType(null, new FieldTypeProvider(field), null).getNested(nestingLevel);
1163 | }
1164 |
1165 | /**
1166 | * Return a {@link ResolvableType} for the specified {@link Field} with a given
1167 | * implementation and the given nesting level.
1168 | * Use this variant when the class that declares the field includes generic
1169 | * parameter variables that are satisfied by the implementation class.
1170 | * @param field the source field
1171 | * @param nestingLevel the nesting level (1 for the outer level; 2 for a nested
1172 | * generic type; etc)
1173 | * @param implementationClass the implementation class
1174 | * @return a {@link ResolvableType} for the specified field
1175 | * @see #forField(Field)
1176 | */
1177 | public static ResolvableType forField(Field field, int nestingLevel, @Nullable Class> implementationClass) {
1178 | Assert.notNull(field, "Field must not be null");
1179 | ResolvableType owner = forType(implementationClass).as(field.getDeclaringClass());
1180 | return forType(null, new FieldTypeProvider(field), owner.asVariableResolver()).getNested(nestingLevel);
1181 | }
1182 |
1183 | /**
1184 | * Return a {@link ResolvableType} for the specified {@link Constructor} parameter.
1185 | * @param constructor the source constructor (must not be {@code null})
1186 | * @param parameterIndex the parameter index
1187 | * @return a {@link ResolvableType} for the specified constructor parameter
1188 | * @see #forConstructorParameter(Constructor, int, Class)
1189 | */
1190 | public static ResolvableType forConstructorParameter(Constructor> constructor, int parameterIndex) {
1191 | Assert.notNull(constructor, "Constructor must not be null");
1192 | return forMethodParameter(new MethodParameter(constructor, parameterIndex));
1193 | }
1194 |
1195 | /**
1196 | * Return a {@link ResolvableType} for the specified {@link Constructor} parameter
1197 | * with a given implementation. Use this variant when the class that declares the
1198 | * constructor includes generic parameter variables that are satisfied by the
1199 | * implementation class.
1200 | * @param constructor the source constructor (must not be {@code null})
1201 | * @param parameterIndex the parameter index
1202 | * @param implementationClass the implementation class
1203 | * @return a {@link ResolvableType} for the specified constructor parameter
1204 | * @see #forConstructorParameter(Constructor, int)
1205 | */
1206 | public static ResolvableType forConstructorParameter(Constructor> constructor, int parameterIndex,
1207 | Class> implementationClass) {
1208 |
1209 | Assert.notNull(constructor, "Constructor must not be null");
1210 | MethodParameter methodParameter = new MethodParameter(constructor, parameterIndex, implementationClass);
1211 | return forMethodParameter(methodParameter);
1212 | }
1213 |
1214 | /**
1215 | * Return a {@link ResolvableType} for the specified {@link Method} return type.
1216 | * @param method the source for the method return type
1217 | * @return a {@link ResolvableType} for the specified method return
1218 | * @see #forMethodReturnType(Method, Class)
1219 | */
1220 | public static ResolvableType forMethodReturnType(Method method) {
1221 | Assert.notNull(method, "Method must not be null");
1222 | return forMethodParameter(new MethodParameter(method, -1));
1223 | }
1224 |
1225 | /**
1226 | * Return a {@link ResolvableType} for the specified {@link Method} return type.
1227 | * Use this variant when the class that declares the method includes generic
1228 | * parameter variables that are satisfied by the implementation class.
1229 | * @param method the source for the method return type
1230 | * @param implementationClass the implementation class
1231 | * @return a {@link ResolvableType} for the specified method return
1232 | * @see #forMethodReturnType(Method)
1233 | */
1234 | public static ResolvableType forMethodReturnType(Method method, Class> implementationClass) {
1235 | Assert.notNull(method, "Method must not be null");
1236 | MethodParameter methodParameter = new MethodParameter(method, -1, implementationClass);
1237 | return forMethodParameter(methodParameter);
1238 | }
1239 |
1240 | /**
1241 | * Return a {@link ResolvableType} for the specified {@link Method} parameter.
1242 | * @param method the source method (must not be {@code null})
1243 | * @param parameterIndex the parameter index
1244 | * @return a {@link ResolvableType} for the specified method parameter
1245 | * @see #forMethodParameter(Method, int, Class)
1246 | * @see #forMethodParameter(MethodParameter)
1247 | */
1248 | public static ResolvableType forMethodParameter(Method method, int parameterIndex) {
1249 | Assert.notNull(method, "Method must not be null");
1250 | return forMethodParameter(new MethodParameter(method, parameterIndex));
1251 | }
1252 |
1253 | /**
1254 | * Return a {@link ResolvableType} for the specified {@link Method} parameter with a
1255 | * given implementation. Use this variant when the class that declares the method
1256 | * includes generic parameter variables that are satisfied by the implementation class.
1257 | * @param method the source method (must not be {@code null})
1258 | * @param parameterIndex the parameter index
1259 | * @param implementationClass the implementation class
1260 | * @return a {@link ResolvableType} for the specified method parameter
1261 | * @see #forMethodParameter(Method, int, Class)
1262 | * @see #forMethodParameter(MethodParameter)
1263 | */
1264 | public static ResolvableType forMethodParameter(Method method, int parameterIndex, Class> implementationClass) {
1265 | Assert.notNull(method, "Method must not be null");
1266 | MethodParameter methodParameter = new MethodParameter(method, parameterIndex, implementationClass);
1267 | return forMethodParameter(methodParameter);
1268 | }
1269 |
1270 | /**
1271 | * Return a {@link ResolvableType} for the specified {@link MethodParameter}.
1272 | * @param methodParameter the source method parameter (must not be {@code null})
1273 | * @return a {@link ResolvableType} for the specified method parameter
1274 | * @see #forMethodParameter(Method, int)
1275 | */
1276 | public static ResolvableType forMethodParameter(MethodParameter methodParameter) {
1277 | return forMethodParameter(methodParameter, (Type) null);
1278 | }
1279 |
1280 | /**
1281 | * Return a {@link ResolvableType} for the specified {@link MethodParameter} with a
1282 | * given implementation type. Use this variant when the class that declares the method
1283 | * includes generic parameter variables that are satisfied by the implementation type.
1284 | * @param methodParameter the source method parameter (must not be {@code null})
1285 | * @param implementationType the implementation type
1286 | * @return a {@link ResolvableType} for the specified method parameter
1287 | * @see #forMethodParameter(MethodParameter)
1288 | */
1289 | public static ResolvableType forMethodParameter(MethodParameter methodParameter,
1290 | @Nullable ResolvableType implementationType) {
1291 |
1292 | Assert.notNull(methodParameter, "MethodParameter must not be null");
1293 | implementationType = (implementationType != null ? implementationType :
1294 | forType(methodParameter.getContainingClass()));
1295 | ResolvableType owner = implementationType.as(methodParameter.getDeclaringClass());
1296 | return forType(null, new MethodParameterTypeProvider(methodParameter), owner.asVariableResolver()).
1297 | getNested(methodParameter.getNestingLevel(), methodParameter.typeIndexesPerLevel);
1298 | }
1299 |
1300 | /**
1301 | * Return a {@link ResolvableType} for the specified {@link MethodParameter},
1302 | * overriding the target type to resolve with a specific given type.
1303 | * @param methodParameter the source method parameter (must not be {@code null})
1304 | * @param targetType the type to resolve (a part of the method parameter's type)
1305 | * @return a {@link ResolvableType} for the specified method parameter
1306 | * @see #forMethodParameter(Method, int)
1307 | */
1308 | public static ResolvableType forMethodParameter(MethodParameter methodParameter, @Nullable Type targetType) {
1309 | Assert.notNull(methodParameter, "MethodParameter must not be null");
1310 | return forMethodParameter(methodParameter, targetType, methodParameter.getNestingLevel());
1311 | }
1312 |
1313 | /**
1314 | * Return a {@link ResolvableType} for the specified {@link MethodParameter} at
1315 | * a specific nesting level, overriding the target type to resolve with a specific
1316 | * given type.
1317 | * @param methodParameter the source method parameter (must not be {@code null})
1318 | * @param targetType the type to resolve (a part of the method parameter's type)
1319 | * @param nestingLevel the nesting level to use
1320 | * @return a {@link ResolvableType} for the specified method parameter
1321 | * @since 5.2
1322 | * @see #forMethodParameter(Method, int)
1323 | */
1324 | static ResolvableType forMethodParameter(
1325 | MethodParameter methodParameter, @Nullable Type targetType, int nestingLevel) {
1326 |
1327 | ResolvableType owner = forType(methodParameter.getContainingClass()).as(methodParameter.getDeclaringClass());
1328 | return forType(targetType, new MethodParameterTypeProvider(methodParameter), owner.asVariableResolver()).
1329 | getNested(nestingLevel, methodParameter.typeIndexesPerLevel);
1330 | }
1331 |
1332 | /**
1333 | * Return a {@link ResolvableType} as a array of the specified {@code componentType}.
1334 | * @param componentType the component type
1335 | * @return a {@link ResolvableType} as an array of the specified component type
1336 | */
1337 | public static ResolvableType forArrayComponent(ResolvableType componentType) {
1338 | Assert.notNull(componentType, "Component type must not be null");
1339 | Class> arrayClass = Array.newInstance(componentType.resolve(), 0).getClass();
1340 | return new ResolvableType(arrayClass, null, null, componentType);
1341 | }
1342 |
1343 | /**
1344 | * Return a {@link ResolvableType} for the specified {@link Type}.
1345 | * Note: The resulting {@link ResolvableType} instance may not be {@link Serializable}.
1346 | * @param type the source type (potentially {@code null})
1347 | * @return a {@link ResolvableType} for the specified {@link Type}
1348 | * @see #forType(Type, ResolvableType)
1349 | */
1350 | public static ResolvableType forType(@Nullable Type type) {
1351 | return forType(type, null, null);
1352 | }
1353 |
1354 | /**
1355 | * Return a {@link ResolvableType} for the specified {@link Type} backed by the given
1356 | * owner type.
1357 | * Note: The resulting {@link ResolvableType} instance may not be {@link Serializable}.
1358 | * @param type the source type or {@code null}
1359 | * @param owner the owner type used to resolve variables
1360 | * @return a {@link ResolvableType} for the specified {@link Type} and owner
1361 | * @see #forType(Type)
1362 | */
1363 | public static ResolvableType forType(@Nullable Type type, @Nullable ResolvableType owner) {
1364 | VariableResolver variableResolver = null;
1365 | if (owner != null) {
1366 | variableResolver = owner.asVariableResolver();
1367 | }
1368 | return forType(type, variableResolver);
1369 | }
1370 |
1371 |
1372 | /**
1373 | * Return a {@link ResolvableType} for the specified {@link ParameterizedTypeReference}.
1374 | * Note: The resulting {@link ResolvableType} instance may not be {@link Serializable}.
1375 | * @param typeReference the reference to obtain the source type from
1376 | * @return a {@link ResolvableType} for the specified {@link ParameterizedTypeReference}
1377 | * @since 4.3.12
1378 | * @see #forType(Type)
1379 | */
1380 | public static ResolvableType forType(ParameterizedTypeReference> typeReference) {
1381 | return forType(typeReference.getType(), null, null);
1382 | }
1383 |
1384 | /**
1385 | * Return a {@link ResolvableType} for the specified {@link Type} backed by a given
1386 | * {@link VariableResolver}.
1387 | * @param type the source type or {@code null}
1388 | * @param variableResolver the variable resolver or {@code null}
1389 | * @return a {@link ResolvableType} for the specified {@link Type} and {@link VariableResolver}
1390 | */
1391 | static ResolvableType forType(@Nullable Type type, @Nullable VariableResolver variableResolver) {
1392 | return forType(type, null, variableResolver);
1393 | }
1394 |
1395 | /**
1396 | * Return a {@link ResolvableType} for the specified {@link Type} backed by a given
1397 | * {@link VariableResolver}.
1398 | * @param type the source type or {@code null}
1399 | * @param typeProvider the type provider or {@code null}
1400 | * @param variableResolver the variable resolver or {@code null}
1401 | * @return a {@link ResolvableType} for the specified {@link Type} and {@link VariableResolver}
1402 | */
1403 | static ResolvableType forType(
1404 | @Nullable Type type, @Nullable TypeProvider typeProvider, @Nullable VariableResolver variableResolver) {
1405 |
1406 | if (type == null && typeProvider != null) {
1407 | type = SerializableTypeWrapper.forTypeProvider(typeProvider);
1408 | }
1409 | if (type == null) {
1410 | return NONE;
1411 | }
1412 |
1413 | // For simple Class references, build the wrapper right away -
1414 | // no expensive resolution necessary, so not worth caching...
1415 | if (type instanceof Class) {
1416 | return new ResolvableType(type, typeProvider, variableResolver, (ResolvableType) null);
1417 | }
1418 |
1419 | // Purge empty entries on access since we don't have a clean-up thread or the like.
1420 | cache.purgeUnreferencedEntries();
1421 |
1422 | // Check the cache - we may have a ResolvableType which has been resolved before...
1423 | ResolvableType resultType = new ResolvableType(type, typeProvider, variableResolver);
1424 | ResolvableType cachedType = cache.get(resultType);
1425 | if (cachedType == null) {
1426 | cachedType = new ResolvableType(type, typeProvider, variableResolver, resultType.hash);
1427 | cache.put(cachedType, cachedType);
1428 | }
1429 | resultType.resolved = cachedType.resolved;
1430 | return resultType;
1431 | }
1432 |
1433 | /**
1434 | * Clear the internal {@code ResolvableType}/{@code SerializableTypeWrapper} cache.
1435 | * @since 4.2
1436 | */
1437 | public static void clearCache() {
1438 | cache.clear();
1439 | SerializableTypeWrapper.cache.clear();
1440 | }
1441 |
1442 |
1443 | /**
1444 | * Strategy interface used to resolve {@link TypeVariable TypeVariables}.
1445 | */
1446 | interface VariableResolver extends Serializable {
1447 |
1448 | /**
1449 | * Return the source of the resolver (used for hashCode and equals).
1450 | */
1451 | Object getSource();
1452 |
1453 | /**
1454 | * Resolve the specified variable.
1455 | * @param variable the variable to resolve
1456 | * @return the resolved variable, or {@code null} if not found
1457 | */
1458 | @Nullable
1459 | ResolvableType resolveVariable(TypeVariable> variable);
1460 | }
1461 |
1462 |
1463 | @SuppressWarnings("serial")
1464 | private static class DefaultVariableResolver implements VariableResolver {
1465 |
1466 | private final ResolvableType source;
1467 |
1468 | DefaultVariableResolver(ResolvableType resolvableType) {
1469 | this.source = resolvableType;
1470 | }
1471 |
1472 | @Override
1473 | @Nullable
1474 | public ResolvableType resolveVariable(TypeVariable> variable) {
1475 | return this.source.resolveVariable(variable);
1476 | }
1477 |
1478 | @Override
1479 | public Object getSource() {
1480 | return this.source;
1481 | }
1482 | }
1483 |
1484 |
1485 | @SuppressWarnings("serial")
1486 | private static class TypeVariablesVariableResolver implements VariableResolver {
1487 |
1488 | private final TypeVariable>[] variables;
1489 |
1490 | private final ResolvableType[] generics;
1491 |
1492 | public TypeVariablesVariableResolver(TypeVariable>[] variables, ResolvableType[] generics) {
1493 | this.variables = variables;
1494 | this.generics = generics;
1495 | }
1496 |
1497 | @Override
1498 | @Nullable
1499 | public ResolvableType resolveVariable(TypeVariable> variable) {
1500 | TypeVariable> variableToCompare = SerializableTypeWrapper.unwrap(variable);
1501 | for (int i = 0; i < this.variables.length; i++) {
1502 | TypeVariable> resolvedVariable = SerializableTypeWrapper.unwrap(this.variables[i]);
1503 | if (ObjectUtils.nullSafeEquals(resolvedVariable, variableToCompare)) {
1504 | return this.generics[i];
1505 | }
1506 | }
1507 | return null;
1508 | }
1509 |
1510 | @Override
1511 | public Object getSource() {
1512 | return this.generics;
1513 | }
1514 | }
1515 |
1516 |
1517 | private static final class SyntheticParameterizedType implements ParameterizedType, Serializable {
1518 |
1519 | private final Type rawType;
1520 |
1521 | private final Type[] typeArguments;
1522 |
1523 | public SyntheticParameterizedType(Type rawType, Type[] typeArguments) {
1524 | this.rawType = rawType;
1525 | this.typeArguments = typeArguments;
1526 | }
1527 |
1528 | @Override
1529 | public String getTypeName() {
1530 | String typeName = this.rawType.getTypeName();
1531 | if (this.typeArguments.length > 0) {
1532 | StringJoiner stringJoiner = new StringJoiner(", ", "<", ">");
1533 | for (Type argument : this.typeArguments) {
1534 | stringJoiner.add(argument.getTypeName());
1535 | }
1536 | return typeName + stringJoiner;
1537 | }
1538 | return typeName;
1539 | }
1540 |
1541 | @Override
1542 | @Nullable
1543 | public Type getOwnerType() {
1544 | return null;
1545 | }
1546 |
1547 | @Override
1548 | public Type getRawType() {
1549 | return this.rawType;
1550 | }
1551 |
1552 | @Override
1553 | public Type[] getActualTypeArguments() {
1554 | return this.typeArguments;
1555 | }
1556 |
1557 | @Override
1558 | public boolean equals(@Nullable Object other) {
1559 | if (this == other) {
1560 | return true;
1561 | }
1562 | if (!(other instanceof ParameterizedType)) {
1563 | return false;
1564 | }
1565 | ParameterizedType otherType = (ParameterizedType) other;
1566 | return (otherType.getOwnerType() == null && this.rawType.equals(otherType.getRawType()) &&
1567 | Arrays.equals(this.typeArguments, otherType.getActualTypeArguments()));
1568 | }
1569 |
1570 | @Override
1571 | public int hashCode() {
1572 | return (this.rawType.hashCode() * 31 + Arrays.hashCode(this.typeArguments));
1573 | }
1574 |
1575 | @Override
1576 | public String toString() {
1577 | return getTypeName();
1578 | }
1579 | }
1580 |
1581 |
1582 | /**
1583 | * Internal helper to handle bounds from {@link WildcardType WildcardTypes}.
1584 | */
1585 | private static class WildcardBounds {
1586 |
1587 | private final Kind kind;
1588 |
1589 | private final ResolvableType[] bounds;
1590 |
1591 | /**
1592 | * Internal constructor to create a new {@link WildcardBounds} instance.
1593 | * @param kind the kind of bounds
1594 | * @param bounds the bounds
1595 | * @see #get(ResolvableType)
1596 | */
1597 | public WildcardBounds(Kind kind, ResolvableType[] bounds) {
1598 | this.kind = kind;
1599 | this.bounds = bounds;
1600 | }
1601 |
1602 | /**
1603 | * Return {@code true} if this bounds is the same kind as the specified bounds.
1604 | */
1605 | public boolean isSameKind(WildcardBounds bounds) {
1606 | return this.kind == bounds.kind;
1607 | }
1608 |
1609 | /**
1610 | * Return {@code true} if this bounds is assignable to all the specified types.
1611 | * @param types the types to test against
1612 | * @return {@code true} if this bounds is assignable to all types
1613 | */
1614 | public boolean isAssignableFrom(ResolvableType... types) {
1615 | for (ResolvableType bound : this.bounds) {
1616 | for (ResolvableType type : types) {
1617 | if (!isAssignable(bound, type)) {
1618 | return false;
1619 | }
1620 | }
1621 | }
1622 | return true;
1623 | }
1624 |
1625 | private boolean isAssignable(ResolvableType source, ResolvableType from) {
1626 | return (this.kind == Kind.UPPER ? source.isAssignableFrom(from) : from.isAssignableFrom(source));
1627 | }
1628 |
1629 | /**
1630 | * Return the underlying bounds.
1631 | */
1632 | public ResolvableType[] getBounds() {
1633 | return this.bounds;
1634 | }
1635 |
1636 | /**
1637 | * Get a {@link WildcardBounds} instance for the specified type, returning
1638 | * {@code null} if the specified type cannot be resolved to a {@link WildcardType}.
1639 | * @param type the source type
1640 | * @return a {@link WildcardBounds} instance or {@code null}
1641 | */
1642 | @Nullable
1643 | public static WildcardBounds get(ResolvableType type) {
1644 | ResolvableType resolveToWildcard = type;
1645 | while (!(resolveToWildcard.getType() instanceof WildcardType)) {
1646 | if (resolveToWildcard == NONE) {
1647 | return null;
1648 | }
1649 | resolveToWildcard = resolveToWildcard.resolveType();
1650 | }
1651 | WildcardType wildcardType = (WildcardType) resolveToWildcard.type;
1652 | Kind boundsType = (wildcardType.getLowerBounds().length > 0 ? Kind.LOWER : Kind.UPPER);
1653 | Type[] bounds = (boundsType == Kind.UPPER ? wildcardType.getUpperBounds() : wildcardType.getLowerBounds());
1654 | ResolvableType[] resolvableBounds = new ResolvableType[bounds.length];
1655 | for (int i = 0; i < bounds.length; i++) {
1656 | resolvableBounds[i] = ResolvableType.forType(bounds[i], type.variableResolver);
1657 | }
1658 | return new WildcardBounds(boundsType, resolvableBounds);
1659 | }
1660 |
1661 | /**
1662 | * The various kinds of bounds.
1663 | */
1664 | enum Kind {UPPER, LOWER}
1665 | }
1666 |
1667 |
1668 | /**
1669 | * Internal {@link Type} used to represent an empty value.
1670 | */
1671 | @SuppressWarnings("serial")
1672 | static class EmptyType implements Type, Serializable {
1673 |
1674 | static final Type INSTANCE = new EmptyType();
1675 |
1676 | Object readResolve() {
1677 | return INSTANCE;
1678 | }
1679 | }
1680 |
1681 | }
1682 |
--------------------------------------------------------------------------------
/src/main/resources/interview.sql:
--------------------------------------------------------------------------------
1 | -- SQL execute link >> https://onecompiler.com/mysql/3y92m8sqt
2 |
3 | -- create
4 | CREATE TABLE course (
5 | id BIGINT PRIMARY KEY,
6 | name VARCHAR(64) NOT NULL
7 | );
8 | CREATE TABLE student (
9 | id BIGINT PRIMARY KEY,
10 | name VARCHAR(64) NOT NULL
11 | );
12 | CREATE TABLE student_score (
13 | id BIGINT PRIMARY KEY,
14 | student_id BIGINT NOT NULL,
15 | course_id BIGINT NOT NULL,
16 | score FLOAT NOT NULL
17 | );
18 |
19 | -- insert
20 | INSERT INTO course VALUES (1, '语文');
21 | INSERT INTO course VALUES (2, '数学');
22 | INSERT INTO course VALUES (3, '英语');
23 |
24 | INSERT INTO student VALUES (1, '小李');
25 | INSERT INTO student VALUES (2, '小马');
26 | INSERT INTO student VALUES (3, '小王');
27 | INSERT INTO student VALUES (4, '小张');
28 |
29 | -- 小李
30 | INSERT INTO student_score VALUES (1, 1, 1, 80);
31 | INSERT INTO student_score VALUES (2, 1, 2, 90);
32 | INSERT INTO student_score VALUES (3, 1, 3, 70);
33 |
34 | -- 小马
35 | INSERT INTO student_score VALUES (4, 2, 1, 70);
36 | INSERT INTO student_score VALUES (5, 2, 2, 90);
37 | INSERT INTO student_score VALUES (6, 2, 3, 90);
38 |
39 | -- 小王
40 | INSERT INTO student_score VALUES (7, 3, 1, 80);
41 | INSERT INTO student_score VALUES (8, 3, 2, 90);
42 | INSERT INTO student_score VALUES (9, 3, 3, 90);
43 |
44 | -- 小张
45 | INSERT INTO student_score VALUES (10, 4, 1, 70);
46 | INSERT INTO student_score VALUES (11, 4, 2, 80);
47 | INSERT INTO student_score VALUES (12, 4, 3, 80);
48 |
49 |
50 | -- fetch
51 | -- SELECT * FROM student_score ORDER BY course_id DESC;
52 | -- 视频中的SQL
53 | SELECT c.name AS 课程,t.score AS 最高分分数,s.name AS 学生名 FROM
54 | (SELECT MAX(score) score, course_id FROM student_score ss
55 | GROUP BY course_id) t
56 | RIGHT JOIN
57 | student_score sc
58 | ON sc.score = t.score AND sc.course_id = t.course_id
59 | LEFT JOIN
60 | student s
61 | ON s.id = sc.student_id
62 | LEFT JOIN
63 | course c
64 | ON c.id = sc.course_id
65 | ORDER BY c.id DESC;
66 |
67 |
68 | -- 下面是正确答案
69 | SELECT c.name AS 课程,t.score AS 最高分分数,s.name AS 学生名 FROM
70 | (SELECT MAX(score) score, course_id FROM student_score ss
71 | GROUP BY course_id) t
72 | LEFT JOIN -- 这里换成LEFT即可
73 | student_score sc
74 | ON sc.score = t.score AND sc.course_id = t.course_id
75 | LEFT JOIN
76 | student s
77 | ON s.id = sc.student_id
78 | LEFT JOIN
79 | course c
80 | ON c.id = sc.course_id
81 | ORDER BY c.id DESC;
--------------------------------------------------------------------------------