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