diff --git a/build.gradle.kts b/build.gradle.kts
index ed7b22a0..16d8a2ac 100644
--- a/build.gradle.kts
+++ b/build.gradle.kts
@@ -11,6 +11,7 @@ configurations.compileClasspath {
dependencies {
implementation("org.ow2.asm:asm:9.9")
+ implementation("com.github.javaparser:javaparser-core:3.28.0")
compileOnly("org.gradlex:extra-java-module-info:1.13.1")
compileOnly("com.autonomousapps:dependency-analysis-gradle-plugin:3.5.1")
}
diff --git a/gradle/verification-keyring.keys b/gradle/verification-keyring.keys
index cba99fe6..5bd5d14b 100644
--- a/gradle/verification-keyring.keys
+++ b/gradle/verification-keyring.keys
@@ -1754,3 +1754,16 @@ CgkQuhmUn6JgkhZmBQEA3b5QhIg4LhToSGJ0sI3mPr270z+Sefyl/L8s2i7ZJKEA
/1su4aPLl+FaeuZHpInOy991PXFh+IJICL1irc2DfV4G
=stfL
-----END PGP PUBLIC KEY BLOCK-----
+
+id 6DE9B8077FBB2F8A019F4904BD17A565509DEE20
+uid jean-pierre.lerbscher@jperf.com
+-----BEGIN PGP PUBLIC KEY BLOCK-----
+
+xjMEZl2j9RYJKwYBBAHaRw8BAQdAPzZyNkr92xKYzBrTOsN8Fwy9l2W0ez4Hu0t3
+/MoohtG0H2plYW4tcGllcnJlLmxlcmJzY2hlckBqcGVyZi5jb23OOARmXaP1Egor
+BgEEAZdVAQUBAQdAoTUzjZPhQLyzRo9jIO8TrgC+mfazNL5gB+fOWhB//T4DAQgH
+wn4EGBYKACYWIQRt6bgHf7svigGfSQS9F6VlUJ3uIAUCZl2j9QIbDAUJBaOKqwAK
+CRC9F6VlUJ3uIIpxAP9MihNcqlK2wPp2uURiLmw16dN3o50gxWeLMjBxethg0gD/
+VLRHao8huHsPY9XMrgbHSNLZOT7geBJOdvwrTRTy3A0=
+=BzAO
+-----END PGP PUBLIC KEY BLOCK-----
diff --git a/gradle/verification-metadata.xml b/gradle/verification-metadata.xml
index aee68149..e816a246 100644
--- a/gradle/verification-metadata.xml
+++ b/gradle/verification-metadata.xml
@@ -17,9 +17,11 @@
-
+
+
+
diff --git a/src/main/java/org/gradlex/javamodule/dependencies/internal/utils/ModuleInfo.java b/src/main/java/org/gradlex/javamodule/dependencies/internal/utils/ModuleInfo.java
index c3fe5232..0a640f5a 100644
--- a/src/main/java/org/gradlex/javamodule/dependencies/internal/utils/ModuleInfo.java
+++ b/src/main/java/org/gradlex/javamodule/dependencies/internal/utils/ModuleInfo.java
@@ -3,12 +3,25 @@
import static org.gradlex.javamodule.dependencies.internal.utils.ModuleNamingUtil.sourceSetToModuleName;
+import com.github.javaparser.JavaParser;
+import com.github.javaparser.ast.CompilationUnit;
+import com.github.javaparser.ast.Node;
+import com.github.javaparser.ast.expr.Name;
+import com.github.javaparser.ast.modules.ModuleDeclaration;
+import com.github.javaparser.ast.modules.ModuleDirective;
+import com.github.javaparser.ast.modules.ModuleProvidesDirective;
+import com.github.javaparser.ast.modules.ModuleRequiresDirective;
+import com.github.javaparser.ast.nodeTypes.NodeWithIdentifier;
+import com.github.javaparser.ast.nodeTypes.NodeWithName;
import java.io.Serializable;
import java.util.ArrayList;
-import java.util.Arrays;
import java.util.Collections;
+import java.util.LinkedHashMap;
import java.util.List;
+import java.util.Map;
import java.util.Objects;
+import java.util.Optional;
+import java.util.stream.Collectors;
import org.jspecify.annotations.Nullable;
public class ModuleInfo implements Serializable {
@@ -29,18 +42,34 @@ public String literal() {
public static final ModuleInfo EMPTY = new ModuleInfo("");
- private String moduleName = "";
+ private final String moduleName;
+ private final Map imports;
private final List requires = new ArrayList<>();
private final List requiresTransitive = new ArrayList<>();
private final List requiresStatic = new ArrayList<>();
private final List requiresStaticTransitive = new ArrayList<>();
private final List requiresRuntime = new ArrayList<>();
+ private final Map> provides = new LinkedHashMap<>();
public ModuleInfo(String moduleInfoFileContent) {
- boolean insideComment = false;
- for (String line : moduleInfoFileContent.split("\n")) {
- insideComment = parse(line, insideComment);
- }
+ Optional result =
+ new JavaParser().parse(moduleInfoFileContent).getResult();
+ if (!result.isPresent() || !result.get().getModule().isPresent()) {
+ moduleName = "";
+ imports = Collections.emptyMap();
+ return;
+ }
+
+ ModuleDeclaration moduleDeclaration = result.get().getModule().get();
+ moduleName = moduleDeclaration.getNameAsString();
+ imports = processImports(result.get());
+ processDirectives(moduleDeclaration.getDirectives());
+ }
+
+ private Map processImports(CompilationUnit cu) {
+ return cu.getImports().stream()
+ .map(NodeWithName::getName)
+ .collect(Collectors.toMap(NodeWithIdentifier::getId, Node::toString));
}
public String getModuleName() {
@@ -66,6 +95,10 @@ public List get(Directive directive) {
return Collections.emptyList();
}
+ public Map> getProvides() {
+ return provides;
+ }
+
@Nullable
public String moduleNamePrefix(String projectName, String sourceSetName, boolean fail) {
if (moduleName.equals(projectName)) {
@@ -90,44 +123,47 @@ public String moduleNamePrefix(String projectName, String sourceSetName, boolean
return null;
}
- /**
- * @return true, if we are inside a multi-line comment after this line
- */
- private boolean parse(String moduleLine, boolean insideComment) {
- if (insideComment) {
- return !moduleLine.contains("*/");
+ private void processDirectives(List directives) {
+ for (ModuleDirective d : directives) {
+ if (d instanceof ModuleRequiresDirective) {
+ ModuleRequiresDirective directive = (ModuleRequiresDirective) d;
+ String identifier = directive.getNameAsString();
+ if (directive.isStatic() && directive.isTransitive()) {
+ requiresStaticTransitive.add(identifier);
+ } else if (directive.isTransitive()) {
+ requiresTransitive.add(identifier);
+ } else if (directive.isStatic()) {
+ requiresStatic.add(identifier);
+ } else if (isRuntime(directive)) {
+ requiresRuntime.add(identifier);
+ } else {
+ requires.add(identifier);
+ }
+ }
+ if (d instanceof ModuleProvidesDirective) {
+ ModuleProvidesDirective directive = (ModuleProvidesDirective) d;
+ String name = qualifiedName(directive.getName());
+ List with = provides.computeIfAbsent(name, k -> new ArrayList<>());
+ with.addAll(
+ directive.getWith().stream().map(this::qualifiedName).collect(Collectors.toList()));
+ }
}
+ }
- List tokens = Arrays.asList(moduleLine
- .replace(";", "")
- .replace("{", "")
- .replace("}", "")
- .replace(RUNTIME_KEYWORD, "runtime")
- .replaceAll("/\\*.*?\\*/", " ")
- .trim()
- .split("\\s+"));
- int singleLineCommentStartIndex = tokens.indexOf("//");
- if (singleLineCommentStartIndex >= 0) {
- tokens = tokens.subList(0, singleLineCommentStartIndex);
- }
+ private static boolean isRuntime(ModuleRequiresDirective directive) {
+ return directive
+ .getName()
+ .getComment()
+ .map(c -> "runtime".equals(c.getContent().trim()))
+ .orElse(false);
+ }
- if (tokens.contains("module")) {
- moduleName = tokens.get(tokens.size() - 1);
- }
- if (tokens.size() > 1 && tokens.get(0).equals("requires")) {
- if (tokens.size() > 3 && tokens.contains("static") && tokens.contains("transitive")) {
- requiresStaticTransitive.add(tokens.get(3));
- } else if (tokens.size() > 2 && tokens.contains("transitive")) {
- requiresTransitive.add(tokens.get(2));
- } else if (tokens.size() > 2 && tokens.contains("static")) {
- requiresStatic.add(tokens.get(2));
- } else if (tokens.size() > 2 && tokens.contains("runtime")) {
- requiresRuntime.add(tokens.get(2));
- } else {
- requires.add(tokens.get(1));
- }
+ private String qualifiedName(Name name) {
+ if (imports.containsKey(name.getId())) {
+ return imports.get(name.getId());
+ } else {
+ return name.toString();
}
- return moduleLine.lastIndexOf("/*") > moduleLine.lastIndexOf("*/");
}
@Override
diff --git a/src/main/java/org/gradlex/javamodule/dependencies/internal/utils/ModuleInfoCache.java b/src/main/java/org/gradlex/javamodule/dependencies/internal/utils/ModuleInfoCache.java
index bb17c1ed..3073a020 100644
--- a/src/main/java/org/gradlex/javamodule/dependencies/internal/utils/ModuleInfoCache.java
+++ b/src/main/java/org/gradlex/javamodule/dependencies/internal/utils/ModuleInfoCache.java
@@ -101,11 +101,12 @@ public Collection getAllLocalModules() {
}
private boolean maybePutModuleInfo(File folder, ProviderFactory providers) {
+ if (moduleInfo.containsKey(folder)) {
+ return true;
+ }
Provider moduleInfoProvider = provideModuleInfo(folder, providers);
if (moduleInfoProvider.isPresent()) {
- if (!moduleInfo.containsKey(folder)) {
- moduleInfo.put(folder, moduleInfoProvider.get());
- }
+ moduleInfo.put(folder, moduleInfoProvider.get());
return true;
}
return false;