4545import org .gradle .util .GradleVersion ;
4646import org .gradlex .javamodule .packaging .internal .HostIdentification ;
4747import org .gradlex .javamodule .packaging .model .Target ;
48+ import org .gradlex .javamodule .packaging .tasks .FatModuleJar ;
4849import org .gradlex .javamodule .packaging .tasks .Jpackage ;
4950import org .gradlex .javamodule .packaging .tasks .ValidateHostSystemAction ;
5051import org .jspecify .annotations .NullMarked ;
@@ -56,6 +57,7 @@ public abstract class JavaModulePackagingExtension {
5657 private static final Attribute <Boolean > JAVA_MODULE_ATTRIBUTE = Attribute .of ("javaModule" , Boolean .class );
5758 private static final String INTERNAL = "internal" ;
5859 private static final String JPACKAGE = "jpackage" ;
60+ private static final String FAT_MODULE_JAR = "fatModuleJar" ;
5961
6062 private final Project project ;
6163
@@ -95,7 +97,6 @@ public JavaModulePackagingExtension(Project project) {
9597 /**
9698 * Retrieve the target with the given 'label'. If the target does not yet exist, it will be created.
9799 */
98- @ SuppressWarnings ("unused" )
99100 public Target target (String label ) {
100101 return target (label , target -> {});
101102 }
@@ -120,7 +121,6 @@ public Target target(String label, Action<? super Target> action) {
120121 /**
121122 * Configure all targets for the given OS.
122123 */
123- @ SuppressWarnings ("unused" )
124124 public void targetsWithOs (String operatingSystem , Action <? super Target > action ) {
125125 NamedDomainObjectSet <Target > matches =
126126 targets .matching (t -> t .getOperatingSystem ().isPresent ()
@@ -132,7 +132,6 @@ public void targetsWithOs(String operatingSystem, Action<? super Target> action)
132132 * Set a 'primary target'. Standard Gradle tasks that are not bound to a specific target – like 'assemble' – use
133133 * this 'primary target'.
134134 */
135- @ SuppressWarnings ("unused" )
136135 public Target primaryTarget (Target target ) {
137136 SourceSetContainer sourceSets = project .getExtensions ().getByType (SourceSetContainer .class );
138137 ConfigurationContainer configurations = project .getConfigurations ();
@@ -155,7 +154,6 @@ public Target primaryTarget(Target target) {
155154 /**
156155 * Set a test suite to be 'multi-target'. This registers an additional 'test' task for each target.
157156 */
158- @ SuppressWarnings ({"unused" , "UnstableApiUsage" })
159157 public TestSuite multiTargetTestSuite (TestSuite testSuite ) {
160158 if (!(testSuite instanceof JvmTestSuite )) {
161159 return testSuite ;
@@ -183,7 +181,18 @@ public TestSuite multiTargetTestSuite(TestSuite testSuite) {
183181 return testSuite ;
184182 }
185183
184+ void maybeAddSingleDefaultTarget (Target target ) {
185+ if (targets .isEmpty ()) {
186+ targets .add (target );
187+ newTarget (target , true );
188+ }
189+ }
190+
186191 private void newTarget (Target target ) {
192+ newTarget (target , false );
193+ }
194+
195+ private void newTarget (Target target , boolean singleDefault ) {
187196 target .getPackageTypes ().convention (target .getOperatingSystem ().map (os -> {
188197 switch (os ) {
189198 case WINDOWS :
@@ -200,35 +209,41 @@ private void newTarget(Target target) {
200209 SourceSetContainer sourceSets = project .getExtensions ().getByType (SourceSetContainer .class );
201210
202211 sourceSets .all (sourceSet -> {
203- Configuration internal = maybeCreateInternalConfiguration ();
204- configurations .create (
205- target .getName () + capitalize (sourceSet .getCompileClasspathConfigurationName ()), c -> {
206- c .setCanBeConsumed (false );
207- setInvisible (c );
208- configureJavaStandardAttributes (c , Usage .JAVA_API );
209- configureTargetAttributes (c , target );
210- c .extendsFrom (
211- configurations .getByName (sourceSet .getImplementationConfigurationName ()),
212- configurations .getByName (sourceSet .getCompileOnlyConfigurationName ()),
213- internal );
214- });
215- Configuration runtimeClasspath = configurations .create (
216- target .getName () + capitalize (sourceSet .getRuntimeClasspathConfigurationName ()), c -> {
217- c .setCanBeConsumed (false );
218- setInvisible (c );
219- configureJavaStandardAttributes (c , Usage .JAVA_RUNTIME );
220- configureTargetAttributes (c , target );
221- c .extendsFrom (
222- configurations .getByName (sourceSet .getImplementationConfigurationName ()),
223- configurations .getByName (sourceSet .getRuntimeOnlyConfigurationName ()),
224- internal );
225- });
212+ Configuration runtimeClasspath ;
213+ if (singleDefault ) {
214+ runtimeClasspath = configurations .getByName (sourceSet .getRuntimeClasspathConfigurationName ());
215+ } else {
216+ Configuration internal = maybeCreateInternalConfiguration ();
217+ configurations .create (
218+ target .getName () + capitalize (sourceSet .getCompileClasspathConfigurationName ()), c -> {
219+ c .setCanBeConsumed (false );
220+ setInvisible (c );
221+ configureJavaStandardAttributes (c , Usage .JAVA_API );
222+ configureTargetAttributes (c , target );
223+ c .extendsFrom (
224+ configurations .getByName (sourceSet .getImplementationConfigurationName ()),
225+ configurations .getByName (sourceSet .getCompileOnlyConfigurationName ()),
226+ internal );
227+ });
228+ runtimeClasspath = configurations .create (
229+ target .getName () + capitalize (sourceSet .getRuntimeClasspathConfigurationName ()), c -> {
230+ c .setCanBeConsumed (false );
231+ setInvisible (c );
232+ configureJavaStandardAttributes (c , Usage .JAVA_RUNTIME );
233+ configureTargetAttributes (c , target );
234+ c .extendsFrom (
235+ configurations .getByName (sourceSet .getImplementationConfigurationName ()),
236+ configurations .getByName (sourceSet .getRuntimeOnlyConfigurationName ()),
237+ internal );
238+ });
239+ }
226240
227241 if (SourceSet .isMain (sourceSet )) {
228242 project .getPlugins ()
229243 .withType (
230244 ApplicationPlugin .class ,
231- p -> registerTargetSpecificTasks (target , sourceSet .getJarTaskName (), runtimeClasspath ));
245+ p -> registerTargetSpecificTasks (
246+ target , singleDefault , sourceSet .getJarTaskName (), runtimeClasspath ));
232247 }
233248 });
234249 }
@@ -268,13 +283,16 @@ private void configureTargetAttributes(Configuration resolvable, Target target)
268283 target .getArchitecture ().map (name -> getObjects ().named (MachineArchitecture .class , name )));
269284 }
270285
271- private void registerTargetSpecificTasks (Target target , String applicationJarTask , Configuration runtimeClasspath ) {
286+ private void registerTargetSpecificTasks (
287+ Target target , boolean singleDefaultTarget , String applicationJarTask , Configuration runtimeClasspath ) {
272288 TaskContainer tasks = project .getTasks ();
273289
274290 JavaPluginExtension java = project .getExtensions ().getByType (JavaPluginExtension .class );
275291 JavaApplication application = project .getExtensions ().getByType (JavaApplication .class );
276292
277293 TaskProvider <Jpackage > jpackage = tasks .register (JPACKAGE + capitalize (target .getName ()), Jpackage .class , t -> {
294+ t .setDescription ("Runs 'jpackage' command to create an image or s package." );
295+
278296 t .getJavaInstallation ()
279297 .convention (getJavaToolchains ()
280298 .compilerFor (java .getToolchain ())
@@ -318,12 +336,43 @@ private void registerTargetSpecificTasks(Target target, String applicationJarTas
318336 t .setJvmArgs (application .getApplicationDefaultJvmArgs ());
319337 t .classpath (tasks .named ("jar" ), runtimeClasspath );
320338 });
321- maybeAddJpackageLifecycleTask (tasks , target , jpackage );
339+
340+ registerFatModuleJarTask (target , singleDefaultTarget , applicationJarTask , runtimeClasspath );
341+
342+ maybeAddJpackageLifecycleTask (target , jpackage );
343+ }
344+
345+ private void registerFatModuleJarTask (
346+ Target target , boolean singleDefaultTarget , String applicationJarTask , Configuration runtimeClasspath ) {
347+ TaskContainer tasks = project .getTasks ();
348+ JavaApplication application = project .getExtensions ().getByType (JavaApplication .class );
349+ ConfigurationContainer configurations = project .getConfigurations ();
350+
351+ String taskName = FAT_MODULE_JAR + (singleDefaultTarget ? "" : capitalize (target .getName ()));
352+ tasks .register (taskName , FatModuleJar .class , t -> {
353+ String classifier = singleDefaultTarget ? "all" : "all-" + target .getName ();
354+
355+ t .setDescription ("Assembles a fat jar archive containing the complete module path and a launcher." );
356+
357+ t .getMainModule ().convention (application .getMainModule ());
358+ t .getMainClass ().convention (application .getMainClass ());
359+
360+ t .getLauncherPath ().from (configurations .named ("fatModuleJarLauncherPath" ));
361+ t .getLauncherMainClass ().convention ("build.jenesis.launcher.Launcher" );
362+
363+ t .getModulePath ().from (tasks .named (applicationJarTask ));
364+ t .getModulePath ().from (runtimeClasspath );
365+
366+ t .setZip64 (true );
367+
368+ t .getArchiveClassifier ().set (classifier );
369+ });
322370 }
323371
324- private void maybeAddJpackageLifecycleTask (
325- TaskContainer tasks , Target target , TaskProvider <Jpackage > targetJpackage ) {
326- // if a task already exists, do nothing to avoid conflciting with other plugins
372+ private void maybeAddJpackageLifecycleTask (Target target , TaskProvider <Jpackage > targetJpackage ) {
373+ TaskContainer tasks = project .getTasks ();
374+
375+ // if a task already exists, do nothing to avoid conflict with other plugins
327376 TaskProvider <Task > jpackage ;
328377 if (tasks .getNames ().contains (JPACKAGE )) {
329378 jpackage = tasks .named (JPACKAGE );
0 commit comments