diff options
-rw-r--r-- | src/launch/lombok/launch/ShadowClassLoader.java | 57 |
1 files changed, 42 insertions, 15 deletions
diff --git a/src/launch/lombok/launch/ShadowClassLoader.java b/src/launch/lombok/launch/ShadowClassLoader.java index 99f632a0..79809b2f 100644 --- a/src/launch/lombok/launch/ShadowClassLoader.java +++ b/src/launch/lombok/launch/ShadowClassLoader.java @@ -41,21 +41,39 @@ import java.util.jar.JarFile; /** * The shadow classloader serves to completely hide almost all classes in a given jar file by using a different file ending. * - * Classes loaded by the shadowloader use ".SCL.<em>sclSuffix</em>" instead of ".class". - * - * In addition, the shadowloader will pick up an alternate (priority) classpath, using normal class files, from the system property {@code shadow.classpath}. - * - * This classloader accomplishes a number of things:<ul> - * <li>Avoid contaminating the namespace of any project using lombok. Autocompleters in IDEs will NOT suggest anything other than actual public API. - * <li>Like jarjar, allows folding in dependencies such as ASM without foisting these dependencies on projects that use lombok. shadowloader obviates the need for jarjar. - * <li>Allows an agent (which MUST be in jar form) to still load everything except this loader infrastructure from class files generated by the IDE, which should - * considerably help debugging, as you can now rely on the IDE's built-in auto-recompile features instead of having to run a full build everytime, and it should help - * with hot code replace and the like. - * </ul> - * - * Implementation note: {@code lombok.patcher} <em>relies</em> on this class having no dependencies on any other class except the JVM boot class, notably - * including any other classes in this package, <strong>including</strong> inner classes of this very class. So, don't write closures, anonymous inner class literals, - * enums, or anything else that could cause the compilation of this file to produce more than 1 class file. + * The shadow classloader also serves to link in a project as it is being developed (a 'bin' dir from an IDE for example). + * <p> + * Classes loaded by the shadowloader use ".SCL.<em>sclSuffix</em>" in addition to ".class". In other words, most of the class files in a given jar end in this suffix, which + * serves to hide them from any tool that isn't aware of the suffix (such as IDEs generating auto-complete dialogs, and javac's classpath in general). Only shadowloader can actually + * load these classes. + * <p> + * The shadowloader will pick up an alternate (priority) classpath, using normal class files, from the system property "<code>shadow.override.<em>sclSuffix</em></code>". + * This shadow classpath looks just like a normal java classpath; the path separator is applied (semi-colon on windows, colon elsewhere), and entries can consist of directories, + * jar files, or directories ending in "/*" to pick up all jars inside it. + * <p> + * Load order is as follows if at least one override is present: + * <li>First, if the resource is found in one of the paths stated in the shadow classpath, find that. + * <li>Next, ask the <code>parent</code> loader, which is passed during construction of the ShadowClassLoader. + * <li>Notably, this jar's contents are always skipped! (The idea of the shadow classpath is that this jar only functions as a launcher, not as a source of your actual application). + * </ul> + * + * If no overrides are present, the load order is as follows: + * <li>First, if the resource is found in our own jar (trying ".SCL.<em>sclSuffix</em>" first for any resource request ending in ".class"), return that. + * <li>Next, ask the <code>parent</code> loader. + * </ul> + * + * Use ShadowClassLoader to accomplish the following things:<ul> + * <li>Avoid contaminating the namespace of any project using an SCL-based jar. Autocompleters in IDEs will NOT suggest anything other than actual public API. + * <li>Like jarjar, allows folding in dependencies such as ASM without foisting these dependencies on projects that use this jar. shadowloader obviates the need for jarjar. + * <li>Allows an agent (which MUST be in jar form) to still load everything except this loader infrastructure from class files generated by the IDE, which should + * considerably help debugging, as you can now rely on the IDE's built-in auto-recompile features instead of having to run a full build everytime, and it should help + * with hot code replace and the like (this is what the {@code shadow.override} feature is for). + * </ul> + * + * Implementation note: {@code lombok.eclipse.agent.EclipseLoaderPatcher} <em>relies</em> on this class having no dependencies on any other class except the JVM boot class, notably + * including any other classes in this package, <strong>including</strong> inner classes. So, don't write closures, anonymous inner class literals, + * enums, or anything else that could cause the compilation of this file to produce more than 1 class file. In general, actually passing load control to this loader is a bit tricky + * so ensure that this class has zero dependencies on anything except java core classes. */ class ShadowClassLoader extends ClassLoader { private static final String SELF_NAME = "lombok/launch/ShadowClassLoader.class"; @@ -67,6 +85,9 @@ class ShadowClassLoader extends ClassLoader { private final String sclSuffix; private final List<String> parentExclusion = new ArrayList<String>(); + /** + * Calls the {@link ShadowClassLoader(ClassLoader, String, String, String[]) constructor with no exclusions and the source of this class as base. + */ ShadowClassLoader(ClassLoader source, String sclSuffix) { this(source, sclSuffix, null); } @@ -169,6 +190,9 @@ class ShadowClassLoader extends ClassLoader { } } + /** + * Looks up {@code altName} in {@code location}, and if that isn't found, looks up {@code name}; {@code altName} can be null in which case it is skipped. + */ private URL getResourceFromLocation(String name, String altName, File location) { if (location.isDirectory()) { try { @@ -211,6 +235,9 @@ class ShadowClassLoader extends ClassLoader { return null; } + /** + * Checks if the stated item is located inside the same classpath root as the jar that hosts ShadowClassLoader.class. {@code item} and {@code name} refer to the same thing. + */ private boolean inOwnBase(URL item, String name) { if (item == null) return false; String itemString = item.toString(); |