Skip to content
Permalink
Browse files

java9-modularity#72: support for "moduleOptions.compileModuleInfoSepa…

…rately"

added CompileModuleOptions and CompileModuleInfoTask

NOTE: potentially breaking change for "compileJava" in Kotlin DSL (see modified "build.gradle.kts")
  • Loading branch information...
tlinkowski committed Mar 16, 2019
1 parent 365192c commit 81d535313a08260a11af68ebf64c531894b0083e
@@ -445,6 +445,16 @@ patchModules.config = [
]
```

Compilation
===

Separate compilation of `module-info.java`
----

If you need to compile the main `module-info.java` separately from the rest of `src/main/java`
files, you can enable `compileModuleInfoSeparately` option on `compileJava` task. It will exclude `module-info.java`
from `compileJava` and introduce a dedicated `compileModuleInfoJava` task.

Limitations
===

@@ -20,6 +20,7 @@ private void configureModularity(Project project, String moduleName) {
extensions.create("patchModules", PatchModuleExtension.class);

new CompileTask(project).configureCompileJava();
new CompileModuleInfoTask(project).configureCompileModuleInfoJava();
new CompileTestTask().configureCompileTestJava(project, moduleName);
new TestTask().configureTestJava(project, moduleName);
new RunTask().configureRun(project, moduleName);
@@ -0,0 +1,35 @@
package org.javamodularity.moduleplugin.extensions;

import org.gradle.api.Project;
import org.gradle.api.tasks.compile.JavaCompile;
import org.javamodularity.moduleplugin.tasks.ModuleOptions;

public class CompileModuleOptions extends ModuleOptions {

/**
* Name of the extra Java compile task created if {@code compileModuleInfoSeparately} is {@code true}.
*/
public static final String COMPILE_MODULE_INFO_TASK_NAME = "compileModuleInfoJava";

private final Project project;

private boolean compileModuleInfoSeparately = false;

public CompileModuleOptions(Project project) {
super(project);
this.project = project;
}

public boolean getCompileModuleInfoSeparately() {
return compileModuleInfoSeparately;
}

public void setCompileModuleInfoSeparately(boolean compileModuleInfoSeparately) {
if (compileModuleInfoSeparately) {
// we need to create "compileModuleInfoJava" task eagerly so that the user can configure it immediately
project.getTasks().maybeCreate(COMPILE_MODULE_INFO_TASK_NAME, JavaCompile.class);
}
this.compileModuleInfoSeparately = compileModuleInfoSeparately;
}

}
@@ -0,0 +1,24 @@
package org.javamodularity.moduleplugin.tasks;

import org.gradle.api.Project;
import org.gradle.api.tasks.compile.JavaCompile;
import org.javamodularity.moduleplugin.JavaProjectHelper;
import org.javamodularity.moduleplugin.extensions.CompileModuleOptions;

abstract class AbstractCompileTask {

protected final Project project;

AbstractCompileTask(Project project) {
this.project = project;
}

final CompileJavaTaskMutator createCompileJavaTaskMutator(
JavaCompile compileJava, CompileModuleOptions moduleOptions) {
return new CompileJavaTaskMutator(project, compileJava.getClasspath(), moduleOptions);
}

final JavaProjectHelper helper() {
return new JavaProjectHelper(project);
}
}
@@ -1,8 +1,10 @@
package org.javamodularity.moduleplugin.tasks;

import org.gradle.api.Project;
import org.gradle.api.file.FileCollection;
import org.gradle.api.tasks.compile.AbstractCompile;
import org.gradle.api.tasks.compile.JavaCompile;
import org.javamodularity.moduleplugin.extensions.CompileModuleOptions;

import java.util.ArrayList;
import java.util.List;
@@ -11,13 +13,34 @@

private static final String COMPILE_KOTLIN_TASK_NAME = "compileKotlin";

static void mutateJavaCompileTask(Project project, JavaCompile compileJava) {
ModuleOptions moduleOptions = compileJava.getExtensions().getByType(ModuleOptions.class);
private final Project project;
/**
* {@linkplain JavaCompile#getClasspath() Classpath} of {@code compileJava} task.
*/
private final FileCollection compileJavaClasspath;
/**
* {@link CompileModuleOptions} of {@code compileJava} task.
*/
private final CompileModuleOptions moduleOptions;

CompileJavaTaskMutator(Project project, FileCollection compileJavaClasspath, CompileModuleOptions moduleOptions) {
this.project = project;
this.compileJavaClasspath = compileJavaClasspath;
this.moduleOptions = moduleOptions;
}

/**
* The argument is a {@link JavaCompile} task whose modularity is to be configured.
*
* @param javaCompile {@code compileJava} if {@link CompileModuleOptions#getCompileModuleInfoSeparately()}
* is {@code false}, {@code compileModuleInfoJava} if it is {@code true}
*/
void modularizeJavaCompileTask(JavaCompile javaCompile) {
PatchModuleExtension patchModuleExtension = project.getExtensions().getByType(PatchModuleExtension.class);

var compilerArgs = new ArrayList<>(compileJava.getOptions().getCompilerArgs());
var compilerArgs = new ArrayList<>(javaCompile.getOptions().getCompilerArgs());

compilerArgs.addAll(List.of("--module-path", compileJava.getClasspath()
compilerArgs.addAll(List.of("--module-path", compileJavaClasspath
.filter(patchModuleExtension::isUnpatched)
.getAsPath()));

@@ -27,14 +50,14 @@ static void mutateJavaCompileTask(Project project, JavaCompile compileJava) {
compilerArgs.add(addModules);
}

compilerArgs.addAll(patchModuleExtension.configure(compileJava.getClasspath()));
compileJava.getOptions().setCompilerArgs(compilerArgs);
compileJava.setClasspath(project.files());
compilerArgs.addAll(patchModuleExtension.configure(compileJavaClasspath));
javaCompile.getOptions().setCompilerArgs(compilerArgs);
javaCompile.setClasspath(project.files());

// https://github.com/java9-modularity/gradle-modules-plugin/issues/45
AbstractCompile compileKotlin = (AbstractCompile) project.getTasks().findByName(COMPILE_KOTLIN_TASK_NAME);
if (compileKotlin != null) {
compileJava.setDestinationDir(compileKotlin.getDestinationDir());
javaCompile.setDestinationDir(compileKotlin.getDestinationDir());
}
}

@@ -0,0 +1,81 @@
package org.javamodularity.moduleplugin.tasks;

import org.gradle.api.Action;
import org.gradle.api.Project;
import org.gradle.api.Task;
import org.gradle.api.plugins.JavaPlugin;
import org.gradle.api.tasks.compile.JavaCompile;
import org.javamodularity.moduleplugin.extensions.CompileModuleOptions;

import java.nio.file.Files;
import java.nio.file.Path;

public class CompileModuleInfoTask extends AbstractCompileTask {

public CompileModuleInfoTask(Project project) {
super(project);
}

/**
* @see CompileTask#configureCompileJava()
*/
public void configureCompileModuleInfoJava() {
helper().findCompileJavaTask(JavaPlugin.COMPILE_JAVA_TASK_NAME)
.ifPresent(this::configureCompileModuleInfoJava);
}

private void configureCompileModuleInfoJava(JavaCompile compileJava) {
var moduleOptions = compileJava.getExtensions().getByType(CompileModuleOptions.class);
project.afterEvaluate(p -> {
if (moduleOptions.getCompileModuleInfoSeparately()) {
configureModularityForCompileModuleInfoJava(compileJava, moduleOptions);
}
});
}

/**
* @see CompileTask#configureModularityForCompileJava
*/
void configureModularityForCompileModuleInfoJava(
JavaCompile compileJava, CompileModuleOptions moduleOptions) {
JavaCompile compileModuleInfoJava = preconfigureCompileModuleInfoJava(compileJava);
CompileJavaTaskMutator mutator = createCompileJavaTaskMutator(compileJava, moduleOptions);

// don't convert to lambda: https://github.com/java9-modularity/gradle-modules-plugin/issues/54
compileModuleInfoJava.doFirst(new Action<Task>() {
@Override
public void execute(Task task) {
mutator.modularizeJavaCompileTask(compileModuleInfoJava);
}
});
}

/**
* Preconfigures a separate task that is meant to compile {@code module-info.java} separately.
* Final (modular) configuration is performed later by {@link CompileJavaTaskMutator}.
*/
private JavaCompile preconfigureCompileModuleInfoJava(JavaCompile compileJava) {
var compileModuleInfoJava = helper().compileJavaTask(CompileModuleOptions.COMPILE_MODULE_INFO_TASK_NAME);

compileModuleInfoJava.setClasspath(project.files()); // empty
compileModuleInfoJava.setSource(pathToModuleInfoJava());
compileModuleInfoJava.setDestinationDir(compileJava.getDestinationDir());

// we need all the compiled classes before compiling module-info.java
compileModuleInfoJava.dependsOn(compileJava);

// make "classes" trigger module-info.java compilation
helper().task(JavaPlugin.CLASSES_TASK_NAME).dependsOn(compileModuleInfoJava);

return compileModuleInfoJava;
}

private Path pathToModuleInfoJava() {
return helper().mainSourceSet().getJava().getSrcDirs().stream()
.map(srcDir -> srcDir.toPath().resolve("module-info.java"))
.filter(Files::exists)
.findFirst()
.orElseThrow(() -> new IllegalStateException("module-info.java not found"));
}

}
@@ -5,34 +5,45 @@
import org.gradle.api.Task;
import org.gradle.api.plugins.JavaPlugin;
import org.gradle.api.tasks.compile.JavaCompile;
import org.javamodularity.moduleplugin.JavaProjectHelper;
import org.javamodularity.moduleplugin.extensions.CompileModuleOptions;

public class CompileTask {

private final Project project;
public class CompileTask extends AbstractCompileTask {

public CompileTask(Project project) {
this.project = project;
super(project);
}

/**
* @see CompileModuleInfoTask#configureCompileModuleInfoJava()
*/
public void configureCompileJava() {
helper().findCompileJavaTask(JavaPlugin.COMPILE_JAVA_TASK_NAME)
.ifPresent(this::configureCompileJava);
}

private void configureCompileJava(JavaCompile compileJava) {
compileJava.getExtensions().create("moduleOptions", ModuleOptions.class, project);
var moduleOptions = compileJava.getExtensions().create("moduleOptions", CompileModuleOptions.class, project);
project.afterEvaluate(p -> {
if (moduleOptions.getCompileModuleInfoSeparately()) {
compileJava.exclude("module-info.java");
} else {
configureModularityForCompileJava(compileJava, moduleOptions);
}
});
}

/**
* @see CompileModuleInfoTask#configureModularityForCompileModuleInfoJava
*/
void configureModularityForCompileJava(JavaCompile compileJava, CompileModuleOptions moduleOptions) {
CompileJavaTaskMutator mutator = createCompileJavaTaskMutator(compileJava, moduleOptions);
// don't convert to lambda: https://github.com/java9-modularity/gradle-modules-plugin/issues/54
compileJava.doFirst(new Action<Task>() {
@Override
public void execute(Task task) {
CompileJavaTaskMutator.mutateJavaCompileTask(project, compileJava);
mutator.modularizeJavaCompileTask(compileJava);
}
});
}

private JavaProjectHelper helper() {
return new JavaProjectHelper(project);
}
}
@@ -4,27 +4,30 @@
import org.gradle.api.plugins.JavaPlugin;
import org.gradle.api.tasks.compile.JavaCompile;
import org.gradle.testfixtures.ProjectBuilder;
import org.javamodularity.moduleplugin.extensions.CompileModuleOptions;
import org.junit.jupiter.api.Test;

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

import static org.junit.jupiter.api.Assertions.*;
import static org.junit.jupiter.api.Assertions.assertEquals;

class CompileJavaTaskMutatorTest {

@Test
void mutateJavaCompileTask() {
void modularizeJavaCompileTask() {
// given
Project project = ProjectBuilder.builder().withProjectDir(new File("test-project/")).build();
project.getPlugins().apply("java");
final JavaCompile compileJava = (JavaCompile) project.getTasks().findByName(JavaPlugin.COMPILE_JAVA_TASK_NAME);
compileJava.getExtensions().create("moduleOptions", ModuleOptions.class, project);
JavaCompile compileJava = (JavaCompile) project.getTasks().getByName(JavaPlugin.COMPILE_JAVA_TASK_NAME);
CompileModuleOptions moduleOptions = compileJava.getExtensions()
.create("moduleOptions", CompileModuleOptions.class, project);
project.getExtensions().create("patchModules", PatchModuleExtension.class);
CompileJavaTaskMutator mutator = new CompileJavaTaskMutator(project, compileJava.getClasspath(), moduleOptions);

// when
CompileJavaTaskMutator.mutateJavaCompileTask(project, compileJava);
mutator.modularizeJavaCompileTask(compileJava);

// then
List<String> twoLastArguments = twoLastCompilerArgs(compileJava);
@@ -1,12 +1,13 @@
import org.javamodularity.moduleplugin.tasks.ModuleOptions
import org.javamodularity.moduleplugin.extensions.CompileModuleOptions
import org.javamodularity.moduleplugin.tasks.TestModuleOptions
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile

//region NO-OP (DSL testing)
tasks {
compileJava {
extensions.configure(ModuleOptions::class) {
extensions.configure(CompileModuleOptions::class) {
addModules = listOf()
compileModuleInfoSeparately = false
}
}

@@ -6,6 +6,7 @@ plugins {
compileJava {
moduleOptions {
addModules = []
compileModuleInfoSeparately = false
}
}

0 comments on commit 81d5353

Please sign in to comment.
You can’t perform that action at this time.