mirror of
https://github.com/tiennm99/lombok.git
synced 2026-10-14 04:16:19 +00:00
Merge branch 'sclExpansionUpdate'
This commit is contained in:
commit
657a13b0dd
1 file changed
+126
-19
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2014-2015 The Project Lombok Authors.
|
||||
* Copyright (C) 2014-2018 The Project Lombok Authors.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
@@ -21,9 +21,13 @@
|
||||
*/
|
||||
package lombok.launch;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URI;
|
||||
@@ -36,14 +40,16 @@ import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.Set;
|
||||
import java.util.Vector;
|
||||
import java.util.WeakHashMap;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.ConcurrentMap;
|
||||
import java.util.jar.JarEntry;
|
||||
import java.util.jar.JarFile;
|
||||
import java.util.zip.ZipEntry;
|
||||
import java.util.zip.ZipInputStream;
|
||||
|
||||
/**
|
||||
* The shadow classloader serves to completely hide almost all classes in a given jar file by using a different file ending.
|
||||
@@ -66,6 +72,7 @@ import java.util.jar.JarFile;
|
||||
*
|
||||
* 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, check any jar files other than our own, loading them via this classloader, if they have a file <code>META-INF/ShadowClassLoader</code> that contains a line of text with <em>sclSuffix</em>.
|
||||
* <li>Next, ask the <code>parent</code> loader.
|
||||
* </ul>
|
||||
*
|
||||
@@ -110,9 +117,7 @@ class ShadowClassLoader extends ClassLoader {
|
||||
if (!pe.endsWith("/")) pe = pe + "/";
|
||||
this.parentExclusion.add(pe);
|
||||
}
|
||||
if (highlanders != null) for (String hl : highlanders) {
|
||||
this.highlanders.add(hl);
|
||||
}
|
||||
if (highlanders != null) for (String hl : highlanders) this.highlanders.add(hl);
|
||||
|
||||
if (selfBase != null) {
|
||||
SELF_BASE = selfBase;
|
||||
@@ -125,12 +130,7 @@ class ShadowClassLoader extends ClassLoader {
|
||||
throw new RuntimeException("ShadowLoader can't find itself. SCL loader type: " + (cl == null ? "*NULL*" : cl.getClass().toString()));
|
||||
}
|
||||
SELF_BASE_LENGTH = sclClassStr.length() - SELF_NAME.length();
|
||||
String decoded;
|
||||
try {
|
||||
decoded = URLDecoder.decode(sclClassStr.substring(0, SELF_BASE_LENGTH), "UTF-8");
|
||||
} catch (UnsupportedEncodingException e) {
|
||||
throw new InternalError("UTF-8 not available");
|
||||
}
|
||||
String decoded = urlDecode(sclClassStr.substring(0, SELF_BASE_LENGTH));
|
||||
SELF_BASE = decoded;
|
||||
}
|
||||
|
||||
@@ -148,11 +148,11 @@ class ShadowClassLoader extends ClassLoader {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private final Map<String, Object> mapJarPathToTracker = new HashMap<String, Object>();
|
||||
private static final Map<Object, String> mapTrackerToJarPath = new WeakHashMap<Object, String>();
|
||||
private static final Map<Object, Set<String>> mapTrackerToJarContents = new WeakHashMap<Object, Set<String>>();
|
||||
|
||||
|
||||
/**
|
||||
* This cache ensures that any given jar file is only opened once in order to determine the full contents of it.
|
||||
* We use 'trackers' to make sure that the bulk of the memory taken up by this cache (the list of strings representing the content of a jar file)
|
||||
@@ -296,6 +296,10 @@ class ShadowClassLoader extends ClassLoader {
|
||||
return null;
|
||||
}
|
||||
|
||||
private boolean partOfShadow(URL item, String name) {
|
||||
return inOwnBase(item, name) || isPartOfShadowSuffix(item, name, sclSuffix);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
@@ -305,6 +309,109 @@ class ShadowClassLoader extends ClassLoader {
|
||||
return (itemString.length() == SELF_BASE_LENGTH + name.length()) && SELF_BASE.regionMatches(0, itemString, 0, SELF_BASE_LENGTH);
|
||||
}
|
||||
|
||||
private static boolean sclFileContainsSuffix(InputStream in, String suffix) throws IOException {
|
||||
BufferedReader br = new BufferedReader(new InputStreamReader(in, "UTF-8"));
|
||||
for (String line = br.readLine(); line != null; line = br.readLine()) {
|
||||
line = line.trim();
|
||||
if (line.isEmpty() || line.charAt(0) == '#') continue;
|
||||
if (line.equals(suffix)) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private static String urlDecode(String in) {
|
||||
try {
|
||||
return URLDecoder.decode(in, "UTF-8");
|
||||
} catch (UnsupportedEncodingException e) {
|
||||
throw new InternalError("UTF-8 not supported");
|
||||
}
|
||||
}
|
||||
|
||||
private Map<String, Boolean> fileRootCache = new HashMap<String, Boolean>();
|
||||
private boolean isPartOfShadowSuffixFileBased(String fileRoot, String suffix) {
|
||||
String key = fileRoot + "::" + suffix;
|
||||
Boolean existing = fileRootCache.get(key);
|
||||
if (existing != null) return existing.booleanValue();
|
||||
|
||||
File f = new File(fileRoot + "/META-INF/ShadowClassLoader");
|
||||
try {
|
||||
FileInputStream fis = new FileInputStream(f);
|
||||
try {
|
||||
boolean v = sclFileContainsSuffix(fis, suffix);
|
||||
fileRootCache.put(key, v);
|
||||
return v;
|
||||
} finally {
|
||||
fis.close();
|
||||
}
|
||||
} catch (FileNotFoundException fnfEx) {
|
||||
fileRootCache.put(key, false);
|
||||
return false;
|
||||
} catch (IOException e) {
|
||||
fileRootCache.put(key, false);
|
||||
return false; // *unexpected*
|
||||
}
|
||||
}
|
||||
|
||||
private Map<String, Boolean> jarLocCache = new HashMap<String, Boolean>();
|
||||
private boolean isPartOfShadowSuffixJarBased(String jarLoc, String suffix) {
|
||||
String key = jarLoc + "::" + suffix;
|
||||
Boolean existing = jarLocCache.get(key);
|
||||
if (existing != null) return existing.booleanValue();
|
||||
|
||||
if (jarLoc.startsWith("file:/")) jarLoc = urlDecode(jarLoc.substring(5));
|
||||
try {
|
||||
FileInputStream jar = new FileInputStream(jarLoc);
|
||||
try {
|
||||
ZipInputStream zip = new ZipInputStream(jar);
|
||||
while (true) {
|
||||
ZipEntry entry = zip.getNextEntry();
|
||||
if (entry == null) {
|
||||
jarLocCache.put(key, false);
|
||||
return false;
|
||||
}
|
||||
if (!"META-INF/ShadowClassLoader".equals(entry.getName())) continue;
|
||||
boolean v = sclFileContainsSuffix(zip, suffix);
|
||||
jarLocCache.put(key, v);
|
||||
return v;
|
||||
}
|
||||
} finally {
|
||||
jar.close();
|
||||
}
|
||||
} catch (FileNotFoundException fnfEx) {
|
||||
jarLocCache.put(key, false);
|
||||
return false;
|
||||
} catch (IOException ex) {
|
||||
jarLocCache.put(key, false);
|
||||
return false; // *unexpected*
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isPartOfShadowSuffix(URL item, String name, String suffix) {
|
||||
// Instead of throwing an exception or logging, weird, unexpected cases just return false.
|
||||
// This is better than throwing an exception, because exceptions would make your build tools unusable.
|
||||
// Such cases are marked with the comment: // *unexpected*
|
||||
if (item == null) return false;
|
||||
String url = item.toString();
|
||||
if (url.startsWith("file:/")) {
|
||||
url = urlDecode(url.substring(5));
|
||||
if (url.length() <= name.length() || !url.endsWith(name) || url.charAt(url.length() - name.length() - 1) != '/') {
|
||||
return false; // *unexpected*
|
||||
}
|
||||
|
||||
String fileRoot = url.substring(0, url.length() - name.length() - 1);
|
||||
return isPartOfShadowSuffixFileBased(fileRoot, suffix);
|
||||
} else if (url.startsWith("jar:")) {
|
||||
int sep = url.indexOf('!');
|
||||
if (sep == -1) {
|
||||
return false; // *unexpected*
|
||||
}
|
||||
String jarLoc = url.substring(4, sep);
|
||||
return isPartOfShadowSuffixJarBased(jarLoc, suffix);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override public Enumeration<URL> getResources(String name) throws IOException {
|
||||
String altName = null;
|
||||
if (name.endsWith(".class")) altName = name.substring(0, name.length() - 6) + ".SCL." + sclSuffix;
|
||||
@@ -329,14 +436,14 @@ class ShadowClassLoader extends ClassLoader {
|
||||
Enumeration<URL> sec = super.getResources(name);
|
||||
while (sec.hasMoreElements()) {
|
||||
URL item = sec.nextElement();
|
||||
if (!inOwnBase(item, name)) vector.add(item);
|
||||
if (!partOfShadow(item, name)) vector.add(item);
|
||||
}
|
||||
|
||||
if (altName != null) {
|
||||
Enumeration<URL> tern = super.getResources(altName);
|
||||
while (tern.hasMoreElements()) {
|
||||
URL item = tern.nextElement();
|
||||
if (!inOwnBase(item, altName)) vector.add(item);
|
||||
if (!partOfShadow(item, altName)) vector.add(item);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -376,11 +483,11 @@ class ShadowClassLoader extends ClassLoader {
|
||||
|
||||
if (altName != null) {
|
||||
URL res = super.getResource(altName);
|
||||
if (res != null && (!noSuper || inOwnBase(res, altName))) return res;
|
||||
if (res != null && (!noSuper || partOfShadow(res, altName))) return res;
|
||||
}
|
||||
|
||||
URL res = super.getResource(name);
|
||||
if (res != null && (!noSuper || inOwnBase(res, name))) return res;
|
||||
if (res != null && (!noSuper || partOfShadow(res, name))) return res;
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -394,12 +501,12 @@ class ShadowClassLoader extends ClassLoader {
|
||||
private URL getResourceSkippingSelf(String name) throws IOException {
|
||||
URL candidate = super.getResource(name);
|
||||
if (candidate == null) return null;
|
||||
if (!inOwnBase(candidate, name)) return candidate;
|
||||
if (!partOfShadow(candidate, name)) return candidate;
|
||||
|
||||
Enumeration<URL> en = super.getResources(name);
|
||||
while (en.hasMoreElements()) {
|
||||
candidate = en.nextElement();
|
||||
if (!inOwnBase(candidate, name)) return candidate;
|
||||
if (!partOfShadow(candidate, name)) return candidate;
|
||||
}
|
||||
|
||||
return null;
|
||||
|
||||
Reference in new issue
Block a user