diff --git a/core/src/main/java/org/elasticsearch/bootstrap/JarHell.java b/core/src/main/java/org/elasticsearch/bootstrap/JarHell.java index fecc370f748..dac62415549 100644 --- a/core/src/main/java/org/elasticsearch/bootstrap/JarHell.java +++ b/core/src/main/java/org/elasticsearch/bootstrap/JarHell.java @@ -46,6 +46,11 @@ import java.util.jar.Manifest; /** Simple check for duplicate class files across the classpath */ public class JarHell { + /** Simple driver class, can be used eg. from builds. Returns non-zero on jar-hell */ + public static void main(String args[]) throws Exception { + checkJarHell(); + } + /** * Checks the current classloader for duplicate classes * @throws IllegalStateException if jar hell was found @@ -57,9 +62,9 @@ public class JarHell { } ESLogger logger = Loggers.getLogger(JarHell.class); if (logger.isDebugEnabled()) { - logger.debug("java.class.path= {}" + System.getProperty("java.class.path")); - logger.debug("sun.boot.class.path= {}" + System.getProperty("sun.boot.class.path")); - logger.debug("classloader urls= {}" + Arrays.toString(((URLClassLoader)loader).getURLs())); + logger.debug("java.class.path: {}", System.getProperty("java.class.path")); + logger.debug("sun.boot.class.path: {}", System.getProperty("sun.boot.class.path")); + logger.debug("classloader urls: {}", Arrays.toString(((URLClassLoader)loader).getURLs())); } checkJarHell(((URLClassLoader)loader).getURLs()); } @@ -70,14 +75,27 @@ public class JarHell { */ @SuppressForbidden(reason = "needs JarFile for speed, just reading entries") public static void checkJarHell(URL urls[]) throws Exception { + ESLogger logger = Loggers.getLogger(JarHell.class); + // we don't try to be sneaky and use deprecated/internal/not portable stuff + // like sun.boot.class.path, and with jigsaw we don't yet have a way to get + // a "list" at all. So just exclude any elements underneath the java home + String javaHome = System.getProperty("java.home"); + logger.debug("java.home: {}", javaHome); final Map clazzes = new HashMap<>(32768); Set seenJars = new HashSet<>(); for (final URL url : urls) { String path = URLDecoder.decode(url.getPath(), "UTF-8"); + // exclude system resources + if (path.startsWith(javaHome)) { + logger.debug("excluding system resource: {}", path); + continue; + } if (path.endsWith(".jar")) { if (!seenJars.add(path)) { + logger.debug("excluding duplicate classpath element: {}", path); continue; // we can't fail because of sheistiness with joda-time } + logger.debug("examining jar: {}", path); try (JarFile file = new JarFile(path)) { Manifest manifest = file.getManifest(); if (manifest != null) { @@ -111,6 +129,7 @@ public class JarHell { } } } else { + logger.debug("examining directory: {}", path); // case for tests: where we have class files in the classpath final Path root = PathUtils.get(url.toURI()); final String sep = root.getFileSystem().getSeparator(); diff --git a/core/src/test/java/org/elasticsearch/bootstrap/BootstrapForTesting.java b/core/src/test/java/org/elasticsearch/bootstrap/BootstrapForTesting.java index 1fbb1462ac6..e73805ff995 100644 --- a/core/src/test/java/org/elasticsearch/bootstrap/BootstrapForTesting.java +++ b/core/src/test/java/org/elasticsearch/bootstrap/BootstrapForTesting.java @@ -25,6 +25,7 @@ import org.elasticsearch.bootstrap.ESPolicy; import org.elasticsearch.bootstrap.Security; import org.elasticsearch.common.Strings; import org.elasticsearch.common.io.PathUtils; +import org.elasticsearch.common.logging.Loggers; import java.io.FilePermission; import java.nio.file.Path; @@ -55,7 +56,13 @@ public class BootstrapForTesting { try { JarHell.checkJarHell(); } catch (Exception e) { - throw new RuntimeException("found jar hell in test classpath", e); + if (Boolean.parseBoolean(System.getProperty("tests.maven"))) { + throw new RuntimeException("found jar hell in test classpath", e); + } else { + Loggers.getLogger(BootstrapForTesting.class) + .warn("Your ide or custom test runner has jar hell issues, " + + "you might want to look into that", e); + } } // make sure java.io.tmpdir exists always (in case code uses it in a static initializer)