1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.apache.shiro.lang.util;
20
21 import org.slf4j.Logger;
22 import org.slf4j.LoggerFactory;
23
24 import java.io.InputStream;
25 import java.lang.annotation.Annotation;
26 import java.lang.reflect.Constructor;
27 import java.lang.reflect.Method;
28 import java.util.ArrayList;
29 import java.util.HashMap;
30 import java.util.List;
31
32
33
34
35
36
37
38
39 public final class ClassUtils {
40
41
42
43
44 private static final Logger LOGGER = LoggerFactory.getLogger(ClassUtils.class);
45
46
47
48
49
50 private static final HashMap<String, Class<?>> PRIM_CLASSES
51 = new HashMap<>(8, 1.0F);
52
53 static {
54 PRIM_CLASSES.put("boolean", boolean.class);
55 PRIM_CLASSES.put("byte", byte.class);
56 PRIM_CLASSES.put("char", char.class);
57 PRIM_CLASSES.put("short", short.class);
58 PRIM_CLASSES.put("int", int.class);
59 PRIM_CLASSES.put("long", long.class);
60 PRIM_CLASSES.put("float", float.class);
61 PRIM_CLASSES.put("double", double.class);
62 PRIM_CLASSES.put("void", void.class);
63 }
64
65
66
67
68 private static final ClassLoaderAccessor THREAD_CL_ACCESSOR = new ExceptionIgnoringAccessor() {
69 @Override
70 protected ClassLoader doGetClassLoader() throws Throwable {
71 return Thread.currentThread().getContextClassLoader();
72 }
73 };
74
75
76
77
78 private static final ClassLoaderAccessor CLASS_CL_ACCESSOR = new ExceptionIgnoringAccessor() {
79 @Override
80 protected ClassLoader doGetClassLoader() throws Throwable {
81 return ClassUtils.class.getClassLoader();
82 }
83 };
84
85
86
87
88 private static final ClassLoaderAccessor SYSTEM_CL_ACCESSOR = new ExceptionIgnoringAccessor() {
89 @Override
90 protected ClassLoader doGetClassLoader() throws Throwable {
91 return ClassLoader.getSystemClassLoader();
92 }
93 };
94
95 private ClassUtils() {
96
97 }
98
99
100
101
102
103
104
105
106
107
108
109
110
111 public static InputStream getResourceAsStream(String name) {
112
113 InputStream is = THREAD_CL_ACCESSOR.getResourceStream(name);
114
115 if (is == null) {
116 if (LOGGER.isTraceEnabled()) {
117 LOGGER.trace("Resource [" + name + "] was not found via the thread context ClassLoader. Trying the "
118 + "current ClassLoader...");
119 }
120 is = CLASS_CL_ACCESSOR.getResourceStream(name);
121 }
122
123 if (is == null) {
124 if (LOGGER.isTraceEnabled()) {
125 LOGGER.trace("Resource [" + name + "] was not found via the current class loader. Trying the "
126 + "system/application ClassLoader...");
127 }
128 is = SYSTEM_CL_ACCESSOR.getResourceStream(name);
129 }
130
131 if (is == null && LOGGER.isTraceEnabled()) {
132 LOGGER.trace("Resource [" + name + "] was not found via the thread context, current, or "
133 + "system/application ClassLoaders. All heuristics have been exhausted. Returning null.");
134 }
135
136 return is;
137 }
138
139
140
141
142
143
144
145
146
147
148
149
150
151 @SuppressWarnings("unchecked")
152 public static <T> Class<T> forName(String fqcn) throws UnknownClassException {
153 Class<?> clazz = THREAD_CL_ACCESSOR.loadClass(fqcn);
154
155 if (clazz == null) {
156 if (LOGGER.isTraceEnabled()) {
157 LOGGER.trace("Unable to load class named [" + fqcn
158 + "] from the thread context ClassLoader. Trying the current ClassLoader...");
159 }
160 clazz = CLASS_CL_ACCESSOR.loadClass(fqcn);
161 }
162
163 if (clazz == null) {
164 if (LOGGER.isTraceEnabled()) {
165 LOGGER.trace("Unable to load class named [" + fqcn + "] from the current ClassLoader. "
166 + "Trying the system/application ClassLoader...");
167 }
168 clazz = SYSTEM_CL_ACCESSOR.loadClass(fqcn);
169 }
170
171 if (clazz == null) {
172
173 clazz = PRIM_CLASSES.get(fqcn);
174 }
175
176 if (clazz == null) {
177 String msg = "Unable to load class named [" + fqcn + "] from the thread context, current, or "
178 + "system/application ClassLoaders. All heuristics have been exhausted. Class could not be found.";
179 throw new UnknownClassException(msg);
180 }
181
182 return (Class<T>) clazz;
183 }
184
185 public static boolean isAvailable(String fullyQualifiedClassName) {
186 try {
187 forName(fullyQualifiedClassName);
188 return true;
189 } catch (UnknownClassException e) {
190 return false;
191 }
192 }
193
194 public static Object newInstance(String fqcn) {
195 return newInstance(forName(fqcn));
196 }
197
198 public static Object newInstance(String fqcn, Object... args) {
199 return newInstance(forName(fqcn), args);
200 }
201
202 public static Object newInstance(Class<?> clazz) {
203 if (clazz == null) {
204 String msg = "Class method parameter cannot be null.";
205 throw new IllegalArgumentException(msg);
206 }
207 try {
208 return clazz.getDeclaredConstructor().newInstance();
209 } catch (Exception e) {
210 throw new InstantiationException("Unable to instantiate class [" + clazz.getName() + "]", e);
211 }
212 }
213
214 public static Object newInstance(Class<?> clazz, Object... args) {
215 var argTypes = new Class<?>[args.length];
216 for (int i = 0; i < args.length; i++) {
217 argTypes[i] = args[i].getClass();
218 }
219 Constructor<?> ctor = getConstructor(clazz, argTypes);
220 return instantiate(ctor, args);
221 }
222
223 public static Constructor<?> getConstructor(Class<?> clazz, Class<?>... argTypes) {
224 try {
225 return clazz.getConstructor(argTypes);
226 } catch (NoSuchMethodException e) {
227 throw new IllegalStateException(e);
228 }
229 }
230
231 public static Object instantiate(Constructor<?> ctor, Object... args) {
232 try {
233 return ctor.newInstance(args);
234 } catch (Exception e) {
235 String msg = "Unable to instantiate Permission instance with constructor [" + ctor + "]";
236 throw new InstantiationException(msg, e);
237 }
238 }
239
240
241
242
243
244
245
246 public static List<Method> getAnnotatedMethods(final Class<?> type, final Class<? extends Annotation> annotation) {
247 final List<Method> methods = new ArrayList<>();
248 Class<?> clazz = type;
249 while (!Object.class.equals(clazz)) {
250 Method[] currentClassMethods = clazz.getDeclaredMethods();
251 for (final Method method : currentClassMethods) {
252 if (annotation == null || method.isAnnotationPresent(annotation)) {
253 methods.add(method);
254 }
255 }
256
257 clazz = clazz.getSuperclass();
258 }
259 return methods;
260 }
261
262
263
264
265 private interface ClassLoaderAccessor {
266 Class<?> loadClass(String fqcn);
267
268 InputStream getResourceStream(String name);
269 }
270
271
272
273
274 private abstract static class ExceptionIgnoringAccessor implements ClassLoaderAccessor {
275
276 public Class<?> loadClass(String fqcn) {
277 Class<?> clazz = null;
278 ClassLoader cl = getClassLoader();
279 if (cl != null) {
280 try {
281
282 clazz = Class.forName(fqcn, false, cl);
283 } catch (ClassNotFoundException e) {
284 if (LOGGER.isTraceEnabled()) {
285 LOGGER.trace("Unable to load clazz named [" + fqcn + "] from class loader [" + cl + "]");
286 }
287 }
288 }
289 return clazz;
290 }
291
292 public InputStream getResourceStream(String name) {
293 InputStream is = null;
294 ClassLoader cl = getClassLoader();
295 if (cl != null) {
296 is = cl.getResourceAsStream(name);
297 }
298 return is;
299 }
300
301 protected final ClassLoader getClassLoader() {
302 try {
303 return doGetClassLoader();
304 } catch (Throwable t) {
305 if (LOGGER.isDebugEnabled()) {
306 LOGGER.debug("Unable to acquire ClassLoader.", t);
307 }
308 }
309 return null;
310 }
311
312 protected abstract ClassLoader doGetClassLoader() throws Throwable;
313 }
314 }