Skip to content

Commit dd3d198

Browse files
authored
Check that 'Automatic-Module-Names' are not changed accidentally (#85)
See #79
1 parent 7148906 commit dd3d198

File tree

3 files changed

+99
-6
lines changed

3 files changed

+99
-6
lines changed

src/main/java/org/gradlex/javamodule/moduleinfo/ExtraJavaModuleInfoTransform.java

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -64,9 +64,9 @@
6464
import java.util.zip.ZipEntry;
6565
import java.util.zip.ZipException;
6666

67-
import static org.gradlex.javamodule.moduleinfo.ModuleNameUtil.automaticModulNameFromFileName;
6867
import static org.gradlex.javamodule.moduleinfo.FilePathToModuleCoordinates.gaCoordinatesFromFilePathMatch;
6968
import static org.gradlex.javamodule.moduleinfo.FilePathToModuleCoordinates.versionFromFilePath;
69+
import static org.gradlex.javamodule.moduleinfo.ModuleNameUtil.automaticModulNameFromFileName;
7070

7171
/**
7272
* An artifact transform that applies additional information to Jars without module information.
@@ -130,18 +130,28 @@ public void transform(TransformOutputs outputs) {
130130
if (realModule && !((ModuleInfo) moduleSpec).patchRealModule) {
131131
throw new RuntimeException("Patching of real modules must be explicitly enabled with 'patchRealModule()'");
132132
}
133+
String definedName = moduleSpec.getModuleName();
134+
String expectedName = autoModuleName(originalJar);
135+
if (expectedName != null && !definedName.equals(expectedName) && !moduleSpec.overrideModuleName) {
136+
throw new RuntimeException("The name '" + definedName + "' is different than the Automatic-Module-Name '" + expectedName + "'; explicitly allow override via 'overrideName()'");
137+
}
133138
addModuleDescriptor(originalJar, getModuleJar(outputs, originalJar), (ModuleInfo) moduleSpec);
134139
} else if (moduleSpec instanceof AutomaticModuleName) {
135140
if (realModule) {
136141
throw new RuntimeException("Patching of real modules must be explicitly enabled with 'patchRealModule()' and can only be done with 'module()'");
137142
}
143+
String definedName = moduleSpec.getModuleName();
144+
String expectedName = autoModuleName(originalJar);
145+
if (expectedName != null && (moduleSpec.getMergedJars().isEmpty() || !definedName.equals(expectedName)) && !moduleSpec.overrideModuleName) {
146+
throw new RuntimeException("'" + definedName + "' already has the Automatic-Module-Name '" + expectedName + "'; explicitly allow override via 'overrideName()'");
147+
}
138148
if (parameters.getFailOnAutomaticModules().get()) {
139149
throw new RuntimeException("Use of 'automaticModule()' is prohibited. Use 'module()' instead: " + originalJar.getName());
140150
}
141151
addAutomaticModuleName(originalJar, getModuleJar(outputs, originalJar), (AutomaticModuleName) moduleSpec);
142152
} else if (realModule) {
143153
outputs.file(originalJar);
144-
} else if (isAutoModule(originalJar)) {
154+
} else if (autoModuleName(originalJar) != null) {
145155
if (parameters.getFailOnAutomaticModules().get()) {
146156
throw new RuntimeException("Found an automatic module: " + originalJar.getName());
147157
}
@@ -210,10 +220,11 @@ private boolean containsMultiReleaseJarEntry(JarInputStream jarStream) {
210220
return manifest != null && Boolean.parseBoolean(manifest.getMainAttributes().getValue("Multi-Release"));
211221
}
212222

213-
private boolean isAutoModule(File jar) {
223+
@Nullable
224+
private String autoModuleName(File jar) {
214225
try (JarInputStream inputStream = new JarInputStream(Files.newInputStream(jar.toPath()))) {
215226
Manifest manifest = inputStream.getManifest();
216-
return manifest != null && manifest.getMainAttributes().getValue("Automatic-Module-Name") != null;
227+
return manifest != null ? manifest.getMainAttributes().getValue("Automatic-Module-Name") : null;
217228
} catch (IOException e) {
218229
throw new RuntimeException(e);
219230
}

src/main/java/org/gradlex/javamodule/moduleinfo/ModuleSpec.java

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,8 @@ public abstract class ModuleSpec implements Serializable {
3636
private final String moduleName;
3737
private final List<String> mergedJars = new ArrayList<>();
3838

39+
boolean overrideModuleName;
40+
3941
protected ModuleSpec(String identifier, String moduleName) {
4042
validateIdentifier(identifier);
4143
validateModuleName(moduleName);
@@ -77,4 +79,11 @@ public void mergeJar(Provider<MinimalExternalModuleDependency> alias) {
7779
public List<String> getMergedJars() {
7880
return mergedJars;
7981
}
82+
83+
/**
84+
* If the Module already has an Automatic-Module-Name, allow changing that name
85+
*/
86+
public void overrideModuleName() {
87+
this.overrideModuleName = true;
88+
}
8089
}

src/test/groovy/org/gradlex/javamodule/moduleinfo/test/EdgeCasesFunctionalTest.groovy

Lines changed: 75 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -158,7 +158,7 @@ class EdgeCasesFunctionalTest extends Specification {
158158
module org.gradle.sample.app {
159159
exports org.gradle.sample.app;
160160
161-
requires org.kohsuke.github;
161+
requires org.kohsuke.github.api;
162162
}
163163
"""
164164
buildFile << """
@@ -167,7 +167,7 @@ class EdgeCasesFunctionalTest extends Specification {
167167
}
168168
169169
extraJavaModuleInfo {
170-
module("org.kohsuke:github-api", "org.kohsuke.github") {
170+
module("org.kohsuke:github-api", "org.kohsuke.github.api") {
171171
exportAllPackages()
172172
requires("org.apache.commons.lang3")
173173
}
@@ -194,4 +194,77 @@ class EdgeCasesFunctionalTest extends Specification {
194194
def result = failRun()
195195
result.output.contains "nd4j.native.api: Invalid module name: 'native' is not a Java identifier"
196196
}
197+
198+
def "fail if module name does not correspond to Automatic-Module-Name - module"() {
199+
given:
200+
buildFile << """
201+
dependencies {
202+
implementation("org.apache.commons:commons-lang3:3.10")
203+
}
204+
205+
extraJavaModuleInfo {
206+
module("org.apache.commons:commons-lang3", "org.apache.commons.lang") {
207+
exportAllPackages()
208+
}
209+
}
210+
"""
211+
212+
expect:
213+
def result = failRun()
214+
result.output.contains "The name 'org.apache.commons.lang' is different than the Automatic-Module-Name 'org.apache.commons.lang3'; explicitly allow override via 'overrideName()'"
215+
}
216+
217+
def "fail if module name does not correspond to Automatic-Module-Name - automaticModule"() {
218+
given:
219+
buildFile << """
220+
dependencies {
221+
implementation("org.apache.commons:commons-lang3:3.10")
222+
}
223+
224+
extraJavaModuleInfo {
225+
automaticModule("org.apache.commons:commons-lang3", "org.apache.commons.lang")
226+
}
227+
"""
228+
229+
expect:
230+
def result = failRun()
231+
result.output.contains "'org.apache.commons.lang' already has the Automatic-Module-Name 'org.apache.commons.lang3'; explicitly allow override via 'overrideName()'"
232+
}
233+
234+
def "do not fail if overrideModuleName is set - module"() {
235+
given:
236+
buildFile << """
237+
dependencies {
238+
implementation("org.apache.commons:commons-lang3:3.10")
239+
}
240+
241+
extraJavaModuleInfo {
242+
module("org.apache.commons:commons-lang3", "org.apache.commons.lang") {
243+
overrideModuleName()
244+
exportAllPackages()
245+
}
246+
}
247+
"""
248+
249+
expect:
250+
build()
251+
}
252+
253+
def "do not fail if overrideModuleName is set - automaticModule"() {
254+
given:
255+
buildFile << """
256+
dependencies {
257+
implementation("org.apache.commons:commons-lang3:3.10")
258+
}
259+
260+
extraJavaModuleInfo {
261+
automaticModule("org.apache.commons:commons-lang3", "org.apache.commons.lang") {
262+
overrideModuleName()
263+
}
264+
}
265+
"""
266+
267+
expect:
268+
build()
269+
}
197270
}

0 commit comments

Comments
 (0)