Skip to content
Merged
Show file tree
Hide file tree
Changes from 13 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions src/main/java/org/openjfx/gradle/JavaFXModule.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2018, 2023, Gluon
* Copyright (c) 2018, 2025, Gluon
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
Expand Down Expand Up @@ -31,6 +31,7 @@

import org.gradle.api.GradleException;

import java.util.Collection;
import java.util.List;
import java.util.Locale;
import java.util.Optional;
Expand Down Expand Up @@ -81,16 +82,15 @@ public boolean compareJarFileName(JavaFXPlatform platform, String jarFileName) {
return p.matcher(jarFileName).matches();
}

public static Set<JavaFXModule> getJavaFXModules(List<String> moduleNames) {
public static Set<JavaFXModule> getJavaFXModules(Collection<String> moduleNames) {
validateModules(moduleNames);

return moduleNames.stream()
.map(JavaFXModule::fromModuleName)
.flatMap(Optional::stream)
.collect(Collectors.toSet());
}

public static void validateModules(List<String> moduleNames) {
public static void validateModules(Collection<String> moduleNames) {
var invalidModules = moduleNames.stream()
.filter(module -> JavaFXModule.fromModuleName(module).isEmpty())
.collect(Collectors.toList());
Expand Down
35 changes: 24 additions & 11 deletions src/main/java/org/openjfx/gradle/JavaFXOptions.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2018, 2023, Gluon
* Copyright (c) 2018, 2025, Gluon
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
Expand Down Expand Up @@ -36,13 +36,14 @@
import org.gradle.api.artifacts.dsl.RepositoryHandler;
import org.gradle.api.artifacts.repositories.FlatDirectoryArtifactRepository;
import org.gradle.api.model.ObjectFactory;
import org.gradle.api.provider.Property;
import org.gradle.api.provider.SetProperty;
import org.gradle.api.tasks.SourceSetContainer;
import org.gradle.nativeplatform.MachineArchitecture;
import org.gradle.nativeplatform.OperatingSystemFamily;

import javax.inject.Inject;
import java.io.File;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
Expand All @@ -54,13 +55,13 @@ abstract public class JavaFXOptions {

static final String MAVEN_JAVAFX_ARTIFACT_GROUP_ID = "org.openjfx";
private static final String JAVAFX_SDK_LIB_FOLDER = "lib";
private final SetProperty<String> modules;
private final Property<JavaFXPlatform> platform;

private JavaFXPlatform platform;

private String version = "17";
private String sdk;
private String[] configurations = new String[] { "implementation" };
private List<String> modules = new ArrayList<>();
private FlatDirectoryArtifactRepository customSDKArtifactRepository;

private final SourceSetContainer sourceSets;
Expand All @@ -80,11 +81,18 @@ abstract public class JavaFXOptions {

public JavaFXOptions(SourceSetContainer sourceSets, OsDetector osDetector) {
this.sourceSets = sourceSets;
platform = JavaFXPlatform.detect(osDetector);
platform = getObjects().property(JavaFXPlatform.class);
getFxPlatform().convention(JavaFXPlatform.detect(osDetector));
setClasspathAttributesForAllSourceSets();
modules = getObjects().setProperty(String.class);
}


public JavaFXPlatform getPlatform() {
return getFxPlatform().get();
}

public Property<JavaFXPlatform> getFxPlatform(){
return platform;
}

Expand All @@ -94,7 +102,7 @@ public JavaFXPlatform getPlatform() {
* Supported classifiers are linux, linux-aarch64, win/windows, osx/mac/macos or osx-aarch64/mac-aarch64/macos-aarch64.
*/
public void setPlatform(String platform) {
this.platform = JavaFXPlatform.fromString(platform);
this.getFxPlatform().set(JavaFXPlatform.fromString(platform));
setClasspathAttributesForAllSourceSets();
}

Expand All @@ -108,10 +116,10 @@ private void setClasspathAttributesForAllSourceSets() {
private void setClasspathAttributes(Configuration classpath) {
classpath.getAttributes().attribute(
OperatingSystemFamily.OPERATING_SYSTEM_ATTRIBUTE,
getObjects().named(OperatingSystemFamily.class, platform.getOsFamily()));
getObjects().named(OperatingSystemFamily.class, platform.get().getOsFamily()));
classpath.getAttributes().attribute(
MachineArchitecture.ARCHITECTURE_ATTRIBUTE,
getObjects().named(MachineArchitecture.class, platform.getArch()));
getObjects().named(MachineArchitecture.class, platform.get().getArch()));
}

public String getVersion() {
Expand Down Expand Up @@ -168,12 +176,17 @@ public String[] getConfigurations() {
return configurations;
}

public List<String> getModules() {
public SetProperty<String> getFxModules() {
return modules;
}

public Set<String> getModules() {
return modules.get();
}

public void setModules(List<String> modules) {
this.modules = modules;
this.modules.set(modules);

}

public void modules(String...moduleNames) {
Expand All @@ -190,7 +203,7 @@ private void declareFXDependencies(String conf) {
return;
}

var javaFXModules = JavaFXModule.getJavaFXModules(this.modules);
var javaFXModules = JavaFXModule.getJavaFXModules(getModules());
if (customSDKArtifactRepository == null) {
javaFXModules.stream()
.sorted()
Expand Down
2 changes: 1 addition & 1 deletion src/main/java/org/openjfx/gradle/JavaFXPlatform.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2018, 2023, Gluon
* Copyright (c) 2018, 2025, Gluon
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
Expand Down
56 changes: 32 additions & 24 deletions src/main/java/org/openjfx/gradle/JavaFXPlugin.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2018, 2023, Gluon
* Copyright (c) 2018, 2025, Gluon
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
Expand Down Expand Up @@ -31,19 +31,19 @@

import com.google.gradle.osdetector.OsDetector;
import com.google.gradle.osdetector.OsDetectorPlugin;
import org.gradle.api.GradleException;
import org.gradle.api.NonNullApi;
import org.gradle.api.Plugin;
import org.gradle.api.Project;
import org.gradle.api.*;
import org.gradle.api.file.FileCollection;
import org.gradle.api.plugins.ApplicationPlugin;
import org.gradle.api.plugins.JavaBasePlugin;
import org.gradle.api.provider.Property;
import org.gradle.api.provider.SetProperty;
import org.gradle.api.tasks.JavaExec;
import org.gradle.api.tasks.SourceSetContainer;
import org.gradle.util.GradleVersion;
import org.openjfx.gradle.metadatarule.JavaFXComponentMetadataRule;

import java.io.File;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

Expand All @@ -54,10 +54,9 @@ public class JavaFXPlugin implements Plugin<Project> {

@Override
public void apply(Project project) {
if (GradleVersion.current().compareTo(GradleVersion.version("6.1")) < 0) {
throw new GradleException("This plugin requires Gradle 6.1+");
if (GradleVersion.current().compareTo(GradleVersion.version("6.4")) < 0) {
throw new GradleException("This plugin requires Gradle 6.4+");
}

// Make sure 'java-base' is applied first, which makes the 'SourceSetContainer' available.
// More concrete Java plugins that build on top of 'java-base' – like 'java-library' or 'application' –
// will be applied by the user.
Expand All @@ -83,39 +82,48 @@ public void apply(Project project) {
// and other Java-base plugins like Kotlin JVM)
project.getPlugins().withId("java", p -> javaFXOptions.setConfiguration("implementation"));

// Only do addition configuration of the ':run' task when the 'application' plugin is applied.
// Otherwise, that task does not exist.
project.getPlugins().withId("application", p -> {
project.getTasks().named(ApplicationPlugin.TASK_RUN_NAME, JavaExec.class, execTask -> {
if (GradleVersion.current().compareTo(GradleVersion.version("6.4")) >= 0 && execTask.getMainModule().isPresent()) {
return; // a module, as determined by Gradle core

project.afterEvaluate(new Action<Project>() {
@Override
public void execute(Project project) {
if (!project.getPlugins().hasPlugin("application") ||
(project.getPlugins().hasPlugin("org.javamodularity.moduleplugin")) && project.getExtensions().findByName("modulename") != null) {
return;
}

execTask.doFirst(a -> {
if (execTask.getExtensions().findByName("moduleOptions") != null) {
return; // a module, as determined by modularity plugin
project.getTasks().named("run", JavaExec.class, new Action<JavaExec>() {
@Override
public void execute(JavaExec task) {
if (task.getMainModule().isPresent()) {
return;
}
final var fxPlatform = javaFXOptions.getFxPlatform();
final var fxModules = javaFXOptions.getFxModules();
task.doFirst(a -> {
putJavaFXJarsOnModulePathForClasspathApplication(task, fxPlatform, fxModules);
});
}

putJavaFXJarsOnModulePathForClasspathApplication(execTask, javaFXOptions);
});
});

}
});

}

/**
* Gradle does currently not put anything on the --module-path if the application itself is executed from
* the classpath. Hence, this patches the setup of Gradle's standard ':run' task to move all JavaFX Jars
* from '-classpath' to '-module-path'. This functionality is only relevant for NON-MODULAR apps.
*/
private static void putJavaFXJarsOnModulePathForClasspathApplication(JavaExec execTask, JavaFXOptions javaFXOptions) {
private static void putJavaFXJarsOnModulePathForClasspathApplication(JavaExec execTask, final Property<JavaFXPlatform> platform, final SetProperty<String> stringSetProperty) {
FileCollection classpath = execTask.getClasspath();

execTask.setClasspath(classpath.filter(jar -> !isJavaFXJar(jar, javaFXOptions.getPlatform())));
var modulePath = classpath.filter(jar -> isJavaFXJar(jar, javaFXOptions.getPlatform()));
execTask.setClasspath(classpath.filter(jar -> !isJavaFXJar(jar, platform.get())));
var modulePath = classpath.filter(jar -> isJavaFXJar(jar, platform.get()));

execTask.getJvmArgumentProviders().add(() -> List.of(
"--module-path", modulePath.getAsPath(),
"--add-modules", String.join(",", javaFXOptions.getModules())
"--add-modules", String.join(",", stringSetProperty.get())
));
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2023, Gluon
* Copyright (c) 2018, 2025, Gluon
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
Expand Down
2 changes: 1 addition & 1 deletion src/test/java/org/openjfx/gradle/JavaFXModuleTest.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2018, 2023, Gluon
* Copyright (c) 2018, 2025, Gluon
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
Expand Down
24 changes: 21 additions & 3 deletions src/test/java/org/openjfx/gradle/JavaFXPluginSmokeTest.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2018, 2023, Gluon
* Copyright (c) 2018, 2025, Gluon
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
Expand Down Expand Up @@ -33,10 +33,12 @@
import org.gradle.testkit.runner.BuildResult;
import org.gradle.testkit.runner.GradleRunner;
import org.gradle.testkit.runner.TaskOutcome;
import org.junit.jupiter.api.Assumptions;
import org.junit.jupiter.api.Test;

import java.io.File;
import java.lang.management.ManagementFactory;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
Expand Down Expand Up @@ -74,6 +76,7 @@ void smokeTestModular() {

@Test
void smokeTestModularWithModularityPlugin() {
Assumptions.assumeFalse(useConfigurationCache(), "modularity plugin does not support configuration cache");
var result = build(":modular-with-modularity-plugin:run");

assertEquals(TaskOutcome.SUCCESS, result.task(":modular-with-modularity-plugin:run").getOutcome());
Expand Down Expand Up @@ -135,7 +138,8 @@ private static List<List<String>> path(BuildResult result, String pathArg) {
return result.getOutput().lines().filter(l -> l.contains(pathArg)).map(l -> {
int pathArgIndex = l.indexOf(pathArg) + pathArg.length();
String pathString = l.substring(pathArgIndex, l.indexOf(" ", pathArgIndex));
if (pathString.isBlank()) {
//recently gradle added an empty classpath instead of omitting it entirely which seems like the same thing?
if (pathString.isBlank() || pathString.equals("\"\"")) {
return List.<String>of();
}
String[] path = pathString.split(System.getProperty("path.separator"));
Expand All @@ -149,7 +153,21 @@ private BuildResult build(String task) {
.withGradleVersion(getGradleVersion())
.withPluginClasspath()
.withDebug(ManagementFactory.getRuntimeMXBean().getInputArguments().toString().contains("-agentlib:jdwp"))
.withArguments("clean", task, "--stacktrace", "--debug")
.withArguments(getGradleRunnerArguments(task))
.build();
}

protected List<String> getGradleRunnerArguments(String taskname) {
//note that the tests are written around --debug, they will fail if you reduce logging
final var args = new ArrayList<String>(List.of("clean", taskname, "--stacktrace", "--debug"));
if (useConfigurationCache()) {
args.add("--configuration-cache");
}
return args;

}

protected boolean useConfigurationCache() {
return false;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
/*
* Copyright (c) 2025, Gluon
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* * Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* * Neither the name of the copyright holder nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package org.openjfx.gradle;


class JavaFXPluginSmokeTestGradle64 extends JavaFXPluginSmokeTest {

@Override
protected String getGradleVersion() {
return "6.4";
}

}
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2023, Gluon
* Copyright (c) 2018, 2025, Gluon
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2023, Gluon
* Copyright (c) 2018, 2025, Gluon
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
Expand Down
Loading