Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add DSL for module dependencies that cannot be defined in module-info #35

Merged
merged 11 commits into from
Aug 8, 2023
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
# Java Module Dependencies Gradle Plugin - Changelog

## Version 1.4
* [#31](https://github.com/gradlex-org/java-module-dependencies/issues/31) DSL for module dependencies that cannot be defined in module-info

## Version 1.3.1

* Fix integration with analysis plugin if root projects are involved
Expand Down
72 changes: 48 additions & 24 deletions README.MD
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,8 @@ that shows all plugins in combination.
For a quick start, you can find some samples here:
* [samples/versions-in-platform](samples/versions-in-platform)
* [samples/versions-in-catalog](samples/versions-in-catalog)
* [samples/module-info-dsl](samples/module-info-dsl)
* [samples/module-info-dsl-no-platform](samples/module-info-dsl-no-platform)
* [samples/kotlin](samples/kotlin)

For general information about how to structure Gradle builds and apply community plugins like this one to all subprojects
Expand Down Expand Up @@ -84,6 +86,32 @@ module org.example.mymodule {

Note that `requires /*runtime*/` is a directive specifically supported by this plugin to allow the specification of _runtime only_ dependencies.

## Define additional module dependencies in build files

With this plugin you move dependency definitions into `module-info.java` files and no longer use the `dependencies {}` block in build files.
However, there are certain dependency "scopes" not supported by the `module-info.java` syntax.
For this, the plugin offers an extension of Gradle's DSL to be used in `build.gradle(.kts)` files.

```
mainModuleInfo {
runtimeOnly("org.slf4j.simple") // runtime only dependency for the 'main' module
annotationProcessor("dagger.compiler") // annotation processor dependency for the 'main' module
}
```

For modules in other source sets, there are corresponding blocks to define dependencies if needed – e.g. `testFixturesModuleInfo {}`.

In case a source set does **not** contain a `module-info.java`, all dependencies can be defined in the `build.gradle(.kts)` files.
The only case where this should be used is for whitebox testing activated via the [org.gradlex.java-module-testing](https://github.com/gradlex-org/java-module-testing) plugin.

```
testModuleInfo {
requires("org.assertj.core")
requires("org.hamcrest")
requires("org.junit.jupiter.api")
}
```

## Add Module Name mapping information (if needed)

You may define additional mappings from _Module Name_ to _group:name (GA) coordinates_.
Expand All @@ -98,7 +126,6 @@ You can define additional entries (or overwrite entries from the plugin) as foll
```
// optional configuration if required
javaModuleDependencies {
// Make an automatic module known
moduleNameToGA.put("org.apache.commons.lang3", "org.apache.commons:commons-lang3")
}
```
Expand All @@ -124,7 +151,8 @@ If you have a `prefixOfYourChoice`, all your Modules **need to have the same pre
## Define Module versions in a Platform project as Dependency Constraints

Use Gradle's dependency constraints and/or platforms to define versions for the modules you depend on.
Inside a `javaModuleDependencies { }` block, you can use the `gav("module.name", "1.0")` notation to define a version by Module Name instead of coordinates.
For that the plugin offers a `moduleInfo { }` block in `java-platform` projects.
In that block, you have the `version("module.name", "1.0")` notation to define a version by Module Name instead of coordinates.
For libraries that consist of multiple components and have a BOM for version management, you might prefer to include the BOM, which you need to do by coordinates, because a BOM does not have a Module Name.

```
Expand All @@ -134,12 +162,10 @@ plugins {
}
// Define versions for Modules via the Module Name
dependencies.constraints {
javaModuleDependencies {
api(gav("org.apache.xmlbeans", "5.0.1"))
api(gav("org.slf4j", "1.7.28"))
api(gav("org.slf4j.simple", "1.7.28"))
}
moduleInfo {
version("org.apache.xmlbeans", "5.0.1")
version("org.slf4j", "2.0.7")
version("org.slf4j.simple", "2.0.7")
}
// Use BOMs for Modules that are part of a library of multiple Modules
Expand Down Expand Up @@ -205,22 +231,20 @@ $ ./gradlew :app:recommendModuleVersions -q
Latest Stable Versions of Java Modules - use in your platform project's build.gradle(.kts)
==========================================================================================
dependencies.constraints {
javaModuleDependencies {
api(gav("com.fasterxml.jackson.annotation", "2.13.2"))
api(gav("com.fasterxml.jackson.core", "2.13.2"))
api(gav("com.fasterxml.jackson.databind", "2.13.2.2"))
api(gav("org.apache.logging.log4j", "2.17.2"))
api(gav("org.apache.xmlbeans", "5.0.3"))
api(gav("org.junit.jupiter.api", "5.8.2"))
api(gav("org.junit.jupiter.engine", "5.8.2"))
api(gav("org.junit.platform.commons", "1.8.2"))
api(gav("org.junit.platform.engine", "1.8.2"))
api(gav("org.junit.platform.launcher", "1.8.2"))
api(gav("org.opentest4j", "1.2.0"))
api(gav("org.slf4j", "1.7.36"))
api(gav("org.slf4j.simple", "1.7.36"))
}
moduleInfo {
version("com.fasterxml.jackson.annotation", "2.13.2")
version("com.fasterxml.jackson.core", "2.13.2")
version("com.fasterxml.jackson.databind", "2.13.2.2")
version("org.apache.logging.log4j", "2.17.2")
version("org.apache.xmlbeans", "5.0.3")
version("org.junit.jupiter.api", "5.8.2")
version("org.junit.jupiter.engine", "5.8.2")
version("org.junit.platform.commons", "1.8.2")
version("org.junit.platform.engine", "1.8.2")
version("org.junit.platform.launcher", "1.8.2")
version("org.opentest4j", "1.2.0")
version("org.slf4j", "1.7.36")
version("org.slf4j.simple", "1.7.36")
}
```

Expand Down
5 changes: 5 additions & 0 deletions build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,11 @@ pluginPublishConventions {
}
}

gradlePlugin.plugins.create("java-module-versions") {
id = "${project.group}.${name}"
implementationClass = "org.gradlex.javamodule.dependencies.JavaModuleVersionsPlugin"
}

tasks.test {
useJUnitPlatform()
maxParallelForks = 4
Expand Down
24 changes: 24 additions & 0 deletions samples/module-info-dsl-no-platform/app/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
plugins {
id("org.example.java-module-app")
}

application {
applicationDefaultJvmArgs = listOf("-ea")
mainClass.set("org.example.app.App")
mainModule.set("org.example.app")
}

mainModuleInfo {
runtimeOnly("org.slf4j.simple")
}

testModuleInfo {
requires("org.junit.jupiter.api")
}

moduleInfo {
version("org.slf4j", "2.0.7")
version("org.slf4j.simple", "2.0.7")
version("com.fasterxml.jackson.databind", "2.14.0")
version("org.junit.jupiter.api", "5.9.3")
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
module org.example.app {
requires org.example.lib;
requires org.slf4j;

exports org.example.app;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package org.example.app;

import org.example.lib.Lib;
import org.slf4j.LoggerFactory;

public class App {

public static void main(String[] args) {
LoggerFactory.getLogger(App.class).info("App running...");
doWork();
}

public static void doWork() {
new Lib();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package org.example.app;

import org.example.lib.Lib;
import org.junit.jupiter.api.Test;

import java.io.IOException;
import java.io.InputStream;

import static java.nio.charset.StandardCharsets.UTF_8;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull;

public class AppTest {

@Test
public void testApp() throws IOException {
assertEquals("org.example.lib", Lib.class.getModule().getName());
assertEquals("org.example.app", App.class.getModule().getName());
assertEquals("org.example.app", AppTest.class.getModule().getName());
try (InputStream is = AppTest.class.getResourceAsStream("/data.txt")) {
assertNotNull(is);
assertEquals("ABC", new String(is.readAllBytes(), UTF_8));
}
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
ABC
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
open module org.example.app.test.functional {
requires org.example.app;
requires org.junit.jupiter.api;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package org.example.app.test;

import org.junit.jupiter.api.Test;
import org.example.app.App;

import java.io.IOException;
import java.io.InputStream;

import static java.nio.charset.StandardCharsets.UTF_8;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull;

public class AppFunctionalTest {

@Test
void testAppFunctional() throws IOException {
assertEquals("org.example.app", App.class.getModule().getName());
assertEquals("org.example.app.test.functional", AppFunctionalTest.class.getModule().getName());
try (InputStream is = AppFunctionalTest.class.getResourceAsStream("/data.txt")) {
assertNotNull(is);
assertEquals("DEF", new String(is.readAllBytes(), UTF_8));
}
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
DEF
3 changes: 3 additions & 0 deletions samples/module-info-dsl-no-platform/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
plugins {
id("org.example.root")
}
38 changes: 38 additions & 0 deletions samples/module-info-dsl-no-platform/build.out
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
> Task :lib:compileJava
> Task :lib:processResources NO-SOURCE
> Task :lib:classes
> Task :lib:jar
> Task :app:compileJava
> Task :app:processResources NO-SOURCE
> Task :app:classes
> Task :app:jar
> Task :app:startScripts
> Task :app:distTar
> Task :app:distZip
> Task :app:assemble
> Task :app:compileTestJava
> Task :app:processTestResources
> Task :app:testClasses
> Task :app:test
> Task :app:compileTestFunctionalJava
> Task :app:processTestFunctionalResources
> Task :app:testFunctionalClasses
> Task :app:testFunctionalJar
> Task :app:testFunctional
> Task :app:check
> Task :app:build
> Task :lib:assemble
> Task :lib:compileTestJava
> Task :lib:processTestResources
> Task :lib:testClasses
> Task :lib:test
> Task :lib:compileTestFunctionalJava
> Task :lib:processTestFunctionalResources
> Task :lib:testFunctionalClasses
> Task :lib:testFunctionalJar
> Task :lib:testFunctional
> Task :lib:check
> Task :lib:build

> Task :app:run
[main] INFO org.example.app.App - App running...
2 changes: 2 additions & 0 deletions samples/module-info-dsl-no-platform/build.sample.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
executable: gradlew
expected-output-file: build.out
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
plugins {
`kotlin-dsl`
}

dependencies {
implementation("com.autonomousapps:dependency-analysis-gradle-plugin:1.20.0")
implementation("org.gradlex:java-module-dependencies:1.3.1")
implementation("org.gradlex:java-module-testing:1.2")
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
dependencyResolutionManagement {
repositories.gradlePluginPortal()
}

// This is for testing against the latest version of the plugin, remove if you copied this for a real project
includeBuild(extra.properties["pluginLocation"] ?: rootDir.parentFile.parentFile.parentFile.parent)
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
plugins {
id("java")
id("org.gradlex.java-module-dependencies")
id("org.gradlex.java-module-testing")
}

group = "org.example"

java.toolchain.languageVersion.set(JavaLanguageVersion.of(17))
testing.suites.register<JvmTestSuite>("testFunctional")
tasks.check { dependsOn(tasks.named("testFunctional")) }

javaModuleDependencies {
versionsFromPlatformAndConsistentResolution(":app", ":app")
}

tasks.withType<Test>().configureEach {
jvmArgs("-Dorg.slf4j.simpleLogger.defaultLogLevel=error")
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
plugins {
id("org.example.java-base")
id("application")
id("org.gradlex.java-module-versions")
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
plugins {
id("org.example.java-base")
id("java-library")
}

Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
plugins {
id("com.autonomousapps.dependency-analysis")
}
7 changes: 7 additions & 0 deletions samples/module-info-dsl-no-platform/lib/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
plugins {
id("org.example.java-module")
}

testModuleInfo {
requires("org.junit.jupiter.api")
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
module org.example.lib {
requires transitive com.fasterxml.jackson.databind;

requires java.logging; // JDK module

exports org.example.lib;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package org.example.lib;

import com.fasterxml.jackson.databind.ObjectMapper;

public class Lib {

public void process(ObjectMapper mapper) {

}
}
Loading