Skip to content

Commit 8e5fbdb

Browse files
Marcono1234aalmiray
authored andcommitted
Generate multi-release directory JAR entries
1 parent 2bd52fe commit 8e5fbdb

2 files changed

Lines changed: 55 additions & 7 deletions

File tree

core/src/main/java/org/moditect/commands/AddModuleInfo.java

Lines changed: 32 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,12 @@
1616
import java.nio.file.StandardCopyOption;
1717
import java.nio.file.attribute.FileTime;
1818
import java.time.Instant;
19+
import java.util.Arrays;
20+
import java.util.Collections;
1921
import java.util.Enumeration;
22+
import java.util.HashSet;
23+
import java.util.List;
24+
import java.util.Set;
2025
import java.util.jar.Attributes;
2126
import java.util.jar.JarEntry;
2227
import java.util.jar.JarFile;
@@ -39,6 +44,7 @@ public class AddModuleInfo {
3944
private static final int DEFAULT_BUFFER_SIZE = 8192;
4045
private static final String NO_JVM_VERSION = "base";
4146
private static final String MANIFEST_ENTRY_NAME = "META-INF/MANIFEST.MF";
47+
private static final String META_INF_VERSIONS_DIR = "META-INF/versions/";
4248
private static final String MODULE_INFO_CLASS = "module-info.class";
4349

4450
private final String moduleInfoSource;
@@ -107,18 +113,31 @@ public void run() {
107113
}
108114

109115
boolean versionedModuleInfo = jvmVersion != null;
110-
String versionedModuleInfoClass = "META-INF/versions/" + jvmVersion + "/" + MODULE_INFO_CLASS;
116+
String moduleInfoDir = versionedModuleInfo ? META_INF_VERSIONS_DIR + jvmVersion + "/" : "";
117+
String moduleInfoEntryName = moduleInfoDir + MODULE_INFO_CLASS;
111118
long lastModifiedTime = toFileTime(timestamp).toMillis();
112119

120+
// For compatibility with Eclipse IDE create directory entries for the multi-version dir
121+
// See https://github.com/moditect/moditect/issues/254
122+
List<String> dirEntriesToCreate = Collections.emptyList();
123+
if (versionedModuleInfo) {
124+
dirEntriesToCreate = Arrays.asList(META_INF_VERSIONS_DIR, moduleInfoDir);
125+
}
126+
127+
Set<String> overwrittenEntries = new HashSet<>();
128+
overwrittenEntries.add(moduleInfoEntryName);
129+
overwrittenEntries.addAll(dirEntriesToCreate);
130+
113131
// brute force copy all entries
114132
try (JarFile jarFile = new JarFile(inputJar.toAbsolutePath().toFile());
115133
JarOutputStream jarout = new JarOutputStream(Files.newOutputStream(tmpOutputJar.toAbsolutePath(), TRUNCATE_EXISTING))) {
116134
Enumeration<JarEntry> entries = jarFile.entries();
117135
while (entries.hasMoreElements()) {
118136
JarEntry inputEntry = entries.nextElement();
137+
String entryName = inputEntry.getName();
119138

120139
// manifest requires extra care due to MRJARs
121-
if (MANIFEST_ENTRY_NAME.equals(inputEntry.getName()) && versionedModuleInfo) {
140+
if (versionedModuleInfo && MANIFEST_ENTRY_NAME.equals(entryName)) {
122141
Manifest manifest = jarFile.getManifest();
123142
if (null == manifest) {
124143
manifest = new Manifest();
@@ -128,28 +147,34 @@ public void run() {
128147
ByteArrayOutputStream baos = new ByteArrayOutputStream();
129148
manifest.write(baos);
130149

131-
JarEntry outputEntry = new JarEntry(inputEntry.getName());
150+
JarEntry outputEntry = new JarEntry(entryName);
132151
outputEntry.setTime(lastModifiedTime);
133152
jarout.putNextEntry(outputEntry);
134153
jarout.write(baos.toByteArray(), 0, baos.size());
135154
jarout.closeEntry();
136155
}
137-
else if ((MODULE_INFO_CLASS.equals(inputEntry.getName()) && !versionedModuleInfo) ||
138-
(versionedModuleInfoClass.equals(inputEntry.getName()) && versionedModuleInfo)) {
156+
else if (overwrittenEntries.contains(entryName)) {
139157
// skip this entry as we'll overwrite it
140158
}
141159
else {
142160
// copy entry as is, set timestamp
143-
JarEntry outputEntry = new JarEntry(inputEntry.getName());
161+
JarEntry outputEntry = new JarEntry(entryName);
144162
outputEntry.setTime(lastModifiedTime);
145163
jarout.putNextEntry(outputEntry);
146164
copy(jarFile.getInputStream(inputEntry), jarout);
147165
jarout.closeEntry();
148166
}
149167
}
150168

169+
for (String dirEntryName : dirEntriesToCreate) {
170+
JarEntry dirEntry = new JarEntry(dirEntryName);
171+
dirEntry.setTime(lastModifiedTime);
172+
jarout.putNextEntry(dirEntry);
173+
jarout.closeEntry();
174+
}
175+
151176
// copy module descriptor
152-
JarEntry outputEntry = versionedModuleInfo ? new JarEntry(versionedModuleInfoClass) : new JarEntry(MODULE_INFO_CLASS);
177+
JarEntry outputEntry = new JarEntry(moduleInfoEntryName);
153178
outputEntry.setTime(lastModifiedTime);
154179
jarout.putNextEntry(outputEntry);
155180
jarout.write(clazz, 0, clazz.length);

core/src/test/java/org/moditect/test/AddModuleInfoTest.java

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,11 +20,15 @@
2020
import java.nio.file.SimpleFileVisitor;
2121
import java.nio.file.StandardCopyOption;
2222
import java.nio.file.attribute.BasicFileAttributes;
23+
import java.util.ArrayList;
24+
import java.util.List;
2325
import java.util.Optional;
2426
import java.util.jar.Attributes;
2527
import java.util.jar.JarEntry;
2628
import java.util.jar.JarOutputStream;
2729
import java.util.jar.Manifest;
30+
import java.util.zip.ZipEntry;
31+
import java.util.zip.ZipFile;
2832

2933
import javax.tools.JavaFileObject;
3034
import javax.tools.StandardLocation;
@@ -37,6 +41,8 @@
3741
import com.google.testing.compile.Compiler;
3842
import com.google.testing.compile.JavaFileObjects;
3943

44+
import static org.junit.Assert.assertEquals;
45+
4046
/**
4147
* @author Gunnar Morling
4248
*/
@@ -93,6 +99,10 @@ public void addJvmVersionModuleInfoAndRunModular() throws Exception {
9399
.run();
94100

95101
Path outputJar = GENERATED_TEST_MODULES.resolve(inputJar.getFileName());
102+
assertJarEntries(outputJar,
103+
List.of("META-INF/MANIFEST.MF", "com/", "com/example/", "com/example/HelloWorld.class",
104+
"META-INF/versions/", "META-INF/versions/9/", "META-INF/versions/9/module-info.class"));
105+
96106
builder = new ProcessBuilder(
97107
JAVA_BIN, "--module-path", outputJar.toString(), "--module", "com.example");
98108

@@ -193,6 +203,9 @@ public void addModuleInfoAndRunModular() throws Exception {
193203
.run();
194204

195205
Path outputJar = GENERATED_TEST_MODULES.resolve(inputJar.getFileName());
206+
assertJarEntries(outputJar,
207+
List.of("META-INF/MANIFEST.MF", "com/", "com/example/", "com/example/HelloWorld.class", "module-info.class"));
208+
196209
builder = new ProcessBuilder(
197210
JAVA_BIN, "--module-path", outputJar.toString(), "--module", "com.example");
198211

@@ -307,4 +320,14 @@ private Path prepareTestJar() throws Exception {
307320

308321
return exampleJar;
309322
}
323+
324+
private void assertJarEntries(Path jarPath, List<String> expectedEntries) throws Exception {
325+
List<String> entries = new ArrayList<>();
326+
// Read as ZIP instead of JAR to avoid any special handling of META-INF by JarFile or JarInputStream
327+
try (ZipFile zipFile = new ZipFile(jarPath.toFile())) {
328+
zipFile.stream().map(ZipEntry::getName).forEach(entries::add);
329+
}
330+
331+
assertEquals(expectedEntries, entries);
332+
}
310333
}

0 commit comments

Comments
 (0)