From dd8b5f45ddc0d1693ab7132c14f02e2d2d09c850 Mon Sep 17 00:00:00 2001 From: Tomas Zezula Date: Thu, 3 Mar 2016 12:56:40 +0100 Subject: [PATCH 1/3] Added module, modulepath attributes and modulepath, moduleupgradepath elements into Java task. --- src/etc/testcases/taskdefs/java.xml | 23 ++ .../org/apache/tools/ant/taskdefs/Java.java | 57 ++++- .../tools/ant/types/CommandlineJava.java | 228 +++++++++++++++++- .../apache/tools/ant/taskdefs/JavaTest.java | 88 ++++++- 4 files changed, 381 insertions(+), 15 deletions(-) diff --git a/src/etc/testcases/taskdefs/java.xml b/src/etc/testcases/taskdefs/java.xml index a0c0450b6..a3d377891 100644 --- a/src/etc/testcases/taskdefs/java.xml +++ b/src/etc/testcases/taskdefs/java.xml @@ -44,6 +44,9 @@ + + @@ -61,6 +64,26 @@ + + + + + + + + + + + + + + + + + + + + null if there is no module. + * @see #getJar() + * @see #getClassname() + * @since ??? + */ + public String getModule() { + if(executableType == ExecutableType.MODULE) { + return parseModuleFromModuleClassPair(javaCommand.getExecutable()); } return null; } @@ -382,6 +438,32 @@ public class CommandlineJava implements Cloneable { return bootclasspath; } + /** + * Create a modulepath. + * @param p the project to use to create the path. + * @return a path to be configured. + * @since ??? + */ + public Path createModulepath(Project p) { + if (modulepath == null) { + modulepath = new Path(p); + } + return modulepath; + } + + /** + * Create an upgrademodulepath. + * @param p the project to use to create the path. + * @return a path to be configured. + * @since ??? + */ + public Path createUpgrademodulepath(Project p) { + if (upgrademodulepath == null) { + upgrademodulepath = new Path(p); + } + return upgrademodulepath; + } + /** * Get the vm version. * @return the vm version. @@ -435,6 +517,18 @@ public class CommandlineJava implements Cloneable { listIterator.add( classpath.concatSystemClasspath("ignore").toString()); } + //module path + if (haveModulepath()) { + listIterator.add("-modulepath"); + listIterator.add( + modulepath.concatSystemClasspath("ignore").toString()); + } + //upgrade module path + if (haveUpgrademodulepath()) { + listIterator.add("-upgrademodulepath"); + listIterator.add( + upgrademodulepath.concatSystemClasspath("ignore").toString()); + } //now any assertions are added if (getAssertions() != null) { getAssertions().applyAssertions(listIterator); @@ -443,8 +537,10 @@ public class CommandlineJava implements Cloneable { // a bug in JDK < 1.4 that forces the jvm type to be specified as the first // option, it is appended here as specified in the docs even though there is // in fact no order. - if (executeJar) { + if (executableType == ExecutableType.JAR) { listIterator.add("-jar"); + } else if (executableType == ExecutableType.MODULE) { + listIterator.add("-m"); } // this is the classname to run as well as its arguments. // in case of 'executeJar', the executable is a jar file. @@ -531,7 +627,7 @@ public class CommandlineJava implements Cloneable { size++; } // jar execution requires an additional -jar option - if (executeJar) { + if (executableType == ExecutableType.JAR || executableType == ExecutableType.MODULE) { size++; } //assertions take up space too @@ -573,6 +669,24 @@ public class CommandlineJava implements Cloneable { return bootclasspath; } + /** + * Get the modulepath. + * @return modulepath or null. + * @since ??? + */ + public Path getModulepath() { + return modulepath; + } + + /** + * Get the upgrademodulepath. + * @return upgrademodulepath or null. + * @since ??? + */ + public Path getUpgrademodulepath() { + return upgrademodulepath; + } + /** * Cache current system properties and set them to those in this * Java command. @@ -617,6 +731,12 @@ public class CommandlineJava implements Cloneable { if (bootclasspath != null) { c.bootclasspath = (Path) bootclasspath.clone(); } + if (modulepath != null) { + c.modulepath = (Path) modulepath.clone(); + } + if (upgrademodulepath != null) { + c.upgrademodulepath = (Path) upgrademodulepath.clone(); + } if (assertions != null) { c.assertions = (Assertions) assertions.clone(); } @@ -660,6 +780,30 @@ public class CommandlineJava implements Cloneable { return calculateBootclasspath(log).size() > 0; } + /** + * Determine whether the modulepath has been specified. + * @return true if the modulepath is to be used. + * @since ??? + */ + public boolean haveModulepath() { + Path fullClasspath = modulepath != null + ? modulepath.concatSystemClasspath("ignore") : null; + return fullClasspath != null + && fullClasspath.toString().trim().length() > 0; + } + + /** + * Determine whether the upgrademodulepath has been specified. + * @return true if the upgrademodulepath is to be used. + * @since ??? + */ + public boolean haveUpgrademodulepath() { + Path fullClasspath = upgrademodulepath != null + ? upgrademodulepath.concatSystemClasspath("ignore") : null; + return fullClasspath != null + && fullClasspath.toString().trim().length() > 0; + } + /** * Calculate the bootclasspath based on the bootclasspath * specified, the build.sysclasspath and ant.build.clonevm magic @@ -696,4 +840,66 @@ public class CommandlineJava implements Cloneable { return cloneVm || "true".equals(System.getProperty("ant.build.clonevm")); } + + /** + * Creates JDK 9 main module command line argument. + * @param module the module name. + * @param classname the classname or null. + * @return the main module with optional classname command line argument. + * @since ??? + */ + private static String createModuleClassPair(final String module, final String classname) { + return classname == null ? + module : + String.format("%s/%s", module, classname); //NOI18N + } + + /** + * Parses a module name from JDK 9 main module command line argument. + * @param moduleClassPair a module with optional classname or null. + * @return the module name or null. + * @since ??? + */ + private static String parseModuleFromModuleClassPair(final String moduleClassPair) { + if (moduleClassPair == null) { + return null; + } + final String[] moduleAndClass = moduleClassPair.split("/"); //NOI18N + return moduleAndClass[0]; + } + + /** + * Parses a classname from JDK 9 main module command line argument. + * @param moduleClassPair a module with optional classname or null. + * @return the classname or null. + * @since ??? + */ + private static String parseClassFromModuleClassPair(final String moduleClassPair) { + if (moduleClassPair == null) { + return null; + } + final String[] moduleAndClass = moduleClassPair.split("/"); //NOI18N + return moduleAndClass.length == 2 ? + moduleAndClass[1] : + null; + } + + /** + * Type of execution. + * @since ??? + */ + private enum ExecutableType { + /** + * Main class execution. + */ + CLASS, + /** + * Jar file execution. + */ + JAR, + /** + * Module execution. + */ + MODULE + } } diff --git a/src/tests/junit/org/apache/tools/ant/taskdefs/JavaTest.java b/src/tests/junit/org/apache/tools/ant/taskdefs/JavaTest.java index d54b8f28e..8d9957180 100644 --- a/src/tests/junit/org/apache/tools/ant/taskdefs/JavaTest.java +++ b/src/tests/junit/org/apache/tools/ant/taskdefs/JavaTest.java @@ -41,6 +41,8 @@ import org.junit.Test; import org.junit.internal.AssumptionViolatedException; import static org.apache.tools.ant.AntAssert.assertContains; +import org.apache.tools.ant.types.Path; +import org.junit.Assert; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; @@ -118,10 +120,94 @@ public class JavaTest { buildRule.executeTarget("testClassnameAndJar"); fail("Build exception should have been thrown - both classname and JAR are not allowed"); } catch (BuildException ex) { - assertEquals("Cannot use 'jar' and 'classname' attributes in same command.", ex.getMessage()); + assertEquals("Cannot use 'jar' with 'classname' or 'module' attributes in same command.", ex.getMessage()); } } + @Test + public void testJarAndModule() { + try { + buildRule.executeTarget("testJarAndModule"); + fail("Build exception should have been thrown - both module and JAR are not allowed"); + } catch (BuildException ex) { + assertEquals("Cannot use 'jar' and 'module' attributes in same command", ex.getMessage()); + } + } + + @Test + public void testModuleAndJar() { + try { + buildRule.executeTarget("testModuleAndJar"); + fail("Build exception should have been thrown - both module and JAR are not allowed"); + } catch (BuildException ex) { + assertEquals("Cannot use 'jar' with 'classname' or 'module' attributes in same command.", ex.getMessage()); + } + } + + @Test + public void testClassnameAndModule() { + buildRule.executeTarget("testClassnameAndModule"); + } + + @Test + public void testModuleAndClassname() { + buildRule.executeTarget("testModuleAndClassname"); + } + + @Test + public void testModule() { + buildRule.executeTarget("testModule"); + } + + @Test + public void testModuleCommandLine() { + final String moduleName = "TestModule"; //NOI18N + final String arg = "appArg"; //NOI18N + final Java java = new Java(); + java.setFork(true); + java.setModule(moduleName); + java.setJvmargs("-Xmx128M"); + java.setArgs(arg); + final String[] cmdLine = java.getCommandLine().getCommandline(); + Assert.assertNotNull("Has command line.", cmdLine); + assertEquals("Command line should have 5 elements", 5, cmdLine.length); + assertEquals("Last command line element should be java argument: " + arg, + arg, + cmdLine[cmdLine.length-1]); + assertEquals("The command line element at index 3 should be module name: " + moduleName, + moduleName, + cmdLine[cmdLine.length-2]); + assertEquals("The command line element at index 2 should be -m", + "-m", + cmdLine[cmdLine.length-3]); + } + + @Test + public void testModuleAndClassnameCommandLine() { + final String moduleName = "TestModule"; //NOI18N + final String className = "org.apache.Test"; //NOI18N + final String moduleClassPair= String.format("%s/%s", moduleName, className); + final String arg = "appArg"; //NOI18N + final Java java = new Java(); + java.setFork(true); + java.setModule(moduleName); + java.setClassname(className); + java.setJvmargs("-Xmx128M"); //NOI18N + java.setArgs(arg); + final String[] cmdLine = java.getCommandLine().getCommandline(); + Assert.assertNotNull("Has command line.", cmdLine); + assertEquals("Command line should have 5 elements", 5, cmdLine.length); + assertEquals("Last command line element should be java argument: " + arg, + arg, + cmdLine[cmdLine.length-1]); + assertEquals("The command line element at index 3 should be module class pair: " + moduleClassPair, + moduleClassPair, + cmdLine[cmdLine.length-2]); + assertEquals("The command line element at index 2 should be -m", + "-m", + cmdLine[cmdLine.length-3]); + } + @Test public void testRun() { buildRule.executeTarget("testRun"); From aef407be4d33de09861a1f9677b2f15ea5ea8fdf Mon Sep 17 00:00:00 2001 From: Tomas Zezula Date: Tue, 8 Mar 2016 21:39:19 +0100 Subject: [PATCH 2/3] Updated Java task manual. Added since tags. --- manual/Tasks/java.html | 62 ++++++++++++++++++- .../org/apache/tools/ant/taskdefs/Java.java | 8 +-- .../tools/ant/types/CommandlineJava.java | 24 +++---- 3 files changed, 75 insertions(+), 19 deletions(-) diff --git a/manual/Tasks/java.html b/manual/Tasks/java.html index a83b0aff2..36d50ce53 100644 --- a/manual/Tasks/java.html +++ b/manual/Tasks/java.html @@ -54,9 +54,9 @@ attributes.

Required - classname + classname the Java class to execute. - Either jar or classname + Either jar, classname or module jar @@ -64,7 +64,7 @@ attributes.

Main-Class entry in the manifest). Fork must be set to true if this option is selected. See notes below for more details. - Either jar or classname + Either jar, classname or module args @@ -119,6 +119,25 @@ attributes.

(ignored if fork is disabled) No + + module + The initial or main module to resolve. To specify + the module main class use the classname attribute. + Fork must be set to true if this option is selected.since Ant 1.9.7 + Either jar, classname or module + + + modulepath + Specify where to find application modules. A list of directories of modules, module files or exploded modules.since Ant 1.9.7 + No + + + modulepathref + The modulepath to use, given as reference to a PATH defined elsewhere. + since Ant 1.9.7 + No + failonerror Stop the buildprocess if the command exits with a @@ -312,6 +331,18 @@ error and would mean the build exits. , then <java> must return 0 otherwise the build will exit, as the class was run by the build JVM.

+

modulepath

+Since Ant 1.9.7 +

Java's modulepath attribute is a PATH like structure and can also be set via a nested +modulepath element.

+ +

upgrademodulepath

+Since Ant 1.9.7 +

The location of modules that replace upgradeable modules in the runtime image +can be specified using this PATH like structure.

+ +

JAR file execution

The parameter of the jar attribute is of type File; @@ -400,6 +431,31 @@ log-prefix to [java1.4]. JVM, as it takes different parameters for other JVMs, That JVM can be started from <exec> if required.

+
+       <java
+           fork="true"
+           failonerror="true"
+           maxmemory="128m"
+           module="TestModule"
+           modulepath="lib:dist/test.jar"/>
+
+Runs the module TestModule resolved on the modulepath lib/:dist/test.jar +with a maximum memory of 128MB. Any non zero return code breaks the build. +
+       <java
+           fork="true"
+           failonerror="true"
+           maxmemory="128m"
+           module="TestModule"
+           classname="Main">
+         <modulepath>
+           <pathelement location="lib"/>
+           <pathelement location="dist/test.jar"/>
+         </modulepath>
+       </java>
+
+Runs the class Main in module TestModule resolved on the modulepath lib/:dist/test.jar +with a maximum memory of 128MB. Any non zero return code breaks the build. diff --git a/src/main/org/apache/tools/ant/taskdefs/Java.java b/src/main/org/apache/tools/ant/taskdefs/Java.java index 99e23429f..623a7c18e 100644 --- a/src/main/org/apache/tools/ant/taskdefs/Java.java +++ b/src/main/org/apache/tools/ant/taskdefs/Java.java @@ -298,7 +298,7 @@ public class Java extends Task { * Set the modulepath to be used when running the Java class. * * @param mp an Ant Path object containing the modulepath. - * @since ??? + * @since 1.9.7 */ public void setModulepath(Path mp) { createModulepath().append(mp); @@ -308,7 +308,7 @@ public class Java extends Task { * Add a path to the modulepath. * * @return created modulepath. - * @since ??? + * @since 1.9.7 */ public Path createModulepath() { return getCommandLine().createModulepath(getProject()).createPath(); @@ -318,7 +318,7 @@ public class Java extends Task { * Add a path to the upgrademodulepath. * * @return created upgrademodulepath. - * @since ??? + * @since 1.9.7 */ public Path createUpgrademodulepath() { return getCommandLine().createUpgrademodulepath(getProject()).createPath(); @@ -379,7 +379,7 @@ public class Java extends Task { * @param module the name of the module. * * @throws BuildException if the jar attribute has been set. - * @since ??? + * @since 1.9.7 */ public void setModule(String module) throws BuildException { if (getCommandLine().getJar() != null) { diff --git a/src/main/org/apache/tools/ant/types/CommandlineJava.java b/src/main/org/apache/tools/ant/types/CommandlineJava.java index cf36a67c9..97b2bcd79 100644 --- a/src/main/org/apache/tools/ant/types/CommandlineJava.java +++ b/src/main/org/apache/tools/ant/types/CommandlineJava.java @@ -374,7 +374,7 @@ public class CommandlineJava implements Cloneable { /** * Set the module to execute. * @param module the module name. - * @since ??? + * @since 1.9.7 */ public void setModule(final String module) { if (executableType == null) { @@ -404,7 +404,7 @@ public class CommandlineJava implements Cloneable { * @return the name of the module to run or null if there is no module. * @see #getJar() * @see #getClassname() - * @since ??? + * @since 1.9.7 */ public String getModule() { if(executableType == ExecutableType.MODULE) { @@ -442,7 +442,7 @@ public class CommandlineJava implements Cloneable { * Create a modulepath. * @param p the project to use to create the path. * @return a path to be configured. - * @since ??? + * @since 1.9.7 */ public Path createModulepath(Project p) { if (modulepath == null) { @@ -455,7 +455,7 @@ public class CommandlineJava implements Cloneable { * Create an upgrademodulepath. * @param p the project to use to create the path. * @return a path to be configured. - * @since ??? + * @since 1.9.7 */ public Path createUpgrademodulepath(Project p) { if (upgrademodulepath == null) { @@ -672,7 +672,7 @@ public class CommandlineJava implements Cloneable { /** * Get the modulepath. * @return modulepath or null. - * @since ??? + * @since 1.9.7 */ public Path getModulepath() { return modulepath; @@ -681,7 +681,7 @@ public class CommandlineJava implements Cloneable { /** * Get the upgrademodulepath. * @return upgrademodulepath or null. - * @since ??? + * @since 1.9.7 */ public Path getUpgrademodulepath() { return upgrademodulepath; @@ -783,7 +783,7 @@ public class CommandlineJava implements Cloneable { /** * Determine whether the modulepath has been specified. * @return true if the modulepath is to be used. - * @since ??? + * @since 1.9.7 */ public boolean haveModulepath() { Path fullClasspath = modulepath != null @@ -795,7 +795,7 @@ public class CommandlineJava implements Cloneable { /** * Determine whether the upgrademodulepath has been specified. * @return true if the upgrademodulepath is to be used. - * @since ??? + * @since 1.9.7 */ public boolean haveUpgrademodulepath() { Path fullClasspath = upgrademodulepath != null @@ -846,7 +846,7 @@ public class CommandlineJava implements Cloneable { * @param module the module name. * @param classname the classname or null. * @return the main module with optional classname command line argument. - * @since ??? + * @since 1.9.7 */ private static String createModuleClassPair(final String module, final String classname) { return classname == null ? @@ -858,7 +858,7 @@ public class CommandlineJava implements Cloneable { * Parses a module name from JDK 9 main module command line argument. * @param moduleClassPair a module with optional classname or null. * @return the module name or null. - * @since ??? + * @since 1.9.7 */ private static String parseModuleFromModuleClassPair(final String moduleClassPair) { if (moduleClassPair == null) { @@ -872,7 +872,7 @@ public class CommandlineJava implements Cloneable { * Parses a classname from JDK 9 main module command line argument. * @param moduleClassPair a module with optional classname or null. * @return the classname or null. - * @since ??? + * @since 1.9.7 */ private static String parseClassFromModuleClassPair(final String moduleClassPair) { if (moduleClassPair == null) { @@ -886,7 +886,7 @@ public class CommandlineJava implements Cloneable { /** * Type of execution. - * @since ??? + * @since 1.9.7 */ private enum ExecutableType { /** From 1e501f27ecc8f292ff028191e886a36d4b571d79 Mon Sep 17 00:00:00 2001 From: Tomas Zezula Date: Tue, 8 Mar 2016 23:11:02 +0100 Subject: [PATCH 3/3] Added modulepathref attribute to Java. --- src/main/org/apache/tools/ant/taskdefs/Java.java | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/main/org/apache/tools/ant/taskdefs/Java.java b/src/main/org/apache/tools/ant/taskdefs/Java.java index 623a7c18e..ffe92cfad 100644 --- a/src/main/org/apache/tools/ant/taskdefs/Java.java +++ b/src/main/org/apache/tools/ant/taskdefs/Java.java @@ -314,6 +314,16 @@ public class Java extends Task { return getCommandLine().createModulepath(getProject()).createPath(); } + /** + * Set the modulepath to use by reference. + * + * @param r a reference to an existing modulepath. + * @since 1.9.7 + */ + public void setModulepathRef(Reference r) { + createModulepath().setRefid(r); + } + /** * Add a path to the upgrademodulepath. *