Skip to content

Commit a38969c

Browse files
committed
Split out extractModuleNameFromJar into smaller steps
1 parent 1266847 commit a38969c

File tree

1 file changed

+87
-63
lines changed

1 file changed

+87
-63
lines changed

build-tools/src/main/java/org/elasticsearch/gradle/plugin/GenerateTestBuildInfoTask.java

Lines changed: 87 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -170,89 +170,113 @@ private java.util.Optional<String> extractClassNameFromJar(JarFile jarFile) {
170170
}
171171

172172
/**
173-
* look through the jar for the module name with each step commented inline;
174-
* the algorithm used here is based on the described in {@link ModuleFinder#of}
173+
* Look through the jar for the module name using a succession of techniques corresponding
174+
* to how the JDK itself determines module names,
175+
* as documented in {@link java.lang.module.ModuleFinder#of}.
175176
*/
176177
private String extractModuleNameFromJar(File file, JarFile jarFile) throws IOException {
177178
String moduleName = null;
178179

179-
// if the jar is multi-release, there will be a set versions
180-
// under the path META-INF/versions/<version number>;
181-
// each version will have its own module-info.class if this is a modular jar;
182-
// look for the module name in the module-info from the latest version
183-
// fewer than or equal to the current JVM version
184180
if (jarFile.isMultiRelease()) {
185-
List<Integer> versions = jarFile.stream()
186-
.filter(je -> je.getName().startsWith(META_INF_VERSIONS_PREFIX) && je.getName().endsWith("/module-info.class"))
187-
.map(
188-
je -> Integer.parseInt(
189-
je.getName().substring(META_INF_VERSIONS_PREFIX.length(), je.getName().length() - META_INF_VERSIONS_PREFIX.length())
190-
)
191-
)
192-
.toList();
193-
versions = new ArrayList<>(versions);
194-
versions.sort(Integer::compareTo);
195-
versions = versions.reversed();
196-
int major = Runtime.version().feature();
197-
StringBuilder path = new StringBuilder("META-INF/versions/");
198-
for (int version : versions) {
199-
if (version <= major) {
200-
path.append(version);
201-
break;
202-
}
203-
}
204-
if (path.length() > META_INF_VERSIONS_PREFIX.length()) {
205-
path.append("/module-info.class");
206-
JarEntry moduleEntry = jarFile.getJarEntry(path.toString());
207-
if (moduleEntry != null) {
208-
try (InputStream inputStream = jarFile.getInputStream(moduleEntry)) {
209-
moduleName = extractModuleNameFromModuleInfo(inputStream);
210-
}
211-
}
181+
StringBuilder dir = versionDirectoryIfExists(jarFile);
182+
if (dir != null) {
183+
dir.append("/module-info.class");
184+
moduleName = getModuleNameFromModuleInfoFile(dir.toString(), jarFile);
212185
}
213186
}
214187

215-
// if the jar is *not* multi-release then first look in
216-
// module-info.class from the top-level if it exists
217188
if (moduleName == null) {
218-
JarEntry moduleEntry = jarFile.getJarEntry("module-info.class");
219-
if (moduleEntry != null) {
220-
try (InputStream inputStream = jarFile.getInputStream(moduleEntry)) {
221-
moduleName = extractModuleNameFromModuleInfo(inputStream);
222-
}
223-
}
189+
moduleName = getModuleNameFromModuleInfoFile("module-info.class", jarFile);
224190
}
225191

226-
// if the jar does *not* contain module-info.class
227-
// check the manifest file for the module name
228192
if (moduleName == null) {
229-
JarEntry manifestEntry = jarFile.getJarEntry("META-INF/MANIFEST.MF");
230-
if (manifestEntry != null) {
231-
try (InputStream inputStream = jarFile.getInputStream(manifestEntry)) {
232-
Manifest manifest = new Manifest(inputStream);
233-
String amn = manifest.getMainAttributes().getValue("Automatic-Module-Name");
234-
if (amn != null) {
235-
moduleName = amn;
236-
}
237-
}
238-
}
193+
moduleName = getAutomaticModuleNameFromManifest(jarFile);
239194
}
240195

241-
// if the jar does not have module-info.class and no module name in the manifest
242-
// default to the jar name without .jar and no versioning
243196
if (moduleName == null) {
244-
String jn = file.getName().substring(0, file.getName().length() - JAR_DESCRIPTOR_SUFFIX.length());
245-
Matcher matcher = Pattern.compile("-(\\d+(\\.|$))").matcher(jn);
246-
if (matcher.find()) {
247-
jn = jn.substring(0, matcher.start());
248-
}
249-
jn = jn.replaceAll("[^A-Za-z0-9]", ".");
250-
moduleName = jn;
197+
moduleName = deriveModuleNameFromJarFileName(file);
251198
}
252199

253200
return moduleName;
254201
}
255202

203+
/**
204+
* if the jar is multi-release, there will be a set versions
205+
* under the path META-INF/versions/<version number>;
206+
* each version will have its own module-info.class if this is a modular jar;
207+
* look for the module name in the module-info from the latest version
208+
* fewer than or equal to the current JVM version
209+
*
210+
* @return a {@link StringBuilder} with the {@code META-INF/versions/<version number>} if it exists; otherwise null
211+
*/
212+
private static StringBuilder versionDirectoryIfExists(JarFile jarFile) {
213+
List<Integer> versions = jarFile.stream()
214+
.filter(je -> je.getName().startsWith(META_INF_VERSIONS_PREFIX) && je.getName().endsWith("/module-info.class"))
215+
.map(
216+
je -> Integer.parseInt(
217+
je.getName().substring(META_INF_VERSIONS_PREFIX.length(), je.getName().length() - META_INF_VERSIONS_PREFIX.length())
218+
)
219+
)
220+
.toList();
221+
versions = new ArrayList<>(versions);
222+
versions.sort(Integer::compareTo);
223+
versions = versions.reversed();
224+
int major = Runtime.version().feature();
225+
StringBuilder path = new StringBuilder(META_INF_VERSIONS_PREFIX);
226+
for (int version : versions) {
227+
if (version <= major) {
228+
return path.append(version);
229+
}
230+
}
231+
return null;
232+
}
233+
234+
/**
235+
* Looks into the specified {@code module-info.class} file, if it exists, and extracts the declared name of the module.
236+
* @return the module name, or null if there is no such {@code module-info.class} file.
237+
*/
238+
private String getModuleNameFromModuleInfoFile(String moduleInfoFileName, JarFile jarFile) throws IOException {
239+
JarEntry moduleEntry = jarFile.getJarEntry(moduleInfoFileName);
240+
if (moduleEntry != null) {
241+
try (InputStream inputStream = jarFile.getInputStream(moduleEntry)) {
242+
return extractModuleNameFromModuleInfo(inputStream);
243+
}
244+
}
245+
return null;
246+
}
247+
248+
/**
249+
* Looks into the {@code MANIFEST.MF} file and returns the {@code Automatic-Module-Name} value if there is one.
250+
* @return the module name, or null if the manifest is nonexistent or has no {@code Automatic-Module-Name} value
251+
*/
252+
private static String getAutomaticModuleNameFromManifest(JarFile jarFile) throws IOException {
253+
JarEntry manifestEntry = jarFile.getJarEntry("META-INF/MANIFEST.MF");
254+
if (manifestEntry != null) {
255+
try (InputStream inputStream = jarFile.getInputStream(manifestEntry)) {
256+
Manifest manifest = new Manifest(inputStream);
257+
String amn = manifest.getMainAttributes().getValue("Automatic-Module-Name");
258+
if (amn != null) {
259+
return amn;
260+
}
261+
}
262+
}
263+
return null;
264+
}
265+
266+
/**
267+
* Compose a module name from the given {@code jarFile} name,
268+
* as documented in {@link java.lang.module.ModuleFinder#of}.
269+
*/
270+
private static @NotNull String deriveModuleNameFromJarFileName(File jarFile) {
271+
String jn = jarFile.getName().substring(0, jarFile.getName().length() - JAR_DESCRIPTOR_SUFFIX.length());
272+
Matcher matcher = Pattern.compile("-(\\d+(\\.|$))").matcher(jn);
273+
if (matcher.find()) {
274+
jn = jn.substring(0, matcher.start());
275+
}
276+
jn = jn.replaceAll("[^A-Za-z0-9]", ".");
277+
return jn;
278+
}
279+
256280
/**
257281
* find the first class and module when the class path entry is a directory
258282
*/

0 commit comments

Comments
 (0)