Repository: ant Updated Branches: refs/heads/master aeed1d84d -> 0ff7cc851
Added module, modulepath attributes and modulepath, moduleupgradepath elements into Java task. Project: http://git-wip-us.apache.org/repos/asf/ant/repo Commit: http://git-wip-us.apache.org/repos/asf/ant/commit/23b0cf06 Tree: http://git-wip-us.apache.org/repos/asf/ant/tree/23b0cf06 Diff: http://git-wip-us.apache.org/repos/asf/ant/diff/23b0cf06 Branch: refs/heads/master Commit: 23b0cf06c276387ac3f5d455c0b45a5c4ab888dc Parents: aeed1d8 Author: Tomas Zezula <[email protected]> Authored: Thu Mar 3 12:56:40 2016 +0100 Committer: Stefan Bodewig <[email protected]> Committed: Sun Mar 6 12:32:28 2016 +0100 ---------------------------------------------------------------------- src/etc/testcases/taskdefs/java.xml | 23 ++ .../org/apache/tools/ant/taskdefs/Java.java | 57 ++++- .../apache/tools/ant/types/CommandlineJava.java | 228 ++++++++++++++++++- .../org/apache/tools/ant/taskdefs/JavaTest.java | 88 ++++++- 4 files changed, 381 insertions(+), 15 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/ant/blob/23b0cf06/src/etc/testcases/taskdefs/java.xml ---------------------------------------------------------------------- diff --git a/src/etc/testcases/taskdefs/java.xml b/src/etc/testcases/taskdefs/java.xml index a0c0450..a3d3778 100644 --- a/src/etc/testcases/taskdefs/java.xml +++ b/src/etc/testcases/taskdefs/java.xml @@ -44,6 +44,9 @@ <property name="pipeapp" value="org.apache.tools.ant.taskdefs.JavaTest$$PipeEntryPoint" /> + <property name="module" + value="TestModule" /> + <target name="testNoJarNoClassname"> <java/> </target> @@ -61,6 +64,26 @@ <java classname="${app}" jar="test.jar" /> </target> + <target name="testModuleAndJar"> + <java module="${module}" jar="test.jar" /> + </target> + + <target name="testJarAndModule"> + <java jar="test.jar" module="${module}" /> + </target> + + <target name="testClassnameAndModule"> + <java classname="${app}" module="${module}" fork="true"/> + </target> + + <target name="testModuleAndClassname"> + <java module="${module}" classname="${app}" fork="true"/> + </target> + + <target name="testModule"> + <java module="${module}" fork="true"/> + </target> + <target name="testRun"> <fail unless="tests-classpath.value" /> <java classname="${app}" http://git-wip-us.apache.org/repos/asf/ant/blob/23b0cf06/src/main/org/apache/tools/ant/taskdefs/Java.java ---------------------------------------------------------------------- diff --git a/src/main/org/apache/tools/ant/taskdefs/Java.java b/src/main/org/apache/tools/ant/taskdefs/Java.java index 5e065bc..99e2342 100644 --- a/src/main/org/apache/tools/ant/taskdefs/Java.java +++ b/src/main/org/apache/tools/ant/taskdefs/Java.java @@ -142,13 +142,18 @@ public class Java extends Task { */ protected void checkConfiguration() throws BuildException { String classname = getCommandLine().getClassname(); - if (classname == null && getCommandLine().getJar() == null) { + String module = getCommandLine().getModule(); + if (classname == null && getCommandLine().getJar() == null && module == null) { throw new BuildException("Classname must not be null."); } if (!fork && getCommandLine().getJar() != null) { throw new BuildException("Cannot execute a jar in non-forked mode." + " Please set fork='true'. "); } + if (!fork && getCommandLine().getModule() != null) { + throw new BuildException("Cannot execute a module in non-forked mode." + + " Please set fork='true'. "); + } if (spawn && !fork) { throw new BuildException("Cannot spawn a java process in non-forked mode." + " Please set fork='true'. "); @@ -290,6 +295,36 @@ 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 ??? + */ + public void setModulepath(Path mp) { + createModulepath().append(mp); + } + + /** + * Add a path to the modulepath. + * + * @return created modulepath. + * @since ??? + */ + public Path createModulepath() { + return getCommandLine().createModulepath(getProject()).createPath(); + } + + /** + * Add a path to the upgrademodulepath. + * + * @return created upgrademodulepath. + * @since ??? + */ + public Path createUpgrademodulepath() { + return getCommandLine().createUpgrademodulepath(getProject()).createPath(); + } + + /** * Set the permissions for the application run inside the same JVM. * @since Ant 1.6 * @return Permissions. @@ -316,8 +351,8 @@ public class Java extends Task { * @throws BuildException if there is also a main class specified. */ public void setJar(File jarfile) throws BuildException { - if (getCommandLine().getClassname() != null) { - throw new BuildException("Cannot use 'jar' and 'classname' " + if (getCommandLine().getClassname() != null || getCommandLine().getModule() != null) { + throw new BuildException("Cannot use 'jar' with 'classname' or 'module' " + "attributes in same command."); } getCommandLine().setJar(jarfile.getAbsolutePath()); @@ -339,6 +374,22 @@ public class Java extends Task { } /** + * Set the Java module to execute. + * + * @param module the name of the module. + * + * @throws BuildException if the jar attribute has been set. + * @since ??? + */ + public void setModule(String module) throws BuildException { + if (getCommandLine().getJar() != null) { + throw new BuildException("Cannot use 'jar' and 'module' " + + "attributes in same command"); + } + getCommandLine().setModule(module); + } + + /** * Deprecated: use nested arg instead. * Set the command line arguments for the class. * http://git-wip-us.apache.org/repos/asf/ant/blob/23b0cf06/src/main/org/apache/tools/ant/types/CommandlineJava.java ---------------------------------------------------------------------- diff --git a/src/main/org/apache/tools/ant/types/CommandlineJava.java b/src/main/org/apache/tools/ant/types/CommandlineJava.java index 9da354d..cf36a67 100644 --- a/src/main/org/apache/tools/ant/types/CommandlineJava.java +++ b/src/main/org/apache/tools/ant/types/CommandlineJava.java @@ -52,6 +52,8 @@ public class CommandlineJava implements Cloneable { private SysProperties sysProperties = new SysProperties(); private Path classpath = null; private Path bootclasspath = null; + private Path modulepath = null; + private Path upgrademodulepath = null; private String vmVersion; private String maxMemory = null; /** @@ -60,10 +62,11 @@ public class CommandlineJava implements Cloneable { private Assertions assertions = null; /** - * Indicate whether it will execute a jar file or not, in this case - * the first vm option must be a -jar and the 'executable' is a jar file. + * Indicate whether it will execute a jar file, module or main class. + * In this case of jar the first vm option must be a -jar and the 'executable' is a jar file. + * In case of module the first vm option is -m and the 'executable' is 'module/mainClass'. */ - private boolean executeJar = false; + private ExecutableType executableType; /** * Whether system properties and bootclasspath shall be cloned. @@ -320,7 +323,7 @@ public class CommandlineJava implements Cloneable { */ public void setJar(String jarpathname) { javaCommand.setExecutable(jarpathname); - executeJar = true; + executableType = ExecutableType.JAR; } /** @@ -330,7 +333,7 @@ public class CommandlineJava implements Cloneable { * @see #getClassname() */ public String getJar() { - if (executeJar) { + if (executableType == ExecutableType.JAR) { return javaCommand.getExecutable(); } return null; @@ -341,8 +344,14 @@ public class CommandlineJava implements Cloneable { * @param classname the fully qualified classname. */ public void setClassname(String classname) { - javaCommand.setExecutable(classname); - executeJar = false; + if (executableType == ExecutableType.MODULE) { + javaCommand.setExecutable(createModuleClassPair( + parseModuleFromModuleClassPair(javaCommand.getExecutable()), + classname)); + } else { + javaCommand.setExecutable(classname); + executableType = ExecutableType.CLASS; + } } /** @@ -351,8 +360,55 @@ public class CommandlineJava implements Cloneable { * @see #getJar() */ public String getClassname() { - if (!executeJar) { - return javaCommand.getExecutable(); + if (executableType != null) { + switch (executableType) { + case CLASS: + return javaCommand.getExecutable(); + case MODULE: + return parseClassFromModuleClassPair(javaCommand.getExecutable()); + } + } + return null; + } + + /** + * Set the module to execute. + * @param module the module name. + * @since ??? + */ + public void setModule(final String module) { + if (executableType == null) { + javaCommand.setExecutable(module); + } else { + switch (executableType) { + case JAR: + javaCommand.setExecutable(module); + break; + case CLASS: + javaCommand.setExecutable(createModuleClassPair( + module, + javaCommand.getExecutable())); + break; + case MODULE: + javaCommand.setExecutable(createModuleClassPair( + module, + parseClassFromModuleClassPair(javaCommand.getExecutable()))); + break; + } + } + executableType = ExecutableType.MODULE; + } + + /** + * Get the name of the module to be run. + * @return the name of the module to run or <tt>null</tt> if there is no module. + * @see #getJar() + * @see #getClassname() + * @since ??? + */ + public String getModule() { + if(executableType == ExecutableType.MODULE) { + return parseModuleFromModuleClassPair(javaCommand.getExecutable()); } return null; } @@ -383,6 +439,32 @@ 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 ??? + */ + 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 @@ -574,6 +670,24 @@ public class CommandlineJava implements Cloneable { } /** + * 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. * @throws BuildException if Security prevented this operation. @@ -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(); } @@ -661,6 +781,30 @@ public class CommandlineJava implements Cloneable { } /** + * 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 * properties as well as the cloneVm attribute. @@ -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 <code>null</code>. + * @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 <code>null</code>. + * @return the module name or <code>null</code>. + * @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 <code>null</code>. + * @return the classname or <code>null</code>. + * @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 + } } http://git-wip-us.apache.org/repos/asf/ant/blob/23b0cf06/src/tests/junit/org/apache/tools/ant/taskdefs/JavaTest.java ---------------------------------------------------------------------- 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 d54b8f2..8d99571 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,11 +120,95 @@ 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"); }
