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");