From 04aa29e3ba374d1d94d1289b2d8b632236ae8833 Mon Sep 17 00:00:00 2001 From: Plamen Totev Date: Sun, 30 Sep 2018 19:12:28 +0300 Subject: [PATCH] Modify ModularJarArchiver to use the manifest main class as default If the main class for a module is not explicitly set, lets use the one specified in the manifest file. That would simplify the creation of modular JAR files - clients should just set the manifest main class as in non-modular JAR file and everything will work out of the box. Also it will allow `ModularJarArchiver` to be used as drop-in replacement of `JarArchiver` without any additional configuration. --- .../jar/JarToolModularJarArchiver.java | 8 ++- .../archiver/jar/ModularJarArchiver.java | 46 ++++++++++++ .../jar/JarToolModularJarArchiverTest.java | 71 ++++++++++++++++++- 3 files changed, 121 insertions(+), 4 deletions(-) diff --git a/src/main/java/org/codehaus/plexus/archiver/jar/JarToolModularJarArchiver.java b/src/main/java/org/codehaus/plexus/archiver/jar/JarToolModularJarArchiver.java index dabc39364..1e6fc7b17 100644 --- a/src/main/java/org/codehaus/plexus/archiver/jar/JarToolModularJarArchiver.java +++ b/src/main/java/org/codehaus/plexus/archiver/jar/JarToolModularJarArchiver.java @@ -180,10 +180,14 @@ private String[] getJarToolArguments() args.add( "--file" ); args.add( getDestFile().getAbsolutePath() ); - if ( getModuleMainClass() != null ) + String mainClass = getModuleMainClass() != null + ? getModuleMainClass() + : getManifestMainClass(); + + if ( mainClass != null ) { args.add( "--main-class" ); - args.add( getModuleMainClass() ); + args.add( mainClass ); } if ( getModuleVersion() != null ) diff --git a/src/main/java/org/codehaus/plexus/archiver/jar/ModularJarArchiver.java b/src/main/java/org/codehaus/plexus/archiver/jar/ModularJarArchiver.java index bf636e110..89cd6c963 100644 --- a/src/main/java/org/codehaus/plexus/archiver/jar/ModularJarArchiver.java +++ b/src/main/java/org/codehaus/plexus/archiver/jar/ModularJarArchiver.java @@ -27,6 +27,13 @@ * they are going to add are part of module * (contain module descriptor class) or not. * + *

The class allows you to set the + * module main class ({@link #setModuleMainClass(String)}), + * but if it is not set or it is set to {@code null}, + * then the {@code Main-Class} attribute of the + * JAR manifest is used (if present) to set + * the module main class. + * * @since 3.6 */ public abstract class ModularJarArchiver @@ -34,6 +41,8 @@ public abstract class ModularJarArchiver { private String moduleMainClass; + private String manifestMainClass; + private String moduleVersion; public String getModuleMainClass() @@ -73,4 +82,41 @@ public void setModuleVersion( String moduleVersion ) this.moduleVersion = moduleVersion; } + /** + * Returns the "Main-Class" attribute of the + * manifest added to the archive. + * + * {@code null} if there is no manifest + * or the attribute is not set. + * + * @return the "Main-Class" attribute of the manifest + */ + protected String getManifestMainClass() + { + return manifestMainClass; + } + + @Override + protected Manifest createManifest() + { + Manifest manifest = super.createManifest(); + + if ( manifest != null ) + { + manifestMainClass = manifest.getMainAttributes() + .getValue( "Main-Class" ); + } + + return manifest; + } + + @Override + public void reset() + { + // We want to be sure that on multiple run + // the latest manifest is used, so lets + // reset it to null + manifestMainClass = null; + super.reset(); + } } diff --git a/src/test/java/org/codehaus/plexus/archiver/jar/JarToolModularJarArchiverTest.java b/src/test/java/org/codehaus/plexus/archiver/jar/JarToolModularJarArchiverTest.java index e7b35b93d..931e8dece 100644 --- a/src/test/java/org/codehaus/plexus/archiver/jar/JarToolModularJarArchiverTest.java +++ b/src/test/java/org/codehaus/plexus/archiver/jar/JarToolModularJarArchiverTest.java @@ -30,8 +30,7 @@ import org.junit.Before; import org.junit.Test; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.*; import static org.junit.Assume.assumeFalse; import static org.junit.Assume.assumeTrue; @@ -76,6 +75,57 @@ public void testModularJarWithMainClassAndVersion() "1.0.0", "com.example.app.Main", "com.example.app", "com.example.resources" ); } + /* + * Verify that when both module main class is set and the + * manifest contains main class atribute, the manifest + * value is overridden + */ + @Test + public void testModularJarWithManifestAndModuleMainClass() + throws Exception + { + assumeTrue( modulesAreSupported() ); + + archiver.addDirectory( new File( "src/test/resources/java-module-descriptor" ) ); + Manifest manifest = new Manifest(); + manifest.addConfiguredAttribute( + new Manifest.Attribute( "Main-Class", "com.example.app.Main2" ) ); + archiver.addConfiguredManifest( manifest ); + archiver.setModuleMainClass( "com.example.app.Main" ); + + archiver.createArchive(); + + // Verify that the explicitly set module main class + // overrides the manifest main + assertModularJarFile( archiver.getDestFile(), + null, "com.example.app.Main", "com.example.app", "com.example.resources" ); + assertManifestMainClass( archiver.getDestFile(), "com.example.app.Main" ); + } + + /** + * Verify that when the module main class is not explicitly set, + * the manifest main class attribute (if present) is used instead + */ + @Test + public void testModularJarWithManifestMainClassAttribute() + throws Exception + { + assumeTrue( modulesAreSupported() ); + + archiver.addDirectory( new File( "src/test/resources/java-module-descriptor" ) ); + Manifest manifest = new Manifest(); + manifest.addConfiguredAttribute( + new Manifest.Attribute( "Main-Class", "com.example.app.Main2" ) ); + archiver.addConfiguredManifest( manifest ); + + archiver.createArchive(); + + // Verify that the the manifest main class attribute is used as module main class + assertModularJarFile( archiver.getDestFile(), + null, "com.example.app.Main2", "com.example.app", "com.example.resources" ); + assertManifestMainClass( archiver.getDestFile(), "com.example.app.Main2" ); + } + /* * Verify that a modular JAR file is created even when no additional attributes are set. */ @@ -288,6 +338,23 @@ private void assertModuleDescriptor( InputStream moduleDescriptorInputStream, assertEquals( expectedPackagesSet, actualPackagesSet ); } + private void assertManifestMainClass( File jarFile, String expectedMainClass ) + throws Exception + { + try ( ZipFile resultingArchive = new ZipFile( jarFile ) ) + { + ZipEntry manifestEntry = resultingArchive.getEntry( "META-INF/MANIFEST.MF" ); + InputStream manifestInputStream = resultingArchive.getInputStream( manifestEntry ); + + // Get the manifest main class attribute + Manifest manifest = new Manifest( manifestInputStream ); + String actualManifestMainClass = manifest.getMainAttributes().getValue( "Main-Class" ); + + assertEquals( expectedMainClass, actualManifestMainClass ); + } + + } + /* * Returns true if the current version of Java does support modules. */