diff --git a/emjar-maven-plugin/README.md b/emjar-maven-plugin/README.md index d8e5334..5e7fe57 100644 --- a/emjar-maven-plugin/README.md +++ b/emjar-maven-plugin/README.md @@ -11,7 +11,11 @@ Maven Plugin Mojo for building bundling jars that contain dependency artifact ja * bundleSuffix - Suffix appended to `finalName` when building output bundle name. Defaults to `-emjar`. + Suffix appended to `finalName` when building output bundle name. + Defaults to `-emjar`. (Due to the way pom files are parsed and + passed to plugins, an empty suffix cannot be directly configured. + Use the value `NONE` to indicate that no suffix should be + appended.) * explicitOrderings diff --git a/emjar-maven-plugin/src/main/java/com/comoyo/maven/plugins/emjar/EmJarMojo.java b/emjar-maven-plugin/src/main/java/com/comoyo/maven/plugins/emjar/EmJarMojo.java index 63f4b3f..43de3d9 100644 --- a/emjar-maven-plugin/src/main/java/com/comoyo/maven/plugins/emjar/EmJarMojo.java +++ b/emjar-maven-plugin/src/main/java/com/comoyo/maven/plugins/emjar/EmJarMojo.java @@ -131,7 +131,7 @@ public class EmJarMojo private String finalName; /** - * Suffix for generated Java Archive file. + * Suffix for generated Java Archive file ("NONE" for none). * * @parameter * property="bundleSuffix" @@ -177,6 +177,7 @@ public class EmJarMojo private static final String CREATED_BY = "Created-By"; private static final int CHUNK_SIZE = 16 * 1024; + private static final String NONE = "NONE"; private final Map>> conflicts = new HashMap<>(); private final Map> seen = new HashMap<>(); @@ -482,7 +483,8 @@ public void execute() throws MojoExecutionException { try { - final File outFile = new File(outputDirectory, finalName + bundleSuffix + ".jar"); + final String suffix = NONE.equals(bundleSuffix) ? "" : bundleSuffix; + final File outFile = new File(outputDirectory, finalName + suffix + ".jar"); getLog().info("Building jar: " + outFile.getPath()); if (ignoreConflicts && conflictsFatal) { throw new MojoExecutionException( diff --git a/emjar/pom.xml b/emjar/pom.xml index e6267c1..4184f89 100644 --- a/emjar/pom.xml +++ b/emjar/pom.xml @@ -53,5 +53,11 @@ ${google.guava.version} test + + org.apache.httpcomponents + httpclient + 4.4 + test + diff --git a/emjar/src/main/java/com/comoyo/emjar/EmJarClassLoader.java b/emjar/src/main/java/com/comoyo/emjar/EmJarClassLoader.java index b39f5fc..1453ac0 100644 --- a/emjar/src/main/java/com/comoyo/emjar/EmJarClassLoader.java +++ b/emjar/src/main/java/com/comoyo/emjar/EmJarClassLoader.java @@ -27,6 +27,7 @@ import java.net.URLStreamHandlerFactory; import java.util.ArrayList; import java.util.Enumeration; +import java.util.List; import java.util.Map; import java.util.Properties; import java.util.concurrent.ConcurrentHashMap; @@ -72,15 +73,14 @@ public class EmJarClassLoader { public final static String EMJAR_LOG_QUIET_PROP = "emjar.log.quiet"; public final static String EMJAR_LOG_DEBUG_PROP = "emjar.log.debug"; + public final static String EMJAR_CLASS_PATH_PROP = "emjar.class.path"; + public final static String JAVA_CLASS_PATH_PROP = "java.class.path"; protected static boolean DEBUG = false; protected static boolean QUIET = false; public final static String SEPARATOR = "!/"; - private final static HandlerFactory factory = new HandlerFactory(); - private final static Handler handler = new Handler(); - static { try { ClassLoader.registerAsParallelCapable(); @@ -89,28 +89,45 @@ public class EmJarClassLoader } } + private EmJarClassLoader( + final Handler handler, final Properties props, final ClassLoader parent) { + super(getClassPath(props, handler), parent, new HandlerFactory(handler)); + } + public EmJarClassLoader() { - super(getClassPath(System.getProperties()), null, factory); + this(new Handler(), System.getProperties(), null); } - public EmJarClassLoader(ClassLoader parent) + public EmJarClassLoader(final ClassLoader parent) { - super(getClassPath(System.getProperties()), parent, factory); + this(new Handler(), System.getProperties(), parent); } - protected EmJarClassLoader(Properties props) + protected EmJarClassLoader(final Properties props) { - super(getClassPath(props), null, factory); + this(new Handler(), props, null); } - private static URL[] getClassPath(final Properties props) + private static URL[] getClassPath(final Properties props, final Handler handler) { - final String classPath = props.getProperty("java.class.path"); QUIET = "true".equalsIgnoreCase(props.getProperty(EMJAR_LOG_QUIET_PROP, "")); DEBUG = "true".equalsIgnoreCase(props.getProperty(EMJAR_LOG_DEBUG_PROP, "")); final ArrayList urls = new ArrayList<>(); + addClassPathUrls(props.getProperty(JAVA_CLASS_PATH_PROP), urls, handler); + addClassPathUrls(props.getProperty(EMJAR_CLASS_PATH_PROP), urls, handler); + if (DEBUG) { + System.err.println("EmJar: using classpath " + urls); + } + return urls.toArray(new URL[0]); + } + + private static void addClassPathUrls( + final String classPath, final List urls, final Handler handler) { + if (classPath == null) { + return; + } for (String elem : classPath.split(File.pathSeparator)) { final File file = new File(elem); try { @@ -142,10 +159,6 @@ private static URL[] getClassPath(final Properties props) // Trying to get by on the classpath entries we can process. } } - if (DEBUG) { - System.err.println("EmJar: using classpath " + urls); - } - return urls.toArray(new URL[0]); } private static URL uriToUrl(URI uri, Handler handler) @@ -160,16 +173,15 @@ private static URL uriToUrl(URI uri, Handler handler) handler); } - @Override - public Class loadClass(String name) - throws ClassNotFoundException - { - return super.loadClass(name); - } - private static class HandlerFactory implements URLStreamHandlerFactory { + private final Handler handler; + + public HandlerFactory(final Handler handler) { + this.handler = handler; + } + @Override public URLStreamHandler createURLStreamHandler(String protocol) { @@ -244,6 +256,11 @@ protected URLConnection openConnection(URL url) final String root = path.substring(0, i); final String nested = path.substring(i + SEPARATOR.length(), j); final String entry = path.substring(j + SEPARATOR.length()); + if (!nested.endsWith(".jar")) { + final URL urlDefaultHandler + = new URL(url.getProtocol(), url.getHost(), url.getPort(), url.getFile()); + return urlDefaultHandler.openConnection(); + } Map> rootJar = rootJars.get(root); @@ -260,13 +277,14 @@ protected URLConnection openConnection(URL url) } final Map descriptors = rootJar.get(nested); + final URL rootUrl = new URL("jar:file:" + root + SEPARATOR); if (descriptors != null) { conn = new OndemandEmbeddedJar.Connection( - bundle.toURL(), root, descriptors, entry); + rootUrl, root, descriptors, entry); } else { conn = new PreloadedEmbeddedJar.Connection( - bundle.toURL(), root, nested, entry); + rootUrl, root, nested, entry); } connections.put(path, conn); } diff --git a/emjar/src/test/java/com/comoyo/emjar/EmJarClassLoaderTest.java b/emjar/src/test/java/com/comoyo/emjar/EmJarClassLoaderTest.java index 06058da..54b07ed 100644 --- a/emjar/src/test/java/com/comoyo/emjar/EmJarClassLoaderTest.java +++ b/emjar/src/test/java/com/comoyo/emjar/EmJarClassLoaderTest.java @@ -19,13 +19,17 @@ import java.io.BufferedReader; import java.io.File; import java.io.FilenameFilter; +import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.net.JarURLConnection; import java.net.URISyntaxException; import java.net.URL; +import java.net.URLClassLoader; import java.net.URLConnection; +import java.util.Enumeration; import java.util.Properties; +import java.util.jar.JarEntry; import java.util.jar.JarFile; import java.util.jar.Manifest; @@ -57,12 +61,49 @@ public boolean accept(File dir, String name) { return new EmJarClassLoader(props); } + /** + * In order to construct a URL, getResourceAsStream ultimately + * calls sun.net.www.ParseUtil.encodePath(). This encodes the + * name's char array to UTF-8 under the assumption that it is + * UCS-2, not UTF-16. Doing so causes bad encodings of non-BMP + * entities. Java 7 was able to process these wrongly encoded + * strings and reconstruct the original char sequence, but Java 8 + * is not. Thus the following, which more or less replicates the + * functionality of getResourceAsStream in order to verify that at + * least EmJar's handling of unicode is up to snuff. + */ + private static InputStream getResourceAsStreamRobust( + final URLClassLoader loader, final String searchName) + throws IOException { + for (final URL url : loader.getURLs()) { + if (!"jar".equals(url.getProtocol())) { + continue; + } + final URLConnection conn = url.openConnection(); + if (!(conn instanceof JarURLConnection)) { + continue; + } + final JarURLConnection jarConn = (JarURLConnection) conn; + final JarFile jarFile = jarConn.getJarFile(); + final Enumeration it = jarFile.entries(); + while (it.hasMoreElements()) { + final JarEntry je = it.nextElement(); + if (searchName.equals(je.getName())) { + return jarFile.getInputStream(je); + } + } + } + return null; + } + @Test public void testClassPathQuoting() throws Exception { final EmJarClassLoader loader = testLoader(); - final InputStream is = loader.getResourceAsStream("entry-" + WEIRD + ".txt"); + final String searchName = "entry-" + WEIRD + ".txt"; + final InputStream is = getResourceAsStreamRobust(loader, searchName); + assertNotNull("Did not find " + searchName + " in classpath", is); final BufferedReader entry = new BufferedReader(new InputStreamReader(is)); assertEquals("Contents mismatch for weird entry", WEIRD, entry.readLine()); } diff --git a/emjar/src/test/java/com/comoyo/emjar/EmJarTest.java b/emjar/src/test/java/com/comoyo/emjar/EmJarTest.java index afe9fca..876fe83 100644 --- a/emjar/src/test/java/com/comoyo/emjar/EmJarTest.java +++ b/emjar/src/test/java/com/comoyo/emjar/EmJarTest.java @@ -19,6 +19,7 @@ import java.io.File; import java.net.URI; import java.net.URISyntaxException; +import org.apache.http.client.utils.URIBuilder; public abstract class EmJarTest { @@ -28,7 +29,10 @@ protected File getResourceFile(String name) throws URISyntaxException { final ClassLoader cl = getClass().getClassLoader(); - final URI uri = cl.getResource("com/comoyo/emjar/" + name).toURI(); + final URI base = cl.getResource("com/comoyo/emjar/").toURI(); + URIBuilder builder = new URIBuilder(base); + builder.setPath(builder.getPath() + name); + final URI uri = builder.build(); if (!"file".equals(uri.getScheme())) { throw new IllegalArgumentException( "Resource " + name + " not present as file (" + uri + ")"); diff --git a/pom.xml b/pom.xml index baa6676..0f9dd52 100644 --- a/pom.xml +++ b/pom.xml @@ -138,7 +138,7 @@ org.apache.maven.plugins maven-source-plugin - 2.2.1 + 2.4 attach-sources