From e3e9a2ccb8b8f14b27987f1363dfbc9367713f9b Mon Sep 17 00:00:00 2001 From: Abhinay Agarwal Date: Wed, 24 Jun 2020 12:49:23 +0530 Subject: [PATCH 01/24] Working directory should be resolved before querying for executable path --- src/main/java/org/openjfx/JavaFXJLinkMojo.java | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/main/java/org/openjfx/JavaFXJLinkMojo.java b/src/main/java/org/openjfx/JavaFXJLinkMojo.java index eb84b77..6298f46 100644 --- a/src/main/java/org/openjfx/JavaFXJLinkMojo.java +++ b/src/main/java/org/openjfx/JavaFXJLinkMojo.java @@ -1,5 +1,5 @@ /* - * Copyright 2019 Gluon + * Copyright 2019, 2020, Gluon * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -164,6 +164,7 @@ public void execute() throws MojoExecutionException { throw new IllegalStateException( "basedir is null. Should not be possible." ); } + handleWorkingDirectory(); Map enviro = handleSystemEnvVariables(); CommandLine commandLine = getExecutablePath(jlinkExecutable, enviro, workingDirectory); @@ -179,8 +180,6 @@ public void execute() throws MojoExecutionException { } try { - handleWorkingDirectory(); - List commandArguments = createCommandArguments(); String[] args = commandArguments.toArray(new String[commandArguments.size()]); commandLine.addArguments(args, false); From 6b352e864be73d26dbffa9823a8de7c2d3a52f86 Mon Sep 17 00:00:00 2001 From: Abhinay Agarwal Date: Wed, 24 Jun 2020 12:54:18 +0530 Subject: [PATCH 02/24] Add dependencies to module-path only when the project is modular --- src/main/java/org/openjfx/JavaFXBaseMojo.java | 94 ++++++++----------- 1 file changed, 41 insertions(+), 53 deletions(-) diff --git a/src/main/java/org/openjfx/JavaFXBaseMojo.java b/src/main/java/org/openjfx/JavaFXBaseMojo.java index bfc905f..34899f6 100644 --- a/src/main/java/org/openjfx/JavaFXBaseMojo.java +++ b/src/main/java/org/openjfx/JavaFXBaseMojo.java @@ -1,5 +1,5 @@ /* - * Copyright 2019 Gluon + * Copyright 2019, 2020, Gluon * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -201,69 +201,58 @@ void preparePaths(Path jdkHome) throws MojoExecutionException { getLog().debug("Total dependencyArtifacts: " + dependencyArtifacts.size()); ResolvePathsRequest fileResolvePathsRequest = ResolvePathsRequest.ofFiles(dependencyArtifacts); - ResolvePathsResult resolvePathsResult; + getLog().debug("module descriptor: " + moduleDescriptorPath); if (moduleDescriptorPath != null) { - getLog().debug("module descriptor: " + moduleDescriptorPath); fileResolvePathsRequest.setMainModuleDescriptor(moduleDescriptorPath); } if (jdkHome != null) { fileResolvePathsRequest.setJdkHome(jdkHome.toFile()); } - resolvePathsResult = locationManager.resolvePaths(fileResolvePathsRequest); - - if (!resolvePathsResult.getPathExceptions().isEmpty() && !isMavenUsingJava8()) { - // for each path exception, show a warning to plugin user... - for (Map.Entry pathException : resolvePathsResult.getPathExceptions().entrySet()) { - Throwable cause = pathException.getValue(); - while (cause.getCause() != null) { - cause = cause.getCause(); - } - String fileName = pathException.getKey().getName(); - getLog().warn("Can't extract module name from " + fileName + ": " + cause.getMessage()); - } - // ...if includePathExceptionsInClasspath is NOT enabled; provide configuration hint to plugin user - if (!includePathExceptionsInClasspath) { - getLog().warn("Some dependencies encountered issues while attempting to be resolved as modules" + - " and will not be included in the classpath; you can change this behavior via the " + - " 'includePathExceptionsInClasspath' configuration parameter."); - } - } + ResolvePathsResult resolvePathsResult = locationManager.resolvePaths(fileResolvePathsRequest); + resolvePathsResult.getPathElements().forEach((key, value) -> pathElements.put(key.getPath(), value)); if (moduleDescriptorPath != null) { + if (!resolvePathsResult.getPathExceptions().isEmpty() && !isMavenUsingJava8()) { + // for each path exception, show a warning to plugin user... + for (Map.Entry pathException : resolvePathsResult.getPathExceptions().entrySet()) { + Throwable cause = pathException.getValue(); + while (cause.getCause() != null) { + cause = cause.getCause(); + } + String fileName = pathException.getKey().getName(); + getLog().warn("Can't extract module name from " + fileName + ": " + cause.getMessage()); + } + // ...if includePathExceptionsInClasspath is NOT enabled; provide configuration hint to plugin user + if (!includePathExceptionsInClasspath) { + getLog().warn("Some dependencies encountered issues while attempting to be resolved as modules" + + " and will not be included in the classpath; you can change this behavior via the " + + " 'includePathExceptionsInClasspath' configuration parameter."); + } + } moduleDescriptor = resolvePathsResult.getMainModuleDescriptor(); - } - - for (Map.Entry entry : resolvePathsResult.getModulepathElements().entrySet()) { - if (ModuleNameSource.FILENAME.equals(entry.getValue())) { - final String message = "Required filename-based automodules detected. " - + "Please don't publish this project to a public artifact repository!"; - - if (moduleDescriptor != null && moduleDescriptor.exports().isEmpty()) { - // application - getLog().info(message); - } else { - // library - getLog().warn(message); + for (Map.Entry entry : resolvePathsResult.getModulepathElements().entrySet()) { + if (ModuleNameSource.FILENAME.equals(entry.getValue())) { + final String message = "Required filename-based automodules detected. " + + "Please don't publish this project to a public artifact repository!"; + + if (moduleDescriptor != null && moduleDescriptor.exports().isEmpty()) { + // application + getLog().info(message); + } else { + // library + getLog().warn(message); + } + break; } - break; } - } - - getLog().debug("pathElements: " + resolvePathsResult.getPathElements().size()); - resolvePathsResult.getPathElements().forEach((key, value) -> pathElements.put(key.getPath(), value)); - getLog().debug("classpathElements: " + resolvePathsResult.getClasspathElements().size()); - resolvePathsResult.getClasspathElements() - .forEach(file -> classpathElements.add(file.getPath())); - getLog().debug("modulepathElements: " + resolvePathsResult.getModulepathElements().size()); - resolvePathsResult.getModulepathElements().keySet() - .forEach(file -> modulepathElements.add(file.getPath())); - - if (includePathExceptionsInClasspath) { - resolvePathsResult.getPathExceptions().keySet() - .forEach(file -> classpathElements.add(file.getPath())); - } + resolvePathsResult.getClasspathElements().forEach(file -> classpathElements.add(file.getPath())); + resolvePathsResult.getModulepathElements().keySet().forEach(file -> modulepathElements.add(file.getPath())); - if (moduleDescriptorPath == null) { + if (includePathExceptionsInClasspath) { + resolvePathsResult.getPathExceptions().keySet() + .forEach(file -> classpathElements.add(file.getPath())); + } + } else { // non-modular projects pathElements.forEach((k, v) -> { if (v != null && v.name() != null && v.name().startsWith(JAVAFX_PREFIX)) { @@ -274,7 +263,6 @@ void preparePaths(Path jdkHome) throws MojoExecutionException { } }); } - } catch (Exception e) { getLog().warn(e.getMessage()); } From 9652045f22a33bc3aba6eb8623478bb46cd127a6 Mon Sep 17 00:00:00 2001 From: Abhinay Agarwal Date: Wed, 24 Jun 2020 12:57:34 +0530 Subject: [PATCH 03/24] Add runtimePath parameter --- README.md | 2 ++ src/main/java/org/openjfx/JavaFXBaseMojo.java | 24 +++++++++++++++++++ src/main/java/org/openjfx/JavaFXRunMojo.java | 9 ++++--- .../java/org/openjfx/model/RuntimePath.java | 22 +++++++++++++++++ 4 files changed, 54 insertions(+), 3 deletions(-) create mode 100644 src/main/java/org/openjfx/model/RuntimePath.java diff --git a/README.md b/README.md index 76ec00a..4dd41f7 100644 --- a/README.md +++ b/README.md @@ -129,6 +129,8 @@ Optionally, the configuration can be modified with: - `includePathExceptionsInClasspath`: When resolving the module-path, setting this value to true will include the dependencies that generate path exceptions in the classpath. By default the value is false, and these dependencies won't be included. +- `runtimePath`: Allows to run the application by adding all the dependencies on either classpath or modulepath. +Values: MODULEPATH, CLASSPATH or DEFAULT. For instance, the following configuration adds some VM options and a command line argument: diff --git a/src/main/java/org/openjfx/JavaFXBaseMojo.java b/src/main/java/org/openjfx/JavaFXBaseMojo.java index 34899f6..ef131e2 100644 --- a/src/main/java/org/openjfx/JavaFXBaseMojo.java +++ b/src/main/java/org/openjfx/JavaFXBaseMojo.java @@ -39,6 +39,7 @@ import org.codehaus.plexus.languages.java.jpms.ResolvePathsResult; import org.codehaus.plexus.util.StringUtils; import org.codehaus.plexus.util.cli.CommandLineUtils; +import org.openjfx.model.RuntimePath; import java.io.BufferedOutputStream; import java.io.File; @@ -59,6 +60,9 @@ import java.util.stream.Collectors; import java.util.stream.Stream; +import static org.openjfx.model.RuntimePath.CLASSPATH; +import static org.openjfx.model.RuntimePath.MODULEPATH; + abstract class JavaFXBaseMojo extends AbstractMojo { static final String JAVAFX_PREFIX = "javafx"; @@ -90,6 +94,9 @@ abstract class JavaFXBaseMojo extends AbstractMojo { @Parameter(readonly = true, required = true, defaultValue = "${project.build.directory}") File builddir; + @Parameter(property = "javafx.runtimePath", defaultValue = "DEFAULT") + RuntimePath runtimePath; + /** * The current working directory. Optional. If not specified, basedir will be used. */ @@ -267,6 +274,23 @@ void preparePaths(Path jdkHome) throws MojoExecutionException { getLog().warn(e.getMessage()); } + if (runtimePath == MODULEPATH) { + if (moduleDescriptor == null) { + // target/classes should still be on classpath + final List classpathJars = classpathElements.stream() + .filter(ce -> ce.endsWith(".jar")) + .collect(Collectors.toList()); + modulepathElements.addAll(classpathJars); + classpathElements.removeAll(classpathJars); + } else { + modulepathElements.addAll(classpathElements); + classpathElements.clear(); + } + } else if (runtimePath == CLASSPATH) { + classpathElements.addAll(modulepathElements); + modulepathElements.clear(); + } + getLog().debug("Classpath:" + classpathElements.size()); classpathElements.forEach(s -> getLog().debug(" " + s)); diff --git a/src/main/java/org/openjfx/JavaFXRunMojo.java b/src/main/java/org/openjfx/JavaFXRunMojo.java index bb448fe..5409d33 100644 --- a/src/main/java/org/openjfx/JavaFXRunMojo.java +++ b/src/main/java/org/openjfx/JavaFXRunMojo.java @@ -1,5 +1,5 @@ /* - * Copyright 2019 Gluon + * Copyright 2019, 2020, Gluon * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -41,6 +41,9 @@ import java.util.regex.Pattern; import java.util.stream.Collectors; +import static org.openjfx.model.RuntimePath.CLASSPATH; +import static org.openjfx.model.RuntimePath.MODULEPATH; + @Mojo(name = "run", requiresDependencyResolution = ResolutionScope.RUNTIME) @Execute(phase = LifecyclePhase.PROCESS_CLASSES) public class JavaFXRunMojo extends JavaFXBaseMojo { @@ -134,7 +137,7 @@ private List createCommandArguments(boolean oldJDK) throws MojoExecution .forEach(commandArguments::add); } if (!oldJDK) { - if (modulepathElements != null && !modulepathElements.isEmpty()) { + if (runtimePath == MODULEPATH || modulepathElements != null && !modulepathElements.isEmpty()) { commandArguments.add(" --module-path"); String modulePath = StringUtils.join(modulepathElements.iterator(), File.pathSeparator); commandArguments.add(modulePath); @@ -154,7 +157,7 @@ private List createCommandArguments(boolean oldJDK) throws MojoExecution } } - if (classpathElements != null && (oldJDK || !classpathElements.isEmpty())) { + if (runtimePath == CLASSPATH || classpathElements != null && (oldJDK || !classpathElements.isEmpty())) { commandArguments.add(" -classpath"); String classpath = ""; if (oldJDK || moduleDescriptor != null) { diff --git a/src/main/java/org/openjfx/model/RuntimePath.java b/src/main/java/org/openjfx/model/RuntimePath.java new file mode 100644 index 0000000..5a04c69 --- /dev/null +++ b/src/main/java/org/openjfx/model/RuntimePath.java @@ -0,0 +1,22 @@ +/* + * Copyright 2020, Gluon + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.openjfx.model; + +public enum RuntimePath { + CLASSPATH, + MODULEPATH, + DEFAULT +} From 594cc5141ba15923e325447cce3dee09a0ca1550 Mon Sep 17 00:00:00 2001 From: Abhinay Agarwal Date: Fri, 26 Jun 2020 18:07:00 +0530 Subject: [PATCH 04/24] Add `jlinkOptions` parameter to pass options to jlink executable --- README.md | 1 + src/main/java/org/openjfx/JavaFXBaseMojo.java | 37 +++++++++++++++ .../java/org/openjfx/JavaFXJLinkMojo.java | 18 ++++++++ src/main/java/org/openjfx/JavaFXRunMojo.java | 36 --------------- .../java/org/openjfx/JavaFXBaseMojoTest.java | 46 +++++++++++++++++++ .../org/openjfx/JavaFXRunMojoTestCase.java | 32 +------------ 6 files changed, 103 insertions(+), 67 deletions(-) diff --git a/README.md b/README.md index 4dd41f7..37bf445 100644 --- a/README.md +++ b/README.md @@ -129,6 +129,7 @@ Optionally, the configuration can be modified with: - `includePathExceptionsInClasspath`: When resolving the module-path, setting this value to true will include the dependencies that generate path exceptions in the classpath. By default the value is false, and these dependencies won't be included. +- `jlinkOptions`: A list of options passed to the jlink executable. - `runtimePath`: Allows to run the application by adding all the dependencies on either classpath or modulepath. Values: MODULEPATH, CLASSPATH or DEFAULT. diff --git a/src/main/java/org/openjfx/JavaFXBaseMojo.java b/src/main/java/org/openjfx/JavaFXBaseMojo.java index ef131e2..ca135f8 100644 --- a/src/main/java/org/openjfx/JavaFXBaseMojo.java +++ b/src/main/java/org/openjfx/JavaFXBaseMojo.java @@ -57,6 +57,7 @@ import java.util.List; import java.util.Map; import java.util.Properties; +import java.util.regex.Pattern; import java.util.stream.Collectors; import java.util.stream.Stream; @@ -421,6 +422,42 @@ static Path getParent(Path path, int depth) { return path.getRoot().resolve(path.subpath(0, path.getNameCount() - depth)); } + List splitComplexArgumentString(String argumentString) { + char[] strArr = argumentString.trim().toCharArray(); + + List splitedArgs = new ArrayList<>(); + StringBuilder sb = new StringBuilder(); + + char expectedSeparator = ' '; + for (int i = 0; i < strArr.length; i++) { + char item = strArr[i]; + + if (item == expectedSeparator + || (expectedSeparator == ' ' && Pattern.matches("\\s", String.valueOf(item))) ) { + + if (expectedSeparator == '"' || expectedSeparator == '\'') { + sb.append(item); + expectedSeparator = ' '; + } else if (expectedSeparator == ' ' && sb.length() > 0) { + splitedArgs.add(sb.toString()); + sb.delete(0, sb.length()); + } + } else { + if (expectedSeparator == ' ' && (item == '"' || item == '\'')) { + expectedSeparator = item; + } + + sb.append(item); + } + + if (i == strArr.length - 1 && sb.length() > 0) { + splitedArgs.add(sb.toString()); + } + } + + return splitedArgs; + } + private static String findExecutable(final String executable, final List paths) { File f = null; search: for (final String path : paths) { diff --git a/src/main/java/org/openjfx/JavaFXJLinkMojo.java b/src/main/java/org/openjfx/JavaFXJLinkMojo.java index ab21c17..ec917d8 100644 --- a/src/main/java/org/openjfx/JavaFXJLinkMojo.java +++ b/src/main/java/org/openjfx/JavaFXJLinkMojo.java @@ -43,6 +43,7 @@ import java.nio.file.Path; import java.nio.file.Paths; import java.util.ArrayList; +import java.util.Collection; import java.util.Comparator; import java.util.List; import java.util.Map; @@ -151,6 +152,12 @@ public class JavaFXJLinkMojo extends JavaFXBaseMojo { @Component(role = Archiver.class, hint = "zip") private ZipArchiver zipArchiver; + /** + * A list of options passed to the jlink {@code executable}. + */ + @Parameter + List jlinkOptions; + public void execute() throws MojoExecutionException { if (skip) { getLog().info( "skipping execute as per configuration" ); @@ -289,6 +296,17 @@ private void patchLauncherScript(String launcherFilename) throws IOException { private List createCommandArguments() throws MojoExecutionException, MojoFailureException { List commandArguments = new ArrayList<>(); preparePaths(getParent(Paths.get(jlinkExecutable), 2)); + + if (jlinkOptions != null) { + jlinkOptions.stream() + .filter(Objects::nonNull) + .filter(String.class::isInstance) + .map(String.class::cast) + .map(this::splitComplexArgumentString) + .flatMap(Collection::stream) + .forEach(commandArguments::add); + } + if (modulepathElements != null && !modulepathElements.isEmpty()) { commandArguments.add(" --module-path"); String modulePath = StringUtils.join(modulepathElements.iterator(), File.pathSeparator); diff --git a/src/main/java/org/openjfx/JavaFXRunMojo.java b/src/main/java/org/openjfx/JavaFXRunMojo.java index 5409d33..2ae2da2 100644 --- a/src/main/java/org/openjfx/JavaFXRunMojo.java +++ b/src/main/java/org/openjfx/JavaFXRunMojo.java @@ -186,42 +186,6 @@ private List createCommandArguments(boolean oldJDK) throws MojoExecution return commandArguments; } - private List splitComplexArgumentString(String argumentString) { - char[] strArr = argumentString.trim().toCharArray(); - - List splitedArgs = new ArrayList<>(); - StringBuilder sb = new StringBuilder(); - - char expectedSeparator = ' '; - for (int i = 0; i < strArr.length; i++) { - char item = strArr[i]; - - if (item == expectedSeparator - || (expectedSeparator == ' ' && Pattern.matches("\\s", String.valueOf(item))) ) { - - if (expectedSeparator == '"' || expectedSeparator == '\'') { - sb.append(item); - expectedSeparator = ' '; - } else if (expectedSeparator == ' ' && sb.length() > 0) { - splitedArgs.add(sb.toString()); - sb.delete(0, sb.length()); - } - } else { - if (expectedSeparator == ' ' && (item == '"' || item == '\'')) { - expectedSeparator = item; - } - - sb.append(item); - } - - if (i == strArr.length - 1 && sb.length() > 0) { - splitedArgs.add(sb.toString()); - } - } - - return splitedArgs; - } - // for tests void setExecutable(String executable) { diff --git a/src/test/java/org/openjfx/JavaFXBaseMojoTest.java b/src/test/java/org/openjfx/JavaFXBaseMojoTest.java index 0f1a70a..54d58c9 100644 --- a/src/test/java/org/openjfx/JavaFXBaseMojoTest.java +++ b/src/test/java/org/openjfx/JavaFXBaseMojoTest.java @@ -1,3 +1,18 @@ +/* + * Copyright 2019, 2020, Gluon + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package org.openjfx; import org.junit.AfterClass; @@ -43,6 +58,37 @@ public void invalidPathWithDepthTest() { Assert.assertNull(JavaFXBaseMojo.getParent(Paths.get("/some-invalid-path"), 2)); } + @Test + public void testSplitComplexArgumentString() { + String option = "param1 " + + "param2 \n " + + "param3\n" + + "param4=\"/path/to/my file.log\" " + + "'var\"foo var\"foo' " + + "'var\"foo' " + + "'var\"foo' " + + "\"foo'var foo'var\" " + + "\"foo'var\" " + + "\"foo'var\""; + + String expected = "START," + + "param1," + + "param2," + + "param3," + + "param4=\"/path/to/my file.log\"," + + "'var\"foo var\"foo'," + + "'var\"foo'," + + "'var\"foo'," + + "\"foo'var foo'var\"," + + "\"foo'var\"," + + "\"foo'var\""; + + String splitedOption = new JavaFXRunMojo().splitComplexArgumentStringAdapter(option) + .stream().reduce("START", (s1, s2) -> s1 + "," + s2); + + Assert.assertEquals(expected, splitedOption); + } + @AfterClass public static void destroy() throws IOException { Files.walk(path.getParent()) diff --git a/src/test/java/org/openjfx/JavaFXRunMojoTestCase.java b/src/test/java/org/openjfx/JavaFXRunMojoTestCase.java index 6b293ed..ebeb6b8 100644 --- a/src/test/java/org/openjfx/JavaFXRunMojoTestCase.java +++ b/src/test/java/org/openjfx/JavaFXRunMojoTestCase.java @@ -1,5 +1,5 @@ /* - * Copyright 2019 Gluon + * Copyright 2019, 2020, Gluon * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -206,34 +206,4 @@ private String getCommandLineAsString(CommandLine commandline) { } return result; } - - public void testSplitComplexArgumentString() { - String option = "param1 " + - "param2 \n " + - "param3\n" + - "param4=\"/path/to/my file.log\" " + - "'var\"foo var\"foo' " + - "'var\"foo' " + - "'var\"foo' " + - "\"foo'var foo'var\" " + - "\"foo'var\" " + - "\"foo'var\""; - - String expected = "START," + - "param1," + - "param2," + - "param3," + - "param4=\"/path/to/my file.log\"," + - "'var\"foo var\"foo'," + - "'var\"foo'," + - "'var\"foo'," + - "\"foo'var foo'var\"," + - "\"foo'var\"," + - "\"foo'var\""; - - String splitedOption = new JavaFXRunMojo().splitComplexArgumentStringAdapter(option) - .stream().reduce("START", (s1, s2) -> s1 + "," + s2); - - assertEquals(expected, splitedOption); - } } From 0bbf8fb6dadb66688b3fc8c7531f6471e616f809 Mon Sep 17 00:00:00 2001 From: Abhinay Agarwal Date: Fri, 21 Aug 2020 11:05:56 +0530 Subject: [PATCH 05/24] Remove DEFAULT from RuntimePath --- README.md | 6 +++--- src/main/java/org/openjfx/model/RuntimePath.java | 6 ++++-- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 37bf445..eaf6bdb 100644 --- a/README.md +++ b/README.md @@ -127,13 +127,13 @@ Optionally, the configuration can be modified with: - `options`: A list of VM options passed to the executable. - `commandlineArgs`: Arguments separated by space for the executed program - `includePathExceptionsInClasspath`: When resolving the module-path, setting this value to true will include the -dependencies that generate path exceptions in the classpath. By default the value is false, and these dependencies +dependencies that generate path exceptions in the classpath. By default, the value is false, and these dependencies won't be included. - `jlinkOptions`: A list of options passed to the jlink executable. - `runtimePath`: Allows to run the application by adding all the dependencies on either classpath or modulepath. -Values: MODULEPATH, CLASSPATH or DEFAULT. +Values: MODULEPATH or CLASSPATH. -For instance, the following configuration adds some VM options and a command line argument: +For instance, the following configuration adds some VM options, and a command line argument: ``` diff --git a/src/main/java/org/openjfx/model/RuntimePath.java b/src/main/java/org/openjfx/model/RuntimePath.java index 5a04c69..d610a50 100644 --- a/src/main/java/org/openjfx/model/RuntimePath.java +++ b/src/main/java/org/openjfx/model/RuntimePath.java @@ -15,8 +15,10 @@ */ package org.openjfx.model; +/** + * Types of RuntimePath + */ public enum RuntimePath { CLASSPATH, - MODULEPATH, - DEFAULT + MODULEPATH } From d4f2fb0d48c5b95f49f3449d40b501ba1657a380 Mon Sep 17 00:00:00 2001 From: Abhinay Agarwal Date: Fri, 4 Sep 2020 13:15:32 +0530 Subject: [PATCH 06/24] Remove defaultValue for runtimePath --- src/main/java/org/openjfx/JavaFXBaseMojo.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/org/openjfx/JavaFXBaseMojo.java b/src/main/java/org/openjfx/JavaFXBaseMojo.java index ca135f8..60a597b 100644 --- a/src/main/java/org/openjfx/JavaFXBaseMojo.java +++ b/src/main/java/org/openjfx/JavaFXBaseMojo.java @@ -95,7 +95,7 @@ abstract class JavaFXBaseMojo extends AbstractMojo { @Parameter(readonly = true, required = true, defaultValue = "${project.build.directory}") File builddir; - @Parameter(property = "javafx.runtimePath", defaultValue = "DEFAULT") + @Parameter(property = "javafx.runtimePath") RuntimePath runtimePath; /** From af073ed9ab54dcefc5d8f3a3ff80b1906d970157 Mon Sep 17 00:00:00 2001 From: Abhinay Agarwal Date: Mon, 21 Sep 2020 17:22:08 +0530 Subject: [PATCH 07/24] Changes as per review --- README.md | 4 ++- src/main/java/org/openjfx/JavaFXBaseMojo.java | 19 +++++++---- src/main/java/org/openjfx/JavaFXRunMojo.java | 9 +++-- .../java/org/openjfx/model/RuntimePath.java | 24 -------------- .../org/openjfx/model/RuntimePathOption.java | 33 +++++++++++++++++++ 5 files changed, 52 insertions(+), 37 deletions(-) delete mode 100644 src/main/java/org/openjfx/model/RuntimePath.java create mode 100644 src/main/java/org/openjfx/model/RuntimePathOption.java diff --git a/README.md b/README.md index eaf6bdb..9ecf2d5 100644 --- a/README.md +++ b/README.md @@ -130,7 +130,9 @@ Optionally, the configuration can be modified with: dependencies that generate path exceptions in the classpath. By default, the value is false, and these dependencies won't be included. - `jlinkOptions`: A list of options passed to the jlink executable. -- `runtimePath`: Allows to run the application by adding all the dependencies on either classpath or modulepath. +- `runtimePathOption`: Allows to run the application by adding all the dependencies on either classpath or modulepath. +A [Launcher class](https://github.com/openjfx/samples/blob/master/CommandLine/Non-modular/CLI/hellofx/src/hellofx/Launcher.java) +is required to run a JavaFX application from the classpath. Values: MODULEPATH or CLASSPATH. For instance, the following configuration adds some VM options, and a command line argument: diff --git a/src/main/java/org/openjfx/JavaFXBaseMojo.java b/src/main/java/org/openjfx/JavaFXBaseMojo.java index 60a597b..41225b7 100644 --- a/src/main/java/org/openjfx/JavaFXBaseMojo.java +++ b/src/main/java/org/openjfx/JavaFXBaseMojo.java @@ -39,7 +39,7 @@ import org.codehaus.plexus.languages.java.jpms.ResolvePathsResult; import org.codehaus.plexus.util.StringUtils; import org.codehaus.plexus.util.cli.CommandLineUtils; -import org.openjfx.model.RuntimePath; +import org.openjfx.model.RuntimePathOption; import java.io.BufferedOutputStream; import java.io.File; @@ -61,8 +61,8 @@ import java.util.stream.Collectors; import java.util.stream.Stream; -import static org.openjfx.model.RuntimePath.CLASSPATH; -import static org.openjfx.model.RuntimePath.MODULEPATH; +import static org.openjfx.model.RuntimePathOption.CLASSPATH; +import static org.openjfx.model.RuntimePathOption.MODULEPATH; abstract class JavaFXBaseMojo extends AbstractMojo { @@ -95,8 +95,11 @@ abstract class JavaFXBaseMojo extends AbstractMojo { @Parameter(readonly = true, required = true, defaultValue = "${project.build.directory}") File builddir; - @Parameter(property = "javafx.runtimePath") - RuntimePath runtimePath; + /** + * Type of {@link RuntimePathOption} to run the application. + */ + @Parameter(property = "javafx.runtimePathOption") + RuntimePathOption runtimePathOption; /** * The current working directory. Optional. If not specified, basedir will be used. @@ -275,7 +278,8 @@ void preparePaths(Path jdkHome) throws MojoExecutionException { getLog().warn(e.getMessage()); } - if (runtimePath == MODULEPATH) { + if (runtimePathOption == MODULEPATH) { + getLog().debug(runtimePathOption + " runtimePathOption set by user. Moving all jars to modulepath."); if (moduleDescriptor == null) { // target/classes should still be on classpath final List classpathJars = classpathElements.stream() @@ -287,7 +291,8 @@ void preparePaths(Path jdkHome) throws MojoExecutionException { modulepathElements.addAll(classpathElements); classpathElements.clear(); } - } else if (runtimePath == CLASSPATH) { + } else if (runtimePathOption == CLASSPATH) { + getLog().debug(runtimePathOption + " runtimePathOption set by user. Moving all jars to classpath."); classpathElements.addAll(modulepathElements); modulepathElements.clear(); } diff --git a/src/main/java/org/openjfx/JavaFXRunMojo.java b/src/main/java/org/openjfx/JavaFXRunMojo.java index 2ae2da2..c890436 100644 --- a/src/main/java/org/openjfx/JavaFXRunMojo.java +++ b/src/main/java/org/openjfx/JavaFXRunMojo.java @@ -38,11 +38,10 @@ import java.util.List; import java.util.Map; import java.util.Objects; -import java.util.regex.Pattern; import java.util.stream.Collectors; -import static org.openjfx.model.RuntimePath.CLASSPATH; -import static org.openjfx.model.RuntimePath.MODULEPATH; +import static org.openjfx.model.RuntimePathOption.CLASSPATH; +import static org.openjfx.model.RuntimePathOption.MODULEPATH; @Mojo(name = "run", requiresDependencyResolution = ResolutionScope.RUNTIME) @Execute(phase = LifecyclePhase.PROCESS_CLASSES) @@ -137,7 +136,7 @@ private List createCommandArguments(boolean oldJDK) throws MojoExecution .forEach(commandArguments::add); } if (!oldJDK) { - if (runtimePath == MODULEPATH || modulepathElements != null && !modulepathElements.isEmpty()) { + if (runtimePathOption == MODULEPATH || modulepathElements != null && !modulepathElements.isEmpty()) { commandArguments.add(" --module-path"); String modulePath = StringUtils.join(modulepathElements.iterator(), File.pathSeparator); commandArguments.add(modulePath); @@ -157,7 +156,7 @@ private List createCommandArguments(boolean oldJDK) throws MojoExecution } } - if (runtimePath == CLASSPATH || classpathElements != null && (oldJDK || !classpathElements.isEmpty())) { + if (runtimePathOption == CLASSPATH || classpathElements != null && (oldJDK || !classpathElements.isEmpty())) { commandArguments.add(" -classpath"); String classpath = ""; if (oldJDK || moduleDescriptor != null) { diff --git a/src/main/java/org/openjfx/model/RuntimePath.java b/src/main/java/org/openjfx/model/RuntimePath.java deleted file mode 100644 index d610a50..0000000 --- a/src/main/java/org/openjfx/model/RuntimePath.java +++ /dev/null @@ -1,24 +0,0 @@ -/* - * Copyright 2020, Gluon - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.openjfx.model; - -/** - * Types of RuntimePath - */ -public enum RuntimePath { - CLASSPATH, - MODULEPATH -} diff --git a/src/main/java/org/openjfx/model/RuntimePathOption.java b/src/main/java/org/openjfx/model/RuntimePathOption.java new file mode 100644 index 0000000..546ad65 --- /dev/null +++ b/src/main/java/org/openjfx/model/RuntimePathOption.java @@ -0,0 +1,33 @@ +/* + * Copyright 2020, Gluon + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.openjfx.model; + +/** + * All the classes and dependencies are added to either the classpath or modulepath depending on the option set in the plugin configuration. + * If not set, the plugin chooses the suitable option for classes and dependencies based on a few parameters, like presence of module descriptor file. + */ +public enum RuntimePathOption { + /** + * Puts all the dependencies on the classpath. If a module-info.java is present, it is ignored. + * A Launcher class is + * required to run a JavaFX application from the classpath. + */ + CLASSPATH, + /** + * Puts all the dependencies on the modulepath. + */ + MODULEPATH +} From 54e5682b2aa57d9566159d97fadeebbc09ccd6e0 Mon Sep 17 00:00:00 2001 From: Abhinay Agarwal Date: Mon, 21 Sep 2020 18:22:01 +0530 Subject: [PATCH 08/24] Refactor JavaFXRunMojo --- src/main/java/org/openjfx/JavaFXRunMojo.java | 50 ++++++++++---------- 1 file changed, 26 insertions(+), 24 deletions(-) diff --git a/src/main/java/org/openjfx/JavaFXRunMojo.java b/src/main/java/org/openjfx/JavaFXRunMojo.java index c890436..52a91d7 100644 --- a/src/main/java/org/openjfx/JavaFXRunMojo.java +++ b/src/main/java/org/openjfx/JavaFXRunMojo.java @@ -138,28 +138,16 @@ private List createCommandArguments(boolean oldJDK) throws MojoExecution if (!oldJDK) { if (runtimePathOption == MODULEPATH || modulepathElements != null && !modulepathElements.isEmpty()) { commandArguments.add(" --module-path"); - String modulePath = StringUtils.join(modulepathElements.iterator(), File.pathSeparator); - commandArguments.add(modulePath); - + commandArguments.add(StringUtils.join(modulepathElements.iterator(), File.pathSeparator)); commandArguments.add(" --add-modules"); - if (moduleDescriptor != null) { - commandArguments.add(" " + moduleDescriptor.name()); - } else { - String modules = pathElements.values().stream() - .filter(Objects::nonNull) - .map(JavaModuleDescriptor::name) - .filter(Objects::nonNull) - .filter(module -> module.startsWith(JAVAFX_PREFIX) && !module.endsWith("Empty")) - .collect(Collectors.joining(",")); - commandArguments.add(" " + modules); - } + commandArguments.add(createAddModulesString(moduleDescriptor, pathElements)); } } - if (runtimePathOption == CLASSPATH || classpathElements != null && (oldJDK || !classpathElements.isEmpty())) { + if (classpathElements != null && !classpathElements.isEmpty()) { commandArguments.add(" -classpath"); String classpath = ""; - if (oldJDK || moduleDescriptor != null) { + if (oldJDK || runtimePathOption == CLASSPATH) { classpath = project.getBuild().getOutputDirectory() + File.pathSeparator; } classpath += StringUtils.join(classpathElements.iterator(), File.pathSeparator); @@ -168,15 +156,9 @@ private List createCommandArguments(boolean oldJDK) throws MojoExecution if (mainClass != null) { if (moduleDescriptor != null) { - commandArguments.add(" --module"); - if (!mainClass.startsWith(moduleDescriptor.name() + "/")) { - commandArguments.add(" " + moduleDescriptor.name() + "/" + mainClass); - } else { - commandArguments.add(" " + mainClass); - } - } else { - commandArguments.add(" " + mainClass); + commandArguments.add("--module"); } + commandArguments.add(" " + createMainClassString(mainClass, moduleDescriptor)); } if (commandlineArgs != null) { @@ -185,6 +167,26 @@ private List createCommandArguments(boolean oldJDK) throws MojoExecution return commandArguments; } + private String createAddModulesString(JavaModuleDescriptor moduleDescriptor, Map pathElements) { + if (moduleDescriptor == null) { + return pathElements.values().stream() + .filter(Objects::nonNull) + .map(JavaModuleDescriptor::name) + .filter(Objects::nonNull) + .filter(module -> module.startsWith(JAVAFX_PREFIX) && !module.endsWith("Empty")) + .collect(Collectors.joining(",")); + } + return moduleDescriptor.name(); + } + + private String createMainClassString(String mainClass, JavaModuleDescriptor moduleDescriptor) { + if (moduleDescriptor != null && + !mainClass.startsWith(moduleDescriptor.name() + "/")) { + return moduleDescriptor.name() + "/" + mainClass; + } + return mainClass; + } + // for tests void setExecutable(String executable) { From 22b7c01f492093e12d95a61d3ee079d1bcfb857a Mon Sep 17 00:00:00 2001 From: Abhinay Agarwal Date: Mon, 21 Sep 2020 18:25:51 +0530 Subject: [PATCH 09/24] Remove unnecessary leading space in entries --- src/main/java/org/openjfx/JavaFXRunMojo.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/java/org/openjfx/JavaFXRunMojo.java b/src/main/java/org/openjfx/JavaFXRunMojo.java index 52a91d7..6e196e0 100644 --- a/src/main/java/org/openjfx/JavaFXRunMojo.java +++ b/src/main/java/org/openjfx/JavaFXRunMojo.java @@ -137,15 +137,15 @@ private List createCommandArguments(boolean oldJDK) throws MojoExecution } if (!oldJDK) { if (runtimePathOption == MODULEPATH || modulepathElements != null && !modulepathElements.isEmpty()) { - commandArguments.add(" --module-path"); + commandArguments.add("--module-path"); commandArguments.add(StringUtils.join(modulepathElements.iterator(), File.pathSeparator)); - commandArguments.add(" --add-modules"); + commandArguments.add("--add-modules"); commandArguments.add(createAddModulesString(moduleDescriptor, pathElements)); } } if (classpathElements != null && !classpathElements.isEmpty()) { - commandArguments.add(" -classpath"); + commandArguments.add("-classpath"); String classpath = ""; if (oldJDK || runtimePathOption == CLASSPATH) { classpath = project.getBuild().getOutputDirectory() + File.pathSeparator; From b3c891f1c8f6a1a486f19a584fd462ae733bf044 Mon Sep 17 00:00:00 2001 From: Abhinay Agarwal Date: Mon, 21 Sep 2020 19:40:51 +0530 Subject: [PATCH 10/24] Ignore module-info.java file if runtimePathOption is set as CLASSPATH --- README.md | 4 ++-- src/main/java/org/openjfx/JavaFXBaseMojo.java | 16 ++++++++++++++-- 2 files changed, 16 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 9ecf2d5..aef067e 100644 --- a/README.md +++ b/README.md @@ -131,8 +131,8 @@ dependencies that generate path exceptions in the classpath. By default, the val won't be included. - `jlinkOptions`: A list of options passed to the jlink executable. - `runtimePathOption`: Allows to run the application by adding all the dependencies on either classpath or modulepath. -A [Launcher class](https://github.com/openjfx/samples/blob/master/CommandLine/Non-modular/CLI/hellofx/src/hellofx/Launcher.java) -is required to run a JavaFX application from the classpath. +If set as CLASSPATH, a [Launcher class](https://github.com/openjfx/samples/blob/master/CommandLine/Non-modular/CLI/hellofx/src/hellofx/Launcher.java) +is required to run a JavaFX application. Also, if a module-info.java is present, it will be ignored. Values: MODULEPATH or CLASSPATH. For instance, the following configuration adds some VM options, and a command line argument: diff --git a/src/main/java/org/openjfx/JavaFXBaseMojo.java b/src/main/java/org/openjfx/JavaFXBaseMojo.java index 41225b7..8fd48c1 100644 --- a/src/main/java/org/openjfx/JavaFXBaseMojo.java +++ b/src/main/java/org/openjfx/JavaFXBaseMojo.java @@ -212,7 +212,7 @@ void preparePaths(Path jdkHome) throws MojoExecutionException { getLog().debug("Total dependencyArtifacts: " + dependencyArtifacts.size()); ResolvePathsRequest fileResolvePathsRequest = ResolvePathsRequest.ofFiles(dependencyArtifacts); - getLog().debug("module descriptor: " + moduleDescriptorPath); + getLog().debug("module descriptor path: " + moduleDescriptorPath); if (moduleDescriptorPath != null) { fileResolvePathsRequest.setMainModuleDescriptor(moduleDescriptorPath); } @@ -222,6 +222,10 @@ void preparePaths(Path jdkHome) throws MojoExecutionException { ResolvePathsResult resolvePathsResult = locationManager.resolvePaths(fileResolvePathsRequest); resolvePathsResult.getPathElements().forEach((key, value) -> pathElements.put(key.getPath(), value)); + if (runtimePathOption == MODULEPATH && moduleDescriptorPath == null) { + throw new MojoExecutionException("module-info.java file is required for MODULEPATH runtimePathOption"); + } + if (moduleDescriptorPath != null) { if (!resolvePathsResult.getPathExceptions().isEmpty() && !isMavenUsingJava8()) { // for each path exception, show a warning to plugin user... @@ -240,7 +244,7 @@ void preparePaths(Path jdkHome) throws MojoExecutionException { " 'includePathExceptionsInClasspath' configuration parameter."); } } - moduleDescriptor = resolvePathsResult.getMainModuleDescriptor(); + moduleDescriptor = createModuleDescriptor(resolvePathsResult); for (Map.Entry entry : resolvePathsResult.getModulepathElements().entrySet()) { if (ModuleNameSource.FILENAME.equals(entry.getValue())) { final String message = "Required filename-based automodules detected. " @@ -307,6 +311,14 @@ void preparePaths(Path jdkHome) throws MojoExecutionException { pathElements.forEach((k, v) -> getLog().debug(" " + k + " :: " + (v != null && v.name() != null ? v.name() : v))); } + private JavaModuleDescriptor createModuleDescriptor(ResolvePathsResult resolvePathsResult) throws MojoExecutionException { + if (runtimePathOption == CLASSPATH) { + getLog().debug(CLASSPATH + " runtimePathOption set by user. module-info.java will be ignored."); + return null; + } + return resolvePathsResult.getMainModuleDescriptor(); + } + private List getCompileClasspathElements(MavenProject project) { List list = new ArrayList<>(); list.add(new File(project.getBuild().getOutputDirectory())); From 87970cce24baaeb41b92b9fe5998b66559eb789d Mon Sep 17 00:00:00 2001 From: Abhinay Agarwal Date: Mon, 5 Oct 2020 16:01:53 +0530 Subject: [PATCH 11/24] Update README.md --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index aef067e..252638f 100644 --- a/README.md +++ b/README.md @@ -129,10 +129,9 @@ Optionally, the configuration can be modified with: - `includePathExceptionsInClasspath`: When resolving the module-path, setting this value to true will include the dependencies that generate path exceptions in the classpath. By default, the value is false, and these dependencies won't be included. -- `jlinkOptions`: A list of options passed to the jlink executable. - `runtimePathOption`: Allows to run the application by adding all the dependencies on either classpath or modulepath. -If set as CLASSPATH, a [Launcher class](https://github.com/openjfx/samples/blob/master/CommandLine/Non-modular/CLI/hellofx/src/hellofx/Launcher.java) -is required to run a JavaFX application. Also, if a module-info.java is present, it will be ignored. +If set as CLASSPATH, a Launcher class ([like this one](https://github.com/openjfx/samples/blob/master/CommandLine/Non-modular/CLI/hellofx/src/hellofx/Launcher.java)) +is required to run a JavaFX application. Also, if a module-info descriptor is present, it will be ignored. Values: MODULEPATH or CLASSPATH. For instance, the following configuration adds some VM options, and a command line argument: @@ -189,6 +188,7 @@ The same command line options for `jlink` can be set: - `bindServices`: Adds the option to bind services. Values: false (default) or true - `ignoreSigningInformation`: Adds the option to ignore signing information. Values: false (default) or true - `jlinkVerbose`: Adds the verbose option. Values: false (default) or true +- `jlinkOptions`: A list of options passed to the jlink executable. - `launcher`: Adds a launcher script with the given name. - If `options` are defined, these will be passed to the launcher script as vm options. - If `commandLineArgs` are defined, these will be passed to the launcher script as command line arguments. From 217c0c07c72c4d786f65409b465d3b0a3c1a1aad Mon Sep 17 00:00:00 2001 From: Abhinay Agarwal Date: Wed, 7 Oct 2020 11:06:27 +0530 Subject: [PATCH 12/24] Add check for Application class --- src/main/java/org/openjfx/JavaFXBaseMojo.java | 36 +++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/src/main/java/org/openjfx/JavaFXBaseMojo.java b/src/main/java/org/openjfx/JavaFXBaseMojo.java index 8fd48c1..8440eed 100644 --- a/src/main/java/org/openjfx/JavaFXBaseMojo.java +++ b/src/main/java/org/openjfx/JavaFXBaseMojo.java @@ -25,6 +25,7 @@ import org.apache.commons.exec.PumpStreamHandler; import org.apache.commons.exec.ShutdownHookProcessDestroyer; import org.apache.maven.artifact.Artifact; +import org.apache.maven.artifact.DependencyResolutionRequiredException; import org.apache.maven.execution.MavenSession; import org.apache.maven.plugin.AbstractMojo; import org.apache.maven.plugin.BuildPluginManager; @@ -46,6 +47,9 @@ import java.io.FileOutputStream; import java.io.IOException; import java.io.OutputStream; +import java.net.MalformedURLException; +import java.net.URL; +import java.net.URLClassLoader; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; @@ -66,6 +70,7 @@ abstract class JavaFXBaseMojo extends AbstractMojo { + private static final String JAVAFX_APPLICATION_CLASS_NAME = "javafx.application.Application"; static final String JAVAFX_PREFIX = "javafx"; @Parameter(defaultValue = "${project}", readonly = true) @@ -299,6 +304,9 @@ void preparePaths(Path jdkHome) throws MojoExecutionException { getLog().debug(runtimePathOption + " runtimePathOption set by user. Moving all jars to classpath."); classpathElements.addAll(modulepathElements); modulepathElements.clear(); + if (doesExtendFXApplication(mainClass)) { + throw new MojoExecutionException("Launcher class is required. Main-class cannot extend Application when running JavaFX application on CLASSPATH"); + } } getLog().debug("Classpath:" + classpathElements.size()); @@ -585,4 +593,32 @@ private ProcessDestroyer getProcessDestroyer() { } return processDestroyer; } + + private boolean doesExtendFXApplication(String mainClass) { + boolean fxApplication = false; + try { + List pathUrls = new ArrayList<>(); + for (String path : project.getCompileClasspathElements()) { + pathUrls.add(new File(path).toURI().toURL()); + } + URL[] urls = pathUrls.toArray(new URL[0]); + URLClassLoader classLoader = new URLClassLoader(urls, JavaFXBaseMojo.class.getClassLoader()); + Class clazz = Class.forName(mainClass, false, classLoader); + fxApplication = doesExtendFXApplication(clazz); + getLog().info("app for " + clazz.toString() + " extends Application: " + fxApplication); + } catch (NoClassDefFoundError | ClassNotFoundException | DependencyResolutionRequiredException | MalformedURLException e) { + getLog().debug(e); + } + return fxApplication; + } + + private static boolean doesExtendFXApplication(Class mainClass) { + for (Class sc = mainClass.getSuperclass(); sc != null; + sc = sc.getSuperclass()) { + if (sc.getName().equals(JAVAFX_APPLICATION_CLASS_NAME)) { + return true; + } + } + return false; + } } From 9c67ae04faf27064579233b14b110ba76dcb1457 Mon Sep 17 00:00:00 2001 From: Abhinay Agarwal Date: Wed, 7 Oct 2020 12:38:25 +0530 Subject: [PATCH 13/24] Add tests for CLASSPATH runtimePathOption --- .../org/openjfx/JavaFXRunMojoTestCase.java | 35 +++++++++++--- src/test/java/org/openjfx/TestLauncher.java | 22 +++++++++ .../classpath-launcher.xml | 48 +++++++++++++++++++ .../classpath-no-launcher.xml | 48 +++++++++++++++++++ 4 files changed, 147 insertions(+), 6 deletions(-) create mode 100644 src/test/java/org/openjfx/TestLauncher.java create mode 100755 src/test/resources/unit/javafxrun-classpath-test/classpath-launcher.xml create mode 100755 src/test/resources/unit/javafxrun-classpath-test/classpath-no-launcher.xml diff --git a/src/test/java/org/openjfx/JavaFXRunMojoTestCase.java b/src/test/java/org/openjfx/JavaFXRunMojoTestCase.java index ebeb6b8..3127153 100644 --- a/src/test/java/org/openjfx/JavaFXRunMojoTestCase.java +++ b/src/test/java/org/openjfx/JavaFXRunMojoTestCase.java @@ -27,7 +27,10 @@ import org.apache.maven.plugin.MojoExecutionException; import org.apache.maven.plugin.MojoFailureException; import org.apache.maven.plugin.testing.AbstractMojoTestCase; -import org.apache.maven.project.*; +import org.apache.maven.project.MavenProject; +import org.apache.maven.project.ProjectBuilder; +import org.apache.maven.project.ProjectBuildingRequest; +import org.apache.maven.project.ProjectBuildingResult; import org.apache.maven.repository.RepositorySystem; import org.apache.maven.repository.internal.MavenRepositorySystemUtils; import org.codehaus.plexus.logging.Logger; @@ -102,19 +105,39 @@ public void testRunOK() throws MojoExecutionException { } public void testSimpleRun() throws Exception { - JavaFXRunMojo mojo = getJavaFXRunMojo("target/test-classes/unit/javafxrun-basic-test"); + final File testPom = getTestFile("src/test/resources/unit/javafxrun-basic-test/pom.xml"); + JavaFXRunMojo mojo = getJavaFXRunMojo(testPom); String output = execute(mojo); assertEquals("JavaFXRun0", output.trim()); } public void testApplicationRun() throws Exception { - JavaFXRunMojo mojo = getJavaFXRunMojo("target/test-classes/unit/javafxrun-app-test"); + final File testPom = getTestFile("src/test/resources/unit/javafxrun-app-test/pom.xml"); + JavaFXRunMojo mojo = getJavaFXRunMojo(testPom); String output = execute(mojo); assertEquals("JavaFXRun1", output.trim()); } - protected JavaFXRunMojo getJavaFXRunMojo(String parent) throws Exception { - File testPom = new File(getBasedir(), parent + "/pom.xml"); + public void testClasspathLauncherRun() throws Exception { + final File testPom = getTestFile("src/test/resources/unit/javafxrun-classpath-test/classpath-launcher.xml"); + JavaFXRunMojo mojo = getJavaFXRunMojo(testPom); + String output = execute(mojo); + assertEquals("JavaFXRun1", output.trim()); + } + + public void testClasspathNoLauncherRun() throws Exception { + final File testPom = getTestFile("src/test/resources/unit/javafxrun-classpath-test/classpath-no-launcher.xml"); + JavaFXRunMojo mojo = getJavaFXRunMojo(testPom); + Exception e = null; + try { + execute(mojo); + } catch (Exception e1) { + e = e1; + } + assertEquals (true, (e instanceof MojoExecutionException)); + } + + protected JavaFXRunMojo getJavaFXRunMojo(File testPom) throws Exception { JavaFXRunMojo mojo = (JavaFXRunMojo) lookupMojo("run", testPom); assertNotNull(mojo); @@ -135,7 +158,7 @@ protected JavaFXRunMojo getJavaFXRunMojo(String parent) throws Exception { setVariableValueToObject(mojo, "compilePath", project.getCompileClasspathElements()); setVariableValueToObject(mojo, "session", session); setVariableValueToObject(mojo, "executable", "java"); - setVariableValueToObject(mojo, "basedir", new File(getBasedir(), parent)); + setVariableValueToObject(mojo, "basedir", new File(getBasedir(), testPom.getParent())); return mojo; } diff --git a/src/test/java/org/openjfx/TestLauncher.java b/src/test/java/org/openjfx/TestLauncher.java new file mode 100644 index 0000000..c70fdf7 --- /dev/null +++ b/src/test/java/org/openjfx/TestLauncher.java @@ -0,0 +1,22 @@ +/* + * Copyright 2020, Gluon + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.openjfx; + +public class TestLauncher { + public static void main(String[] args) { + TestJavaFXRun1.main(args); + } +} \ No newline at end of file diff --git a/src/test/resources/unit/javafxrun-classpath-test/classpath-launcher.xml b/src/test/resources/unit/javafxrun-classpath-test/classpath-launcher.xml new file mode 100755 index 0000000..df1f3f1 --- /dev/null +++ b/src/test/resources/unit/javafxrun-classpath-test/classpath-launcher.xml @@ -0,0 +1,48 @@ + + + 4.0.0 + org.openjfx + javafxrun.classpath.launcher.test + 1.0-SNAPSHOT + jar + + UTF-8 + 11 + 11 + 12.0.1 + + + + org.openjfx + javafx-controls + ${javafx.version} + + + + + + org.openjfx + javafx-maven-plugin + 1.0-SNAPSHOT + + org.openjfx.TestLauncher + CLASSPATH + + + + + diff --git a/src/test/resources/unit/javafxrun-classpath-test/classpath-no-launcher.xml b/src/test/resources/unit/javafxrun-classpath-test/classpath-no-launcher.xml new file mode 100755 index 0000000..60d63a4 --- /dev/null +++ b/src/test/resources/unit/javafxrun-classpath-test/classpath-no-launcher.xml @@ -0,0 +1,48 @@ + + + 4.0.0 + org.openjfx + javafxrun.classpath.launcher.test + 1.0-SNAPSHOT + jar + + UTF-8 + 11 + 11 + 12.0.1 + + + + org.openjfx + javafx-controls + ${javafx.version} + + + + + + org.openjfx + javafx-maven-plugin + 1.0-SNAPSHOT + + org.openjfx.TestJavaFXRun1 + CLASSPATH + + + + + From 8f915b16d5db498de6ec1c7df50836293c38d1d5 Mon Sep 17 00:00:00 2001 From: Abhinay Agarwal Date: Wed, 7 Oct 2020 18:06:07 +0530 Subject: [PATCH 14/24] Update JavaFX version in test pom --- .../unit/javafxrun-classpath-test/classpath-launcher.xml | 2 +- .../unit/javafxrun-classpath-test/classpath-no-launcher.xml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/test/resources/unit/javafxrun-classpath-test/classpath-launcher.xml b/src/test/resources/unit/javafxrun-classpath-test/classpath-launcher.xml index df1f3f1..662b67b 100755 --- a/src/test/resources/unit/javafxrun-classpath-test/classpath-launcher.xml +++ b/src/test/resources/unit/javafxrun-classpath-test/classpath-launcher.xml @@ -23,7 +23,7 @@ UTF-8 11 11 - 12.0.1 + 15 diff --git a/src/test/resources/unit/javafxrun-classpath-test/classpath-no-launcher.xml b/src/test/resources/unit/javafxrun-classpath-test/classpath-no-launcher.xml index 60d63a4..a64376f 100755 --- a/src/test/resources/unit/javafxrun-classpath-test/classpath-no-launcher.xml +++ b/src/test/resources/unit/javafxrun-classpath-test/classpath-no-launcher.xml @@ -23,7 +23,7 @@ UTF-8 11 11 - 12.0.1 + 15 From 351a7c60d0d9adf478202de4a227731bc41407fd Mon Sep 17 00:00:00 2001 From: Abhinay Agarwal Date: Wed, 7 Oct 2020 18:30:49 +0530 Subject: [PATCH 15/24] Revert changes made for jlinkOptions --- README.md | 1 - src/main/java/org/openjfx/JavaFXJLinkMojo.java | 17 ----------------- 2 files changed, 18 deletions(-) diff --git a/README.md b/README.md index 252638f..05ca169 100644 --- a/README.md +++ b/README.md @@ -188,7 +188,6 @@ The same command line options for `jlink` can be set: - `bindServices`: Adds the option to bind services. Values: false (default) or true - `ignoreSigningInformation`: Adds the option to ignore signing information. Values: false (default) or true - `jlinkVerbose`: Adds the verbose option. Values: false (default) or true -- `jlinkOptions`: A list of options passed to the jlink executable. - `launcher`: Adds a launcher script with the given name. - If `options` are defined, these will be passed to the launcher script as vm options. - If `commandLineArgs` are defined, these will be passed to the launcher script as command line arguments. diff --git a/src/main/java/org/openjfx/JavaFXJLinkMojo.java b/src/main/java/org/openjfx/JavaFXJLinkMojo.java index ec917d8..04a5a11 100644 --- a/src/main/java/org/openjfx/JavaFXJLinkMojo.java +++ b/src/main/java/org/openjfx/JavaFXJLinkMojo.java @@ -152,12 +152,6 @@ public class JavaFXJLinkMojo extends JavaFXBaseMojo { @Component(role = Archiver.class, hint = "zip") private ZipArchiver zipArchiver; - /** - * A list of options passed to the jlink {@code executable}. - */ - @Parameter - List jlinkOptions; - public void execute() throws MojoExecutionException { if (skip) { getLog().info( "skipping execute as per configuration" ); @@ -296,17 +290,6 @@ private void patchLauncherScript(String launcherFilename) throws IOException { private List createCommandArguments() throws MojoExecutionException, MojoFailureException { List commandArguments = new ArrayList<>(); preparePaths(getParent(Paths.get(jlinkExecutable), 2)); - - if (jlinkOptions != null) { - jlinkOptions.stream() - .filter(Objects::nonNull) - .filter(String.class::isInstance) - .map(String.class::cast) - .map(this::splitComplexArgumentString) - .flatMap(Collection::stream) - .forEach(commandArguments::add); - } - if (modulepathElements != null && !modulepathElements.isEmpty()) { commandArguments.add(" --module-path"); String modulePath = StringUtils.join(modulepathElements.iterator(), File.pathSeparator); From aafdb53b4298926c32fb209eb21c6dd4b7baf5f0 Mon Sep 17 00:00:00 2001 From: Abhinay Agarwal Date: Wed, 7 Oct 2020 18:31:25 +0530 Subject: [PATCH 16/24] Remove unused import --- src/main/java/org/openjfx/JavaFXJLinkMojo.java | 1 - 1 file changed, 1 deletion(-) diff --git a/src/main/java/org/openjfx/JavaFXJLinkMojo.java b/src/main/java/org/openjfx/JavaFXJLinkMojo.java index 04a5a11..ab21c17 100644 --- a/src/main/java/org/openjfx/JavaFXJLinkMojo.java +++ b/src/main/java/org/openjfx/JavaFXJLinkMojo.java @@ -43,7 +43,6 @@ import java.nio.file.Path; import java.nio.file.Paths; import java.util.ArrayList; -import java.util.Collection; import java.util.Comparator; import java.util.List; import java.util.Map; From 9db5fa97f602504db3b432ca62b39f7c385205c7 Mon Sep 17 00:00:00 2001 From: Abhinay Agarwal Date: Wed, 7 Oct 2020 18:58:42 +0530 Subject: [PATCH 17/24] Revert test changes made for jlinkOptions --- src/main/java/org/openjfx/JavaFXBaseMojo.java | 37 ------------------- src/main/java/org/openjfx/JavaFXRunMojo.java | 37 +++++++++++++++++++ .../java/org/openjfx/JavaFXBaseMojoTest.java | 31 ---------------- .../org/openjfx/JavaFXRunMojoTestCase.java | 33 +++++++++++++++++ 4 files changed, 70 insertions(+), 68 deletions(-) diff --git a/src/main/java/org/openjfx/JavaFXBaseMojo.java b/src/main/java/org/openjfx/JavaFXBaseMojo.java index 8440eed..7ac2656 100644 --- a/src/main/java/org/openjfx/JavaFXBaseMojo.java +++ b/src/main/java/org/openjfx/JavaFXBaseMojo.java @@ -61,7 +61,6 @@ import java.util.List; import java.util.Map; import java.util.Properties; -import java.util.regex.Pattern; import java.util.stream.Collectors; import java.util.stream.Stream; @@ -447,42 +446,6 @@ static Path getParent(Path path, int depth) { return path.getRoot().resolve(path.subpath(0, path.getNameCount() - depth)); } - List splitComplexArgumentString(String argumentString) { - char[] strArr = argumentString.trim().toCharArray(); - - List splitedArgs = new ArrayList<>(); - StringBuilder sb = new StringBuilder(); - - char expectedSeparator = ' '; - for (int i = 0; i < strArr.length; i++) { - char item = strArr[i]; - - if (item == expectedSeparator - || (expectedSeparator == ' ' && Pattern.matches("\\s", String.valueOf(item))) ) { - - if (expectedSeparator == '"' || expectedSeparator == '\'') { - sb.append(item); - expectedSeparator = ' '; - } else if (expectedSeparator == ' ' && sb.length() > 0) { - splitedArgs.add(sb.toString()); - sb.delete(0, sb.length()); - } - } else { - if (expectedSeparator == ' ' && (item == '"' || item == '\'')) { - expectedSeparator = item; - } - - sb.append(item); - } - - if (i == strArr.length - 1 && sb.length() > 0) { - splitedArgs.add(sb.toString()); - } - } - - return splitedArgs; - } - private static String findExecutable(final String executable, final List paths) { File f = null; search: for (final String path : paths) { diff --git a/src/main/java/org/openjfx/JavaFXRunMojo.java b/src/main/java/org/openjfx/JavaFXRunMojo.java index cde2ca5..643fd71 100644 --- a/src/main/java/org/openjfx/JavaFXRunMojo.java +++ b/src/main/java/org/openjfx/JavaFXRunMojo.java @@ -38,6 +38,7 @@ import java.util.List; import java.util.Map; import java.util.Objects; +import java.util.regex.Pattern; import java.util.stream.Collectors; import static org.openjfx.model.RuntimePathOption.CLASSPATH; @@ -187,6 +188,42 @@ private String createMainClassString(String mainClass, JavaModuleDescriptor modu return mainClass; } + private List splitComplexArgumentString(String argumentString) { + char[] strArr = argumentString.trim().toCharArray(); + + List splitedArgs = new ArrayList<>(); + StringBuilder sb = new StringBuilder(); + + char expectedSeparator = ' '; + for (int i = 0; i < strArr.length; i++) { + char item = strArr[i]; + + if (item == expectedSeparator + || (expectedSeparator == ' ' && Pattern.matches("\\s", String.valueOf(item))) ) { + + if (expectedSeparator == '"' || expectedSeparator == '\'') { + sb.append(item); + expectedSeparator = ' '; + } else if (expectedSeparator == ' ' && sb.length() > 0) { + splitedArgs.add(sb.toString()); + sb.delete(0, sb.length()); + } + } else { + if (expectedSeparator == ' ' && (item == '"' || item == '\'')) { + expectedSeparator = item; + } + + sb.append(item); + } + + if (i == strArr.length - 1 && sb.length() > 0) { + splitedArgs.add(sb.toString()); + } + } + + return splitedArgs; + } + // for tests void setExecutable(String executable) { diff --git a/src/test/java/org/openjfx/JavaFXBaseMojoTest.java b/src/test/java/org/openjfx/JavaFXBaseMojoTest.java index 54d58c9..3e61757 100644 --- a/src/test/java/org/openjfx/JavaFXBaseMojoTest.java +++ b/src/test/java/org/openjfx/JavaFXBaseMojoTest.java @@ -58,37 +58,6 @@ public void invalidPathWithDepthTest() { Assert.assertNull(JavaFXBaseMojo.getParent(Paths.get("/some-invalid-path"), 2)); } - @Test - public void testSplitComplexArgumentString() { - String option = "param1 " + - "param2 \n " + - "param3\n" + - "param4=\"/path/to/my file.log\" " + - "'var\"foo var\"foo' " + - "'var\"foo' " + - "'var\"foo' " + - "\"foo'var foo'var\" " + - "\"foo'var\" " + - "\"foo'var\""; - - String expected = "START," + - "param1," + - "param2," + - "param3," + - "param4=\"/path/to/my file.log\"," + - "'var\"foo var\"foo'," + - "'var\"foo'," + - "'var\"foo'," + - "\"foo'var foo'var\"," + - "\"foo'var\"," + - "\"foo'var\""; - - String splitedOption = new JavaFXRunMojo().splitComplexArgumentStringAdapter(option) - .stream().reduce("START", (s1, s2) -> s1 + "," + s2); - - Assert.assertEquals(expected, splitedOption); - } - @AfterClass public static void destroy() throws IOException { Files.walk(path.getParent()) diff --git a/src/test/java/org/openjfx/JavaFXRunMojoTestCase.java b/src/test/java/org/openjfx/JavaFXRunMojoTestCase.java index 3127153..e643fce 100644 --- a/src/test/java/org/openjfx/JavaFXRunMojoTestCase.java +++ b/src/test/java/org/openjfx/JavaFXRunMojoTestCase.java @@ -40,6 +40,8 @@ import org.eclipse.aether.artifact.DefaultArtifact; import org.eclipse.aether.internal.impl.SimpleLocalRepositoryManagerFactory; import org.eclipse.aether.repository.LocalRepository; +import org.junit.Assert; +import org.junit.Test; import org.mockito.Mock; import org.mockito.MockitoAnnotations; @@ -229,4 +231,35 @@ private String getCommandLineAsString(CommandLine commandline) { } return result; } + + @Test + public void testSplitComplexArgumentString() { + String option = "param1 " + + "param2 \n " + + "param3\n" + + "param4=\"/path/to/my file.log\" " + + "'var\"foo var\"foo' " + + "'var\"foo' " + + "'var\"foo' " + + "\"foo'var foo'var\" " + + "\"foo'var\" " + + "\"foo'var\""; + + String expected = "START," + + "param1," + + "param2," + + "param3," + + "param4=\"/path/to/my file.log\"," + + "'var\"foo var\"foo'," + + "'var\"foo'," + + "'var\"foo'," + + "\"foo'var foo'var\"," + + "\"foo'var\"," + + "\"foo'var\""; + + String splitedOption = new JavaFXRunMojo().splitComplexArgumentStringAdapter(option) + .stream().reduce("START", (s1, s2) -> s1 + "," + s2); + + Assert.assertEquals(expected, splitedOption); + } } From ff163ca0a81786b0b63263b0e71609a276e8392e Mon Sep 17 00:00:00 2001 From: Abhinay Agarwal Date: Wed, 7 Oct 2020 19:02:28 +0530 Subject: [PATCH 18/24] More reverts --- src/main/java/org/openjfx/JavaFXJLinkMojo.java | 5 +++-- src/test/java/org/openjfx/JavaFXBaseMojoTest.java | 15 --------------- 2 files changed, 3 insertions(+), 17 deletions(-) diff --git a/src/main/java/org/openjfx/JavaFXJLinkMojo.java b/src/main/java/org/openjfx/JavaFXJLinkMojo.java index ab21c17..5eb7587 100644 --- a/src/main/java/org/openjfx/JavaFXJLinkMojo.java +++ b/src/main/java/org/openjfx/JavaFXJLinkMojo.java @@ -1,5 +1,5 @@ /* - * Copyright 2019, 2020, Gluon + * Copyright 2019 Gluon * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -166,7 +166,7 @@ public void execute() throws MojoExecutionException { } handleWorkingDirectory(); - + Map enviro = handleSystemEnvVariables(); CommandLine commandLine = getExecutablePath(jlinkExecutable, enviro, workingDirectory); @@ -182,6 +182,7 @@ public void execute() throws MojoExecutionException { } try { + List commandArguments = createCommandArguments(); String[] args = commandArguments.toArray(new String[commandArguments.size()]); commandLine.addArguments(args, false); diff --git a/src/test/java/org/openjfx/JavaFXBaseMojoTest.java b/src/test/java/org/openjfx/JavaFXBaseMojoTest.java index 3e61757..0f1a70a 100644 --- a/src/test/java/org/openjfx/JavaFXBaseMojoTest.java +++ b/src/test/java/org/openjfx/JavaFXBaseMojoTest.java @@ -1,18 +1,3 @@ -/* - * Copyright 2019, 2020, Gluon - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ package org.openjfx; import org.junit.AfterClass; From 319d8789459cfd6fc368ef0fbbaf2db4d1fce533 Mon Sep 17 00:00:00 2001 From: Abhinay Agarwal Date: Thu, 8 Oct 2020 01:53:12 +0530 Subject: [PATCH 19/24] Ignore module-name from mainClass if runtimePathOption is CLASSPATH --- src/main/java/org/openjfx/JavaFXBaseMojo.java | 17 +++++- src/main/java/org/openjfx/JavaFXRunMojo.java | 22 ++------ .../java/org/openjfx/JavaFXBaseMojoTest.java | 54 +++++++++++++++++++ 3 files changed, 73 insertions(+), 20 deletions(-) diff --git a/src/main/java/org/openjfx/JavaFXBaseMojo.java b/src/main/java/org/openjfx/JavaFXBaseMojo.java index 7ac2656..3297ca4 100644 --- a/src/main/java/org/openjfx/JavaFXBaseMojo.java +++ b/src/main/java/org/openjfx/JavaFXBaseMojo.java @@ -303,7 +303,7 @@ void preparePaths(Path jdkHome) throws MojoExecutionException { getLog().debug(runtimePathOption + " runtimePathOption set by user. Moving all jars to classpath."); classpathElements.addAll(modulepathElements); modulepathElements.clear(); - if (doesExtendFXApplication(mainClass)) { + if (doesExtendFXApplication(createMainClassString(mainClass, moduleDescriptor, runtimePathOption))) { throw new MojoExecutionException("Launcher class is required. Main-class cannot extend Application when running JavaFX application on CLASSPATH"); } } @@ -446,6 +446,21 @@ static Path getParent(Path path, int depth) { return path.getRoot().resolve(path.subpath(0, path.getNameCount() - depth)); } + String createMainClassString(String mainClass, JavaModuleDescriptor moduleDescriptor, RuntimePathOption runtimePathOption) { + if (runtimePathOption == CLASSPATH) { + if (mainClass.contains("/")) { + getLog().warn("Main module found in with runtimePathOption set as CLASSPATH. Module name will be ignored."); + return mainClass.substring(mainClass.indexOf("/") + 1); + } + return mainClass; + } + if (moduleDescriptor != null && !mainClass.contains("/")) { + getLog().warn("Main module name not found in . Module name will be assumed from module-info.java"); + return moduleDescriptor.name() + "/" + mainClass; + } + return mainClass; + } + private static String findExecutable(final String executable, final List paths) { File f = null; search: for (final String path : paths) { diff --git a/src/main/java/org/openjfx/JavaFXRunMojo.java b/src/main/java/org/openjfx/JavaFXRunMojo.java index 643fd71..8d12d4d 100644 --- a/src/main/java/org/openjfx/JavaFXRunMojo.java +++ b/src/main/java/org/openjfx/JavaFXRunMojo.java @@ -20,11 +20,7 @@ import org.apache.commons.exec.ExecuteException; import org.apache.commons.exec.Executor; import org.apache.maven.plugin.MojoExecutionException; -import org.apache.maven.plugins.annotations.Execute; -import org.apache.maven.plugins.annotations.LifecyclePhase; -import org.apache.maven.plugins.annotations.Mojo; -import org.apache.maven.plugins.annotations.Parameter; -import org.apache.maven.plugins.annotations.ResolutionScope; +import org.apache.maven.plugins.annotations.*; import org.codehaus.plexus.languages.java.jpms.JavaModuleDescriptor; import org.codehaus.plexus.util.IOUtil; import org.codehaus.plexus.util.StringUtils; @@ -33,11 +29,7 @@ import java.io.FileOutputStream; import java.io.IOException; import java.nio.file.Paths; -import java.util.ArrayList; -import java.util.Collection; -import java.util.List; -import java.util.Map; -import java.util.Objects; +import java.util.*; import java.util.regex.Pattern; import java.util.stream.Collectors; @@ -159,7 +151,7 @@ private List createCommandArguments(boolean oldJDK) throws MojoExecution if (moduleDescriptor != null) { commandArguments.add("--module"); } - commandArguments.add(createMainClassString(mainClass, moduleDescriptor)); + commandArguments.add(createMainClassString(mainClass, moduleDescriptor, runtimePathOption)); } if (commandlineArgs != null) { @@ -180,14 +172,6 @@ private String createAddModulesString(JavaModuleDescriptor moduleDescriptor, Map return moduleDescriptor.name(); } - private String createMainClassString(String mainClass, JavaModuleDescriptor moduleDescriptor) { - if (moduleDescriptor != null && !mainClass.contains("/")) { - getLog().warn("Main module name not found in . Module name will be assumed from module-info.java"); - return moduleDescriptor.name() + "/" + mainClass; - } - return mainClass; - } - private List splitComplexArgumentString(String argumentString) { char[] strArr = argumentString.trim().toCharArray(); diff --git a/src/test/java/org/openjfx/JavaFXBaseMojoTest.java b/src/test/java/org/openjfx/JavaFXBaseMojoTest.java index 0f1a70a..057d4e4 100644 --- a/src/test/java/org/openjfx/JavaFXBaseMojoTest.java +++ b/src/test/java/org/openjfx/JavaFXBaseMojoTest.java @@ -1,7 +1,9 @@ package org.openjfx; +import org.codehaus.plexus.languages.java.jpms.JavaModuleDescriptor; import org.junit.AfterClass; import org.junit.Assert; +import org.junit.Before; import org.junit.BeforeClass; import org.junit.Test; @@ -12,10 +14,16 @@ import java.nio.file.Paths; import java.util.Comparator; +import static org.openjfx.model.RuntimePathOption.CLASSPATH; +import static org.openjfx.model.RuntimePathOption.MODULEPATH; + public class JavaFXBaseMojoTest { private static Path path; private static String tempDirPath; + + private JavaFXBaseMojo mojo; + private JavaModuleDescriptor moduleDescriptor; @BeforeClass public static void setup() throws IOException { @@ -23,11 +31,57 @@ public static void setup() throws IOException { path = Files.createDirectories(Paths.get(tempDirPath, "test", "test")); } + @Before + public void create() { + mojo = new JavaFXBaseMojo() { + @Override + public void execute() { + //no-op + } + }; + moduleDescriptor = JavaModuleDescriptor.newModule("hellofx").build(); + } + @Test public void parentTest() { Assert.assertEquals(Paths.get(tempDirPath), JavaFXBaseMojo.getParent(path, 2)); } + @Test + public void mainClassStringWithModuleDescriptor() { + Assert.assertEquals("hellofx/org.openjfx.Main", mojo.createMainClassString("org.openjfx.Main", moduleDescriptor, null)); + } + + @Test + public void mainClassStringWithoutModuleDescriptor() { + Assert.assertEquals("org.openjfx.Main", mojo.createMainClassString("org.openjfx.Main", null, null)); + Assert.assertEquals("hellofx/org.openjfx.Main", mojo.createMainClassString("hellofx/org.openjfx.Main", null, null)); + } + + @Test + public void mainClassStringWithClasspathWithModuleDescriptor() { + Assert.assertEquals("org.openjfx.Main", mojo.createMainClassString("org.openjfx.Main", moduleDescriptor, CLASSPATH)); + Assert.assertEquals("org.openjfx.Main", mojo.createMainClassString("hellofx/org.openjfx.Main", moduleDescriptor, CLASSPATH)); + } + + @Test + public void mainClassStringWithClasspathWithoutModuleDescriptor() { + Assert.assertEquals("org.openjfx.Main", mojo.createMainClassString("org.openjfx.Main", null, CLASSPATH)); + Assert.assertEquals("org.openjfx.Main", mojo.createMainClassString("hellofx/org.openjfx.Main", null, CLASSPATH)); + } + + @Test + public void mainClassStringWithModulepathWithModuleDescriptor() { + Assert.assertEquals("hellofx/org.openjfx.Main", mojo.createMainClassString("org.openjfx.Main", moduleDescriptor, MODULEPATH)); + Assert.assertEquals("hellofx/org.openjfx.Main", mojo.createMainClassString("hellofx/org.openjfx.Main", moduleDescriptor, MODULEPATH)); + } + + @Test + public void mainClassStringWithModulepathWithoutModuleDescriptor() { + Assert.assertEquals("org.openjfx.Main", mojo.createMainClassString("org.openjfx.Main", null, MODULEPATH)); + Assert.assertEquals("hellofx/org.openjfx.Main", mojo.createMainClassString("hellofx/org.openjfx.Main", null, MODULEPATH)); + } + @Test public void invalidParentTest() { Assert.assertNull(JavaFXBaseMojo.getParent(path, 10)); From ebcdee17c9886a0e7e6cd56eb07ec9319fb6fa5f Mon Sep 17 00:00:00 2001 From: Abhinay Agarwal Date: Thu, 8 Oct 2020 23:34:43 +0530 Subject: [PATCH 20/24] Changes as per review --- src/main/java/org/openjfx/JavaFXBaseMojo.java | 6 ++++-- src/main/java/org/openjfx/JavaFXRunMojo.java | 12 ++++++++++-- 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/src/main/java/org/openjfx/JavaFXBaseMojo.java b/src/main/java/org/openjfx/JavaFXBaseMojo.java index 3297ca4..1da3eab 100644 --- a/src/main/java/org/openjfx/JavaFXBaseMojo.java +++ b/src/main/java/org/openjfx/JavaFXBaseMojo.java @@ -60,6 +60,7 @@ import java.util.LinkedHashMap; import java.util.List; import java.util.Map; +import java.util.Objects; import java.util.Properties; import java.util.stream.Collectors; import java.util.stream.Stream; @@ -447,15 +448,16 @@ static Path getParent(Path path, int depth) { } String createMainClassString(String mainClass, JavaModuleDescriptor moduleDescriptor, RuntimePathOption runtimePathOption) { + Objects.requireNonNull(mainClass, "Main class cannot be null"); if (runtimePathOption == CLASSPATH) { if (mainClass.contains("/")) { - getLog().warn("Main module found in with runtimePathOption set as CLASSPATH. Module name will be ignored."); + getLog().warn("Module name found in with runtimePathOption set as CLASSPATH. Module name will be ignored."); return mainClass.substring(mainClass.indexOf("/") + 1); } return mainClass; } if (moduleDescriptor != null && !mainClass.contains("/")) { - getLog().warn("Main module name not found in . Module name will be assumed from module-info.java"); + getLog().warn("Module name not found in . Module name will be assumed from module-info.java"); return moduleDescriptor.name() + "/" + mainClass; } return mainClass; diff --git a/src/main/java/org/openjfx/JavaFXRunMojo.java b/src/main/java/org/openjfx/JavaFXRunMojo.java index 8d12d4d..7970d5d 100644 --- a/src/main/java/org/openjfx/JavaFXRunMojo.java +++ b/src/main/java/org/openjfx/JavaFXRunMojo.java @@ -20,7 +20,11 @@ import org.apache.commons.exec.ExecuteException; import org.apache.commons.exec.Executor; import org.apache.maven.plugin.MojoExecutionException; -import org.apache.maven.plugins.annotations.*; +import org.apache.maven.plugins.annotations.Execute; +import org.apache.maven.plugins.annotations.LifecyclePhase; +import org.apache.maven.plugins.annotations.Mojo; +import org.apache.maven.plugins.annotations.Parameter; +import org.apache.maven.plugins.annotations.ResolutionScope; import org.codehaus.plexus.languages.java.jpms.JavaModuleDescriptor; import org.codehaus.plexus.util.IOUtil; import org.codehaus.plexus.util.StringUtils; @@ -29,7 +33,11 @@ import java.io.FileOutputStream; import java.io.IOException; import java.nio.file.Paths; -import java.util.*; +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import java.util.Map; +import java.util.Objects; import java.util.regex.Pattern; import java.util.stream.Collectors; From e9835f86fdd2ed33391e907bff3a45bd72ad6c59 Mon Sep 17 00:00:00 2001 From: Abhinay Agarwal Date: Fri, 9 Oct 2020 09:11:57 +0530 Subject: [PATCH 21/24] Update README.md --- README.md | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 05ca169..b3cede9 100644 --- a/README.md +++ b/README.md @@ -129,12 +129,18 @@ Optionally, the configuration can be modified with: - `includePathExceptionsInClasspath`: When resolving the module-path, setting this value to true will include the dependencies that generate path exceptions in the classpath. By default, the value is false, and these dependencies won't be included. -- `runtimePathOption`: Allows to run the application by adding all the dependencies on either classpath or modulepath. -If set as CLASSPATH, a Launcher class ([like this one](https://github.com/openjfx/samples/blob/master/CommandLine/Non-modular/CLI/hellofx/src/hellofx/Launcher.java)) +- `runtimePathOption`: The default behaviour of the plugin is to place the dependencies either on +modulepath or classpath depending on various factors. For example, if a dependency contains module descriptor or Automatic-Module-Name +it will be placed on the module-path. `runtimePathOption` configuration allows to run the application by placing all the dependencies on either classpath or modulepath. + + If set as `CLASSPATH`, a Launcher class ([like this one](https://github.com/openjfx/samples/blob/master/CommandLine/Non-modular/CLI/hellofx/src/hellofx/Launcher.java)) is required to run a JavaFX application. Also, if a module-info descriptor is present, it will be ignored. -Values: MODULEPATH or CLASSPATH. -For instance, the following configuration adds some VM options, and a command line argument: + Values: MODULEPATH or CLASSPATH. + +### Example + +The following configuration adds some VM options, and a command line argument: ``` From 8ba1c15eaf9361223d803aada0f7eb6ada79c49d Mon Sep 17 00:00:00 2001 From: Abhinay Agarwal Date: Sat, 10 Oct 2020 13:41:34 +0530 Subject: [PATCH 22/24] Update README.md --- README.md | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index b3cede9..057a2d9 100644 --- a/README.md +++ b/README.md @@ -129,9 +129,8 @@ Optionally, the configuration can be modified with: - `includePathExceptionsInClasspath`: When resolving the module-path, setting this value to true will include the dependencies that generate path exceptions in the classpath. By default, the value is false, and these dependencies won't be included. -- `runtimePathOption`: The default behaviour of the plugin is to place the dependencies either on -modulepath or classpath depending on various factors. For example, if a dependency contains module descriptor or Automatic-Module-Name -it will be placed on the module-path. `runtimePathOption` configuration allows to run the application by placing all the dependencies on either classpath or modulepath. +- `runtimePathOption`: By default, the plugin will place *each* dependency either on modulepath or on classpath (based on certain factors). +When `runtimePathOption` configuration is set, the plugin will place *all* the dependencies on either modulepath or classpath. If set as `CLASSPATH`, a Launcher class ([like this one](https://github.com/openjfx/samples/blob/master/CommandLine/Non-modular/CLI/hellofx/src/hellofx/Launcher.java)) is required to run a JavaFX application. Also, if a module-info descriptor is present, it will be ignored. From 130a2bdfd8b019e2d00da76bb0c79e005adb6b2b Mon Sep 17 00:00:00 2001 From: Abhinay Agarwal Date: Tue, 13 Oct 2020 16:13:45 +0530 Subject: [PATCH 23/24] Remove unnecessary checks while moving dependencies when runtimePathOption is MODULEPATH --- src/main/java/org/openjfx/JavaFXBaseMojo.java | 13 ++----------- 1 file changed, 2 insertions(+), 11 deletions(-) diff --git a/src/main/java/org/openjfx/JavaFXBaseMojo.java b/src/main/java/org/openjfx/JavaFXBaseMojo.java index 1da3eab..2c7e575 100644 --- a/src/main/java/org/openjfx/JavaFXBaseMojo.java +++ b/src/main/java/org/openjfx/JavaFXBaseMojo.java @@ -289,17 +289,8 @@ void preparePaths(Path jdkHome) throws MojoExecutionException { if (runtimePathOption == MODULEPATH) { getLog().debug(runtimePathOption + " runtimePathOption set by user. Moving all jars to modulepath."); - if (moduleDescriptor == null) { - // target/classes should still be on classpath - final List classpathJars = classpathElements.stream() - .filter(ce -> ce.endsWith(".jar")) - .collect(Collectors.toList()); - modulepathElements.addAll(classpathJars); - classpathElements.removeAll(classpathJars); - } else { - modulepathElements.addAll(classpathElements); - classpathElements.clear(); - } + modulepathElements.addAll(classpathElements); + classpathElements.clear(); } else if (runtimePathOption == CLASSPATH) { getLog().debug(runtimePathOption + " runtimePathOption set by user. Moving all jars to classpath."); classpathElements.addAll(modulepathElements); From 182586b276c1ea396726c3473725ef9e4a2ad56d Mon Sep 17 00:00:00 2001 From: Abhinay Agarwal Date: Thu, 15 Oct 2020 17:50:40 +0530 Subject: [PATCH 24/24] Changes as per feedback --- README.md | 2 ++ src/main/java/org/openjfx/JavaFXBaseMojo.java | 8 +++++--- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 057a2d9..c6a4040 100644 --- a/README.md +++ b/README.md @@ -132,6 +132,8 @@ won't be included. - `runtimePathOption`: By default, the plugin will place *each* dependency either on modulepath or on classpath (based on certain factors). When `runtimePathOption` configuration is set, the plugin will place *all* the dependencies on either modulepath or classpath. + If set as `MODULEPATH`, a module descriptor is required. All dependencies need to be either modularized or contain an Automatic-Module-Name. + If set as `CLASSPATH`, a Launcher class ([like this one](https://github.com/openjfx/samples/blob/master/CommandLine/Non-modular/CLI/hellofx/src/hellofx/Launcher.java)) is required to run a JavaFX application. Also, if a module-info descriptor is present, it will be ignored. diff --git a/src/main/java/org/openjfx/JavaFXBaseMojo.java b/src/main/java/org/openjfx/JavaFXBaseMojo.java index 2c7e575..e3adb11 100644 --- a/src/main/java/org/openjfx/JavaFXBaseMojo.java +++ b/src/main/java/org/openjfx/JavaFXBaseMojo.java @@ -295,6 +295,9 @@ void preparePaths(Path jdkHome) throws MojoExecutionException { getLog().debug(runtimePathOption + " runtimePathOption set by user. Moving all jars to classpath."); classpathElements.addAll(modulepathElements); modulepathElements.clear(); + if (mainClass.contains("/")) { + getLog().warn("Module name found in with runtimePathOption set as CLASSPATH. Module name will be ignored."); + } if (doesExtendFXApplication(createMainClassString(mainClass, moduleDescriptor, runtimePathOption))) { throw new MojoExecutionException("Launcher class is required. Main-class cannot extend Application when running JavaFX application on CLASSPATH"); } @@ -312,7 +315,7 @@ void preparePaths(Path jdkHome) throws MojoExecutionException { private JavaModuleDescriptor createModuleDescriptor(ResolvePathsResult resolvePathsResult) throws MojoExecutionException { if (runtimePathOption == CLASSPATH) { - getLog().debug(CLASSPATH + " runtimePathOption set by user. module-info.java will be ignored."); + getLog().info(CLASSPATH + " runtimePathOption set by user. module-info.java will be ignored."); return null; } return resolvePathsResult.getMainModuleDescriptor(); @@ -442,7 +445,6 @@ String createMainClassString(String mainClass, JavaModuleDescriptor moduleDescri Objects.requireNonNull(mainClass, "Main class cannot be null"); if (runtimePathOption == CLASSPATH) { if (mainClass.contains("/")) { - getLog().warn("Module name found in with runtimePathOption set as CLASSPATH. Module name will be ignored."); return mainClass.substring(mainClass.indexOf("/") + 1); } return mainClass; @@ -576,7 +578,7 @@ private boolean doesExtendFXApplication(String mainClass) { URLClassLoader classLoader = new URLClassLoader(urls, JavaFXBaseMojo.class.getClassLoader()); Class clazz = Class.forName(mainClass, false, classLoader); fxApplication = doesExtendFXApplication(clazz); - getLog().info("app for " + clazz.toString() + " extends Application: " + fxApplication); + getLog().debug("Main Class " + clazz.toString() + " extends Application: " + fxApplication); } catch (NoClassDefFoundError | ClassNotFoundException | DependencyResolutionRequiredException | MalformedURLException e) { getLog().debug(e); }