Skip to content

Commit f393625

Browse files
committed
Pass project dependencies to isolated delombok process
1 parent 22d4ca9 commit f393625

1 file changed

Lines changed: 86 additions & 29 deletions

File tree

src/main/java/com/neuvem/java2graph/passes/DelombokPass.java

Lines changed: 86 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -5,40 +5,46 @@
55

66
import java.io.BufferedReader;
77
import java.io.BufferedWriter;
8+
import java.io.File;
89
import java.io.InputStreamReader;
910
import java.nio.file.Files;
1011
import java.nio.file.Path;
11-
import java.util.ArrayList;
12-
import java.util.List;
13-
import java.util.stream.Collectors;
12+
import java.util.*;
13+
import java.util.regex.Matcher;
14+
import java.util.regex.Pattern;
1415
import java.util.stream.Stream;
1516

1617
public class DelombokPass implements Pass {
1718

19+
private static final Pattern PACKAGE_PATTERN = Pattern.compile("^\\s*package\\s+([\\w.]+)\\s*;");
20+
1821
@Override
1922
public void execute(Java2GraphConfig config, GraphContext context) throws Exception {
2023
if (!config.isEnableLombok()) {
2124
return;
2225
}
2326

24-
System.out.println("Processing Lombok annotations via isolated process (filtering builds/hidden)...");
27+
System.out.println("Processing Lombok annotations via isolated process (with classpath resolution)...");
2528

2629
Path delombokDir = Files.createTempDirectory("delombok");
2730
String javaHome = System.getProperty("java.home");
2831
String javaBin = javaHome + "/bin/java";
29-
String classpath = System.getProperty("java.class.path");
32+
String mainClasspath = System.getProperty("java.class.path");
33+
34+
// Resolve the project's dependencies for delombok attribution
35+
String projectClasspath = resolveProjectClasspath(config.getJarPaths());
3036

31-
// Identify source directories while excluding build/hidden folders
32-
List<String> srcPaths = findSourceDirs(config.getSrcDir());
33-
if (srcPaths.isEmpty()) {
37+
// Identify unique source roots (package roots) to preserve structure while avoiding build artifacts
38+
Set<String> srcRoots = findSourceRoots(config.getSrcDir());
39+
if (srcRoots.isEmpty()) {
3440
System.out.println("No Java source files found in " + config.getSrcDir());
3541
return;
3642
}
3743

38-
// Use a response file for delombok to avoid command-line length limits and manage inputs
44+
// Use a response file for delombok to avoid command-line length limits
3945
Path argFile = Files.createTempFile("delombok_args", ".args");
4046
try (BufferedWriter writer = Files.newBufferedWriter(argFile)) {
41-
for (String path : srcPaths) {
47+
for (String path : srcRoots) {
4248
writer.write("\"" + path.replace("\\", "\\\\") + "\"");
4349
writer.newLine();
4450
}
@@ -62,11 +68,17 @@ public void execute(Java2GraphConfig config, GraphContext context) throws Except
6268
command.add("--add-opens=jdk.compiler/com.sun.tools.javac.api=ALL-UNNAMED");
6369

6470
command.add("-cp");
65-
command.add(classpath);
71+
command.add(mainClasspath);
6672
command.add("lombok.launch.Main");
6773
command.add("delombok");
6874
command.add("--nocopy");
6975
command.add("--quiet");
76+
77+
if (!projectClasspath.isEmpty()) {
78+
command.add("--classpath");
79+
command.add(projectClasspath);
80+
}
81+
7082
command.add("@" + argFile.toAbsolutePath());
7183
command.add("-d");
7284
command.add(delombokDir.toAbsolutePath().toString());
@@ -79,14 +91,13 @@ public void execute(Java2GraphConfig config, GraphContext context) throws Except
7991
try (BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()))) {
8092
String line;
8193
while ((line = reader.readLine()) != null) {
82-
// Suppress verbose hidden directory messages from Lombok
8394
if (line.contains("hidden directory")) continue;
8495
output.append(line).append("\n");
8596
}
8697
}
8798

8899
int exitCode = process.waitFor();
89-
Files.deleteIfExists(argFile); // Clean up the temp args file
100+
Files.deleteIfExists(argFile);
90101

91102
if (exitCode != 0) {
92103
System.err.println("Delombok failed with exit code " + exitCode);
@@ -96,20 +107,74 @@ public void execute(Java2GraphConfig config, GraphContext context) throws Except
96107
throw new RuntimeException("Delombok process failed. See logs for details.");
97108
}
98109

99-
// Update the src directory for subsequent passes
110+
// IMPORTANT: Update the src directory for subsequent passes
100111
config.setSrcDir(delombokDir);
101112

102113
System.out.println("Lombok processing complete. Delomboked to: " + delombokDir);
103114
}
104115

105-
private List<String> findSourceDirs(Path root) throws Exception {
106-
try (Stream<Path> walk = Files.walk(root)) {
107-
return walk.filter(Files::isDirectory)
108-
.filter(path -> !isExcluded(path))
109-
.filter(this::hasJavaFiles)
110-
.map(path -> path.toAbsolutePath().toString())
111-
.collect(Collectors.toList());
116+
private String resolveProjectClasspath(List<Path> jarPaths) {
117+
if (jarPaths == null || jarPaths.isEmpty()) {
118+
return "";
119+
}
120+
List<String> classpathElements = new ArrayList<>();
121+
for (Path path : jarPaths) {
122+
if (Files.isRegularFile(path) && path.toString().endsWith(".jar")) {
123+
classpathElements.add(path.toAbsolutePath().toString());
124+
} else if (Files.isDirectory(path)) {
125+
try (Stream<Path> walk = Files.walk(path)) {
126+
walk.filter(p -> Files.isRegularFile(p) && p.toString().endsWith(".jar"))
127+
.map(p -> p.toAbsolutePath().toString())
128+
.forEach(classpathElements::add);
129+
} catch (Exception e) {
130+
// Ignore and continue
131+
}
132+
}
133+
}
134+
return String.join(File.pathSeparator, classpathElements);
135+
}
136+
137+
private Set<String> findSourceRoots(Path start) throws Exception {
138+
Set<String> roots = new LinkedHashSet<>();
139+
try (Stream<Path> walk = Files.walk(start)) {
140+
walk.filter(path -> path.toString().endsWith(".java"))
141+
.filter(file -> !isExcluded(file))
142+
.forEach(file -> {
143+
// Check if already covered
144+
if (roots.stream().anyMatch(root -> file.startsWith(Path.of(root)))) {
145+
return;
146+
}
147+
String root = discoverRoot(file);
148+
if (root != null) {
149+
roots.add(root);
150+
}
151+
});
112152
}
153+
return roots;
154+
}
155+
156+
private String discoverRoot(Path file) {
157+
try (BufferedReader reader = Files.newBufferedReader(file)) {
158+
String line;
159+
int count = 0;
160+
while ((line = reader.readLine()) != null && count < 100) {
161+
Matcher m = PACKAGE_PATTERN.matcher(line);
162+
if (m.find()) {
163+
String pkg = m.group(1);
164+
int depth = pkg.split("\\.").length;
165+
Path root = file.getParent();
166+
for (int i = 0; i < depth; i++) {
167+
if (root.getParent() != null) root = root.getParent();
168+
}
169+
return root.toAbsolutePath().toString();
170+
}
171+
count++;
172+
}
173+
} catch (Exception e) {
174+
// Log quietly and ignore
175+
}
176+
// If no package, root is parent
177+
return file.getParent().toAbsolutePath().toString();
113178
}
114179

115180
private boolean isExcluded(Path path) {
@@ -126,12 +191,4 @@ private boolean isExcluded(Path path) {
126191
}
127192
return false;
128193
}
129-
130-
private boolean hasJavaFiles(Path dir) {
131-
try (Stream<Path> files = Files.list(dir)) {
132-
return files.anyMatch(p -> p.getFileName().toString().endsWith(".java"));
133-
} catch (Exception e) {
134-
return false;
135-
}
136-
}
137194
}

0 commit comments

Comments
 (0)