aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/launch/lombok/launch/ShadowClassLoader.java57
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();