Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,4 @@
/plexus-java/target
*.iml
.idea/
/META-INF
10 changes: 10 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,3 +12,13 @@ Plexus Java:

* [![Maven Central](https://img.shields.io/maven-central/v/org.codehaus.plexus/plexus-java.svg?label=Maven%20Central)](https://search.maven.org/artifact/org.codehaus.plexus/plexus-java)

## Module Parsing Implementations

Plexus Java uses a multi-release JAR to provide optimal module-info parsing for different Java versions:

- **Java 8**: ASM-based parser for module-info.class files
- **Java 9-23**: Native `java.lang.module.ModuleDescriptor` API
- **Java 24+**: Java Class File API (JEP 484)

The appropriate implementation is automatically selected based on the runtime JVM version.

31 changes: 31 additions & 0 deletions plexus-java/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,37 @@
</pluginManagement>
</build>
</profile>
<profile>
<id>jdk24</id>
<activation>
<jdk>[24,)</jdk>
</activation>
<build>
<pluginManagement>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<executions>
<execution>
<id>jdk24</id>
<goals>
<goal>compile</goal>
</goals>
<configuration>
<release>24</release>
<multiReleaseOutput>true</multiReleaseOutput>
<compileSourceRoots>
<compileSourceRoot>${project.basedir}/src/main/java24</compileSourceRoot>
</compileSourceRoots>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</pluginManagement>
</build>
</profile>
</profiles>

</project>
35 changes: 35 additions & 0 deletions plexus-java/src/main/java24/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
# Java 24+ Class File API Implementation

This directory contains an implementation of the module-info parser using the Java Class File API, which was finalized in Java 24 (JEP 484).

## Background

The Class File API provides a native Java API for parsing and generating class files, eliminating the need for external libraries like ASM for this purpose.

### Timeline

- **Java 22** (March 2024): Preview feature (JEP 457)
- **Java 23** (September 2024): Second Preview (JEP 466)
- **Java 24** (March 2025): Finalized (JEP 484)

## Implementation

This implementation uses:
- `java.lang.classfile.ClassFile` for parsing class files
- `java.lang.classfile.attribute.ModuleAttribute` for accessing module information
- The same `JavaModuleDescriptor` builder pattern as other implementations

## Building

When building with Java 24+, this code is automatically compiled and included in the multi-release JAR.

When building with Java 23 or earlier, this code is not compiled, and the Java 9 implementation (using `java.lang.module.ModuleDescriptor`) is used instead.

## Multi-Release JAR

This implementation is part of a multi-release JAR structure:
- Java 8: Uses ASM-based parser
- Java 9-23: Uses `java.lang.module.ModuleDescriptor`
- Java 24+: Uses Class File API (this implementation)

The appropriate version is automatically selected at runtime based on the JVM version.
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package org.codehaus.plexus.languages.java.jpms;

/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
class BinaryModuleInfoParser extends ClassFileApiModuleInfoParser {}
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
package org.codehaus.plexus.languages.java.jpms;

/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/

import java.io.IOException;
import java.io.InputStream;
import java.lang.classfile.ClassFile;
import java.lang.classfile.ClassModel;
import java.lang.classfile.attribute.ModuleAttribute;
import java.lang.classfile.attribute.ModuleExportInfo;
import java.lang.classfile.attribute.ModuleProvidesInfo;
import java.lang.classfile.attribute.ModuleRequiresInfo;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;

import org.codehaus.plexus.languages.java.jpms.JavaModuleDescriptor.JavaRequires.JavaModifier;

/**
* Extract information from module using the Class File API
*
* @author Robert Scholte
* @since 1.5.0
*/
class ClassFileApiModuleInfoParser extends AbstractBinaryModuleInfoParser {
@Override
JavaModuleDescriptor parse(InputStream in) throws IOException {
byte[] bytes = in.readAllBytes();
ClassModel classModel = ClassFile.of().parse(bytes);

ModuleAttribute moduleAttr = classModel
.findAttribute(java.lang.classfile.Attributes.module())
.orElseThrow(() -> new IOException("Not a module-info class file"));

JavaModuleDescriptor.Builder builder =
JavaModuleDescriptor.newModule(moduleAttr.moduleName().name().stringValue());

// Process requires
for (ModuleRequiresInfo requiresInfo : moduleAttr.requires()) {
String moduleName = requiresInfo.requires().name().stringValue();
int flags = requiresInfo.requiresFlagsMask();

boolean isStatic = (flags & ClassFile.ACC_STATIC_PHASE) != 0;
boolean isTransitive = (flags & ClassFile.ACC_TRANSITIVE) != 0;

if (isStatic || isTransitive) {
Set<JavaModifier> modifiers = new LinkedHashSet<>();
if (isStatic) {
modifiers.add(JavaModifier.STATIC);
}
if (isTransitive) {
modifiers.add(JavaModifier.TRANSITIVE);
}
builder.requires(modifiers, moduleName);
} else {
builder.requires(moduleName);
}
}

// Process exports
for (ModuleExportInfo exportInfo : moduleAttr.exports()) {
String packageName =
exportInfo.exportedPackage().name().stringValue().replace('/', '.');
if (exportInfo.exportsTo().isEmpty()) {
builder.exports(packageName);
} else {
Set<String> targets = new HashSet<>();
exportInfo
.exportsTo()
.forEach(target -> targets.add(target.name().stringValue()));
builder.exports(packageName, targets);
}
}

// Process uses
moduleAttr.uses().forEach(usesInfo -> {
String serviceName = usesInfo.name().stringValue().replace('/', '.');
builder.uses(serviceName);
});

// Process provides
for (ModuleProvidesInfo providesInfo : moduleAttr.provides()) {
String serviceName = providesInfo.provides().name().stringValue().replace('/', '.');
List<String> providers = new ArrayList<>();
providesInfo
.providesWith()
.forEach(provider ->
providers.add(provider.name().stringValue().replace('/', '.')));
builder.provides(serviceName, providers);
}

return builder.build();
}
}
1 change: 1 addition & 0 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@
<includes>
<include>src/main/java/**/*.java</include>
<include>src/main/java9/**/*.java</include>
<include>src/main/java24/**/*.java</include>
<include>src/test/java/**/*.java</include>
</includes>
</java>
Expand Down
Loading