• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License").
5  * You may not use this file except in compliance with the License.
6  * A copy of the License is located at
7  *
8  *  http://aws.amazon.com/apache2.0
9  *
10  * or in the "license" file accompanying this file. This file is distributed
11  * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
12  * express or implied. See the License for the specific language governing
13  * permissions and limitations under the License.
14  */
15 
16 package software.amazon.awssdk.core.internal.util;
17 
18 import software.amazon.awssdk.annotations.SdkInternalApi;
19 
20 @SdkInternalApi
21 public final class ClassLoaderHelper {
22 
ClassLoaderHelper()23     private ClassLoaderHelper() {
24     }
25 
loadClassViaClasses(String fqcn, Class<?>[] classes)26     private static Class<?> loadClassViaClasses(String fqcn, Class<?>[] classes) {
27         if (classes == null) {
28             return null;
29         }
30 
31         for (Class<?> clzz: classes) {
32             if (clzz == null) {
33                 continue;
34             }
35             ClassLoader loader = clzz.getClassLoader();
36             if (loader != null) {
37                 try {
38                     return loader.loadClass(fqcn);
39                 } catch (ClassNotFoundException e) {
40                     // move on to try the next class loader
41                 }
42             }
43         }
44         return null;
45     }
46 
loadClassViaContext(String fqcn)47     private static Class<?> loadClassViaContext(String fqcn) {
48         ClassLoader loader = contextClassLoader();
49         try {
50             return loader == null ? null : loader.loadClass(fqcn);
51         } catch (ClassNotFoundException e) {
52             // Ignored.
53         }
54         return null;
55     }
56 
57     /**
58      * Loads the class via the optionally specified classes in the order of
59      * their specification, and if not found, via the context class loader of
60      * the current thread, and if not found, from the caller class loader as the
61      * last resort.
62      *
63      * @param fqcn
64      *            fully qualified class name of the target class to be loaded
65      * @param classes
66      *            class loader providers
67      * @return the class loaded; never null
68      *
69      * @throws ClassNotFoundException
70      *             if failed to load the class
71      */
loadClass(String fqcn, Class<?>... classes)72     public static Class<?> loadClass(String fqcn, Class<?>... classes) throws ClassNotFoundException {
73         return loadClass(fqcn, true, classes);
74     }
75 
76     /**
77      * If classesFirst is false, loads the class via the context class
78      * loader of the current thread, and if not found, via the class loaders of
79      * the optionally specified classes in the order of their specification, and
80      * if not found, from the caller class loader as the
81      * last resort.
82      * <p>
83      * If classesFirst is true, loads the class via the optionally
84      * specified classes in the order of their specification, and if not found,
85      * via the context class loader of the current thread, and if not found,
86      * from the caller class loader as the last resort.
87      *
88      * @param fqcn
89      *            fully qualified class name of the target class to be loaded
90      * @param classesFirst
91      *            true if the class loaders of the optionally specified classes
92      *            take precedence over the context class loader of the current
93      *            thread; false if the opposite is true.
94      * @param classes
95      *            class loader providers
96      * @return the class loaded; never null
97      *
98      * @throws ClassNotFoundException if failed to load the class
99      */
loadClass(String fqcn, boolean classesFirst, Class<?>... classes)100     public static Class<?> loadClass(String fqcn, boolean classesFirst,
101                                      Class<?>... classes) throws ClassNotFoundException {
102         Class<?> target = null;
103         if (classesFirst) {
104             target = loadClassViaClasses(fqcn, classes);
105             if (target == null) {
106                 target = loadClassViaContext(fqcn);
107             }
108         } else {
109             target = loadClassViaContext(fqcn);
110             if (target == null) {
111                 target = loadClassViaClasses(fqcn, classes);
112             }
113         }
114         return target == null ? Class.forName(fqcn) : target;
115     }
116 
117     /**
118      * Attempt to get the current thread's class loader and fallback to the system classloader if null
119      * @return a {@link ClassLoader} or null if none found
120      */
contextClassLoader()121     private static ClassLoader contextClassLoader() {
122         ClassLoader threadClassLoader = Thread.currentThread().getContextClassLoader();
123         if (threadClassLoader != null) {
124             return threadClassLoader;
125         }
126         return ClassLoader.getSystemClassLoader();
127     }
128 
129     /**
130      * Attempt to get class loader that loads the classes and fallback to the thread context classloader if null.
131      *
132      * @param classes the classes
133      * @return a {@link ClassLoader} or null if none found
134      */
classLoader(Class<?>.... classes)135     public static ClassLoader classLoader(Class<?>... classes) {
136         if (classes != null) {
137             for (Class clzz : classes) {
138                 ClassLoader classLoader = clzz.getClassLoader();
139 
140                 if (classLoader != null) {
141                     return classLoader;
142                 }
143             }
144         }
145 
146         return contextClassLoader();
147     }
148 
149 }
150