1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.apache.logging.log4j.core.util;
18
19 import java.lang.reflect.GenericArrayType;
20 import java.lang.reflect.ParameterizedType;
21 import java.lang.reflect.Type;
22 import java.lang.reflect.WildcardType;
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37 public final class TypeUtil {
38 private TypeUtil() {
39 }
40
41
42
43
44
45
46
47
48
49 public static boolean isAssignable(final Type lhs, final Type rhs) {
50 Assert.requireNonNull(lhs, "No left hand side type provided");
51 Assert.requireNonNull(rhs, "No right hand side type provided");
52 if (lhs.equals(rhs)) {
53 return true;
54 }
55 if (Object.class.equals(lhs)) {
56
57 return true;
58 }
59
60 if (lhs instanceof Class<?>) {
61 final Class<?> lhsClass = (Class<?>) lhs;
62 if (rhs instanceof Class<?>) {
63
64 final Class<?> rhsClass = (Class<?>) rhs;
65 return lhsClass.isAssignableFrom(rhsClass);
66 }
67 if (rhs instanceof ParameterizedType) {
68
69 final Type rhsRawType = ((ParameterizedType) rhs).getRawType();
70 if (rhsRawType instanceof Class<?>) {
71 return lhsClass.isAssignableFrom((Class<?>) rhsRawType);
72 }
73 }
74 if (lhsClass.isArray() && rhs instanceof GenericArrayType) {
75
76 return isAssignable(lhsClass.getComponentType(), ((GenericArrayType) rhs).getGenericComponentType());
77 }
78 }
79
80 if (lhs instanceof ParameterizedType) {
81 final ParameterizedType lhsType = (ParameterizedType) lhs;
82 if (rhs instanceof Class<?>) {
83 final Type lhsRawType = lhsType.getRawType();
84 if (lhsRawType instanceof Class<?>) {
85 return ((Class<?>) lhsRawType).isAssignableFrom((Class<?>) rhs);
86 }
87 } else if (rhs instanceof ParameterizedType) {
88 final ParameterizedType rhsType = (ParameterizedType) rhs;
89 return isParameterizedAssignable(lhsType, rhsType);
90 }
91 }
92
93 if (lhs instanceof GenericArrayType) {
94 final Type lhsComponentType = ((GenericArrayType) lhs).getGenericComponentType();
95 if (rhs instanceof Class<?>) {
96
97 final Class<?> rhsClass = (Class<?>) rhs;
98 if (rhsClass.isArray()) {
99 return isAssignable(lhsComponentType, rhsClass.getComponentType());
100 }
101 } else if (rhs instanceof GenericArrayType) {
102 return isAssignable(lhsComponentType, ((GenericArrayType) rhs).getGenericComponentType());
103 }
104 }
105
106 if (lhs instanceof WildcardType) {
107 return isWildcardAssignable((WildcardType) lhs, rhs);
108 }
109
110 return false;
111 }
112
113 private static boolean isParameterizedAssignable(final ParameterizedType lhs, final ParameterizedType rhs) {
114 if (lhs.equals(rhs)) {
115
116 return true;
117 }
118 final Type[] lhsTypeArguments = lhs.getActualTypeArguments();
119 final Type[] rhsTypeArguments = rhs.getActualTypeArguments();
120 final int size = lhsTypeArguments.length;
121 if (rhsTypeArguments.length != size) {
122
123 return false;
124 }
125 for (int i = 0; i < size; i++) {
126
127 final Type lhsArgument = lhsTypeArguments[i];
128 final Type rhsArgument = rhsTypeArguments[i];
129 if (!lhsArgument.equals(rhsArgument) &&
130 !(lhsArgument instanceof WildcardType &&
131 isWildcardAssignable((WildcardType) lhsArgument, rhsArgument))) {
132 return false;
133 }
134 }
135 return true;
136 }
137
138 private static boolean isWildcardAssignable(final WildcardType lhs, final Type rhs) {
139 final Type[] lhsUpperBounds = getEffectiveUpperBounds(lhs);
140 final Type[] lhsLowerBounds = getEffectiveLowerBounds(lhs);
141 if (rhs instanceof WildcardType) {
142
143 final WildcardType rhsType = (WildcardType) rhs;
144 final Type[] rhsUpperBounds = getEffectiveUpperBounds(rhsType);
145 final Type[] rhsLowerBounds = getEffectiveLowerBounds(rhsType);
146 for (final Type lhsUpperBound : lhsUpperBounds) {
147 for (final Type rhsUpperBound : rhsUpperBounds) {
148 if (!isBoundAssignable(lhsUpperBound, rhsUpperBound)) {
149 return false;
150 }
151 }
152 for (final Type rhsLowerBound : rhsLowerBounds) {
153 if (!isBoundAssignable(lhsUpperBound, rhsLowerBound)) {
154 return false;
155 }
156 }
157 }
158 for (final Type lhsLowerBound : lhsLowerBounds) {
159 for (final Type rhsUpperBound : rhsUpperBounds) {
160 if (!isBoundAssignable(rhsUpperBound, lhsLowerBound)) {
161 return false;
162 }
163 }
164 for (final Type rhsLowerBound : rhsLowerBounds) {
165 if (!isBoundAssignable(rhsLowerBound, lhsLowerBound)) {
166 return false;
167 }
168 }
169 }
170 } else {
171
172 for (final Type lhsUpperBound : lhsUpperBounds) {
173 if (!isBoundAssignable(lhsUpperBound, rhs)) {
174 return false;
175 }
176 }
177 for (final Type lhsLowerBound : lhsLowerBounds) {
178 if (!isBoundAssignable(lhsLowerBound, rhs)) {
179 return false;
180 }
181 }
182 }
183 return true;
184 }
185
186 private static Type[] getEffectiveUpperBounds(final WildcardType type) {
187 final Type[] upperBounds = type.getUpperBounds();
188 return upperBounds.length == 0 ? new Type[]{Object.class} : upperBounds;
189 }
190
191 private static Type[] getEffectiveLowerBounds(final WildcardType type) {
192 final Type[] lowerBounds = type.getLowerBounds();
193 return lowerBounds.length == 0 ? new Type[]{null} : lowerBounds;
194 }
195
196 private static boolean isBoundAssignable(final Type lhs, final Type rhs) {
197 return (rhs == null) || ((lhs != null) && isAssignable(lhs, rhs));
198 }
199 }