Skip to content

Commit 9c2574d

Browse files
authored
Fix #1562: Move module-info.class to jar root level (/module-info.class) from under META-INF/versions/17 (#1563)
1 parent b2b591e commit 9c2574d

File tree

3 files changed

+110
-30
lines changed

3 files changed

+110
-30
lines changed

pom.xml

Lines changed: 34 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -184,33 +184,6 @@ tools.jackson.core.*;version=${project.version}
184184
<artifactId>cyclonedx-maven-plugin</artifactId>
185185
</plugin>
186186

187-
<!-- 10-Jan-2025, tatu: [core#1380] Still need to use Moditect to
188-
work around bug/misfeature of maven-shade-plugin where it absolutely
189-
removes root-level `module-info.class`. So use Moditect to put it back
190-
(but from diff place than with Jackson 2.x)
191-
-->
192-
<plugin>
193-
<groupId>org.moditect</groupId>
194-
<artifactId>moditect-maven-plugin</artifactId>
195-
<executions>
196-
<execution>
197-
<id>add-module-infos</id>
198-
<phase>package</phase>
199-
<goals>
200-
<goal>add-module-info</goal>
201-
</goals>
202-
<configuration>
203-
<overwriteExistingFiles>true</overwriteExistingFiles>
204-
<module>
205-
<moduleInfoFile>src/main/java/module-info.java</moduleInfoFile>
206-
</module>
207-
</configuration>
208-
</execution>
209-
</executions>
210-
<configuration>
211-
<jvmVersion>17</jvmVersion>
212-
</configuration>
213-
</plugin>
214187
<!-- 03-Nov-2020, tatu: Add LICENSE from main level -->
215188
<plugin>
216189
<groupId>org.codehaus.mojo</groupId>
@@ -305,6 +278,36 @@ tools.jackson.core.*;version=${project.version}
305278
</execution>
306279
</executions>
307280
</plugin>
281+
<!-- 10-Jan-2025, tatu: [core#1380] Use Moditect to add `module-info.class`
282+
at JAR root level. Must run AFTER shade plugin (declared after it here
283+
so Maven executes it later in `package` phase) so shade cannot strip it.
284+
Override parent's jvmVersion=17 via combine.self="override" so that
285+
module-info.class is placed at root `/` rather than META-INF/versions/17/.
286+
-->
287+
<plugin>
288+
<groupId>org.moditect</groupId>
289+
<artifactId>moditect-maven-plugin</artifactId>
290+
<executions>
291+
<execution>
292+
<id>add-module-infos</id>
293+
<phase>package</phase>
294+
<goals>
295+
<goal>add-module-info</goal>
296+
</goals>
297+
<configuration>
298+
<overwriteExistingFiles>true</overwriteExistingFiles>
299+
<module>
300+
<moduleInfoFile>src/main/java/module-info.java</moduleInfoFile>
301+
</module>
302+
</configuration>
303+
</execution>
304+
</executions>
305+
<!-- Override parent's jvmVersion=17: no jvmVersion means module-info.class
306+
is placed at JAR root instead of META-INF/versions/17/
307+
-->
308+
<configuration combine.self="override">
309+
</configuration>
310+
</plugin>
308311
<plugin>
309312
<groupId>org.gradlex</groupId>
310313
<artifactId>gradle-module-metadata-maven-plugin</artifactId>
@@ -329,9 +332,10 @@ tools.jackson.core.*;version=${project.version}
329332
<Multi-Release>true</Multi-Release>
330333
</manifestEntries>
331334
</archive>
332-
<!-- 10-Jan-2025, tatu: [core#1380] Kludgerus Maximums... must actually
333-
remove `module-info.class` just so Moditect can add it in place
334-
where shade plugin will not filter it out. Oy vey.
335+
<!-- 10-Jan-2025, tatu: [core#1380] Exclude module-info.class from
336+
initial jar so that shade plugin never sees it (shade strips
337+
root-level module-info.class). Moditect re-adds it at root
338+
after shade runs (see moditect plugin declaration below shade).
335339
-->
336340
<excludes>
337341
<exclude>module-info.class</exclude>

release-notes/VERSION

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,11 @@ JSON library.
1919

2020
No changes since 3.1
2121

22+
3.1.1 (not yet released)
23+
24+
#1562: Move `module-info.class` to jar root level (`/module-info.class`)
25+
from under `META-INF/versions/17`
26+
2227
3.1.0 (23-Feb-2026)
2328

2429
#784: Optional leading plus sign not included in textual value of any
Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
package tools.jackson.core.it;
2+
3+
import java.io.File;
4+
import java.io.FileInputStream;
5+
import java.io.InputStream;
6+
import java.util.ArrayList;
7+
import java.util.List;
8+
import java.util.jar.JarEntry;
9+
import java.util.jar.JarInputStream;
10+
11+
import org.junit.jupiter.api.Test;
12+
13+
import static org.junit.jupiter.api.Assertions.*;
14+
15+
/**
16+
* Integration test for [core#1380]: {@code module-info.class} must be placed
17+
* at the root of the JAR ({@code /module-info.class}), not under
18+
* {@code META-INF/versions/}.
19+
*
20+
* @see <a href="https://github.com/FasterXML/jackson-core/issues/1380">[core#1380]</a>
21+
*
22+
* @since 3.1.1
23+
*/
24+
public class ModuleInfoIT
25+
{
26+
@Test
27+
public void moduleInfoAtRootLevel() throws Exception
28+
{
29+
File jarFile = findJacksonCoreJar();
30+
assertNotNull(jarFile, "Could not locate jackson-core JAR file");
31+
assertTrue(jarFile.exists(), "JAR file does not exist: " + jarFile);
32+
33+
boolean rootModuleInfo = false;
34+
List<String> versionedModuleInfos = new ArrayList<>();
35+
36+
try (InputStream is = new FileInputStream(jarFile);
37+
JarInputStream jarStream = new JarInputStream(is)) {
38+
JarEntry entry;
39+
while ((entry = jarStream.getNextJarEntry()) != null) {
40+
String name = entry.getName();
41+
if (name.equals("module-info.class")) {
42+
rootModuleInfo = true;
43+
} else if (name.startsWith("META-INF/versions/") && name.endsWith("/module-info.class")) {
44+
versionedModuleInfos.add(name);
45+
}
46+
}
47+
}
48+
49+
assertTrue(rootModuleInfo,
50+
"module-info.class must be at root of JAR (not only under META-INF/versions/)");
51+
assertTrue(versionedModuleInfos.isEmpty(),
52+
"module-info.class must NOT be under META-INF/versions/; found: " + versionedModuleInfos);
53+
}
54+
55+
private File findJacksonCoreJar() {
56+
File targetDir = new File("target");
57+
if (!targetDir.exists() || !targetDir.isDirectory()) {
58+
return null;
59+
}
60+
File[] jarFiles = targetDir.listFiles((dir, name) ->
61+
name.startsWith("jackson-core-") &&
62+
name.endsWith(".jar") &&
63+
!name.contains("sources") &&
64+
!name.contains("javadoc") &&
65+
!name.contains("tests"));
66+
if (jarFiles == null || jarFiles.length == 0) {
67+
return null;
68+
}
69+
return jarFiles[0];
70+
}
71+
}

0 commit comments

Comments
 (0)