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