Skip to content

Commit 89ceeba

Browse files
committed
Introduce a new DSL method for omiting unwanted service providers
Fixes #13
1 parent 1697c91 commit 89ceeba

File tree

4 files changed

+110
-2
lines changed

4 files changed

+110
-2
lines changed

README.md

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,3 +84,19 @@ configurations {
8484
## How do I add `provides ... with ...` declarations to the `module-info.class` descriptor?
8585

8686
The plugin will automatically retrofit all the available `META-INF/services/*` descriptors into `module-info.class` for you. The `META-INF/services/*` descriptors will be preserved so that a transformed JAR will continue to work if it is placed on the classpath.
87+
88+
The plugin also allows you to ignore some unwanted services from being automatically converted into `provides .. with ...` declarations.
89+
90+
```
91+
extraJavaModuleInfo {
92+
module("groovy-all-2.4.15.jar", "groovy.all", "2.4.15") {
93+
requiresTransitive("java.scripting")
94+
requires("java.logging")
95+
requires("java.desktop")
96+
ignoreServiceProvider("org.codehaus.groovy.runtime.ExtensionModule")
97+
ignoreServiceProvider("org.codehaus.groovy.plugins.Runners")
98+
ignoreServiceProvider("org.codehaus.groovy.source.Extensions")
99+
ignoreServiceProvider("org.codehaus.groovy.source.Extensions")
100+
}
101+
}
102+
```

src/functionalTest/groovy/de/jjohannes/gradle/javamodules/test/ExtraJavaModuleInfoTest.groovy

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -357,6 +357,82 @@ class ExtraJavaModuleInfoTest extends Specification {
357357
run().task(':run').outcome == TaskOutcome.SUCCESS
358358
}
359359

360+
def "can omit unwanted META-INF/services from automatic migration"() {
361+
given:
362+
new File(testFolder.root, "src/main/java/org/gradle/sample/app/data").mkdirs()
363+
364+
testFolder.newFile("src/main/java/org/gradle/sample/app/Main.java") << """
365+
package org.gradle.sample.app;
366+
367+
import java.util.ServiceLoader;
368+
import java.util.stream.Collectors;
369+
import javax.script.ScriptEngineFactory;
370+
import javax.script.ScriptException;
371+
372+
public class Main {
373+
374+
public static void main(String[] args) throws ScriptException {
375+
ScriptEngineFactory scriptEngineFactory = ServiceLoader.load(ScriptEngineFactory.class)
376+
.findFirst()
377+
.orElseThrow(() -> new AssertionError("No providers loaded"));
378+
String engineName = scriptEngineFactory.getEngineName();
379+
if (!engineName.equals("Groovy Scripting Engine")) {
380+
throw new AssertionError("Incorrect Script Engine Loaded: " + engineName);
381+
}
382+
int revVal = (int) scriptEngineFactory.getScriptEngine().eval("2+2");
383+
if (revVal != 4) {
384+
throw new AssertionError("Invalid evaluation result: " + revVal);
385+
}
386+
}
387+
388+
}
389+
"""
390+
testFolder.newFile("src/main/java/module-info.java") << """
391+
module org.gradle.sample.app {
392+
requires groovy.all;
393+
uses javax.script.ScriptEngineFactory;
394+
}
395+
"""
396+
testFolder.newFile("build.gradle.kts") << """
397+
plugins {
398+
application
399+
id("de.jjohannes.extra-java-module-info")
400+
}
401+
402+
repositories {
403+
mavenCentral()
404+
}
405+
406+
java {
407+
modularity.inferModulePath.set(true)
408+
}
409+
410+
dependencies {
411+
implementation("org.codehaus.groovy:groovy-all:2.4.15")
412+
}
413+
414+
extraJavaModuleInfo {
415+
module("groovy-all-2.4.15.jar", "groovy.all", "2.4.15") {
416+
requiresTransitive("java.scripting")
417+
requires("java.logging")
418+
requires("java.desktop")
419+
ignoreServiceProvider("org.codehaus.groovy.runtime.ExtensionModule")
420+
ignoreServiceProvider("org.codehaus.groovy.plugins.Runners")
421+
ignoreServiceProvider("org.codehaus.groovy.source.Extensions")
422+
ignoreServiceProvider("org.codehaus.groovy.source.Extensions")
423+
}
424+
}
425+
426+
application {
427+
mainModule.set("org.gradle.sample.app")
428+
mainClass.set("org.gradle.sample.app.Main")
429+
}
430+
"""
431+
432+
expect:
433+
run().task(':run').outcome == TaskOutcome.SUCCESS
434+
}
435+
360436
def "can add static/transitive 'requires' modifiers to legacy libraries"() {
361437
given:
362438
new File(testFolder.root, "src/main/java/org/gradle/sample/app/data").mkdirs()

src/main/java/de/jjohannes/gradle/javamodules/ExtraModuleInfoTransform.java

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -162,7 +162,7 @@ private static Map<String, String[]> copyAndExtractProviders(JarInputStream inpu
162162
byte[] content = inputStream.readAllBytes();
163163
String entryName = jarEntry.getName();
164164
if (entryName.startsWith(SERVICES_PREFIX) && !entryName.equals(SERVICES_PREFIX)) {
165-
providers.put(entryName.substring(SERVICES_PREFIX.length()).replace('.','/'), extractImplementations(content));
165+
providers.put(entryName.substring(SERVICES_PREFIX.length()), extractImplementations(content));
166166
}
167167
outputStream.putNextEntry(jarEntry);
168168
outputStream.write(content);
@@ -201,7 +201,11 @@ private static byte[] addModuleInfo(ModuleInfo moduleInfo, Map<String, String[]>
201201
moduleVisitor.visitRequire(requireName, Opcodes.ACC_STATIC_PHASE, null);
202202
}
203203
for (Map.Entry<String, String[]> entry : providers.entrySet()) {
204-
moduleVisitor.visitProvide(entry.getKey(), entry.getValue());
204+
String name = entry.getKey();
205+
String[] implementations = entry.getValue();
206+
if (!moduleInfo.getIgnoredServiceProviders().contains(name)) {
207+
moduleVisitor.visitProvide(name.replace('.', '/'), implementations);
208+
}
205209
}
206210
moduleVisitor.visitEnd();
207211
classWriter.visitEnd();

src/main/java/de/jjohannes/gradle/javamodules/ModuleInfo.java

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,9 @@
1717

1818
import java.io.Serializable;
1919
import java.util.ArrayList;
20+
import java.util.LinkedHashSet;
2021
import java.util.List;
22+
import java.util.Set;
2123

2224
/**
2325
* Data class to hold the information that should be added as module-info.class to an existing Jar file.
@@ -29,6 +31,7 @@ public class ModuleInfo implements Serializable {
2931
private List<String> requires = new ArrayList<>();
3032
private List<String> requiresTransitive = new ArrayList<>();
3133
private List<String> requiresStatic = new ArrayList<>();
34+
private Set<String> ignoredServiceProviders = new LinkedHashSet<>();
3235

3336
ModuleInfo(String moduleName, String moduleVersion) {
3437
this.moduleName = moduleName;
@@ -51,6 +54,10 @@ public void requiresStatic(String requiresStatic) {
5154
this.requiresStatic.add(requiresStatic);
5255
}
5356

57+
public void ignoreServiceProvider(String ignoreServiceProvider) {
58+
this.ignoredServiceProviders.add(ignoreServiceProvider);
59+
}
60+
5461
public String getModuleName() {
5562
return moduleName;
5663
}
@@ -74,4 +81,9 @@ protected List<String> getRequiresTransitive() {
7481
protected List<String> getRequiresStatic() {
7582
return requiresStatic;
7683
}
84+
85+
protected Set<String> getIgnoredServiceProviders() {
86+
return ignoredServiceProviders;
87+
}
88+
7789
}

0 commit comments

Comments
 (0)