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