Skip to content

Commit 665fc97

Browse files
committed
feat(jdk-codemodel): add classpath and module-path support to JdkInitializer
1 parent 0d69f5c commit 665fc97

2 files changed

Lines changed: 87 additions & 3 deletions

File tree

jdk-codemodel/src/main/java/build/codemodel/jdk/JdkInitializer.java

Lines changed: 45 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,8 @@ public class JdkInitializer
124124
private final List<File> sourceFiles;
125125
private final List<Path> sourceDirectories;
126126
private final List<JavaFileObject> javaFileObjects;
127+
private final List<Path> classpath;
128+
private final List<Path> modulePath;
127129

128130
private boolean initialized = false;
129131

@@ -137,16 +139,37 @@ public class JdkInitializer
137139
/**
138140
* Creates a {@link JdkInitializer} with explicit source inputs.
139141
*
140-
* @param sourceFiles individual {@link File} source files to parse
142+
* @param sourceFiles individual {@link File} source files to parse
141143
* @param sourceDirectories directories to walk recursively for {@code .java} files
142-
* @param javaFileObjects in-memory or pre-built {@link JavaFileObject} sources
144+
* @param javaFileObjects in-memory or pre-built {@link JavaFileObject} sources
143145
*/
144146
public JdkInitializer(final List<File> sourceFiles,
145147
final List<Path> sourceDirectories,
146148
final List<JavaFileObject> javaFileObjects) {
149+
this(sourceFiles, sourceDirectories, javaFileObjects, List.of(), List.of());
150+
}
151+
152+
/**
153+
* Creates a {@link JdkInitializer} with explicit source inputs and dependency paths.
154+
* Callers are responsible for assembling the classpath and module-path lists; this class
155+
* does no jar classification or module dependency resolution.
156+
*
157+
* @param sourceFiles individual {@link File} source files to parse
158+
* @param sourceDirectories directories to walk recursively for {@code .java} files
159+
* @param javaFileObjects in-memory or pre-built {@link JavaFileObject} sources
160+
* @param classpath jars or directories to pass as {@code --class-path}
161+
* @param modulePath jars or directories to pass as {@code --module-path}
162+
*/
163+
public JdkInitializer(final List<File> sourceFiles,
164+
final List<Path> sourceDirectories,
165+
final List<JavaFileObject> javaFileObjects,
166+
final List<Path> classpath,
167+
final List<Path> modulePath) {
147168
this.sourceFiles = sourceFiles;
148169
this.sourceDirectories = sourceDirectories;
149170
this.javaFileObjects = javaFileObjects;
171+
this.classpath = classpath;
172+
this.modulePath = modulePath;
150173
}
151174

152175
/**
@@ -193,7 +216,7 @@ public void initialize(final CodeModel codeModel) {
193216
return;
194217
}
195218

196-
final var task = compiler.getTask(null, fileManager, diagnostic -> {}, null, null, combined);
219+
final var task = compiler.getTask(null, fileManager, diagnostic -> {}, buildOptions(), null, combined);
197220
final var javacTask = (JavacTask) task;
198221
final var compilationUnits = javacTask.parse();
199222
javacTask.analyze();
@@ -226,6 +249,25 @@ public Void visitClass(final ClassTree classTree, final Void unused) {
226249
}
227250
}
228251

252+
// --- Compiler options ---
253+
254+
private List<String> buildOptions() {
255+
final var options = new ArrayList<String>();
256+
if (!classpath.isEmpty()) {
257+
options.add("--class-path");
258+
options.add(classpath.stream()
259+
.map(Path::toString)
260+
.collect(Collectors.joining(File.pathSeparator)));
261+
}
262+
if (!modulePath.isEmpty()) {
263+
options.add("--module-path");
264+
options.add(modulePath.stream()
265+
.map(Path::toString)
266+
.collect(Collectors.joining(File.pathSeparator)));
267+
}
268+
return options.isEmpty() ? null : options;
269+
}
270+
229271
// --- Source collection ---
230272

231273
private List<JavaFileObject> collectSources(final StandardJavaFileManager fileManager) throws IOException {

jdk-codemodel/src/test/java/build/codemodel/jdk/JdkInitializerTests.java

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,11 @@
1515
import java.io.ByteArrayOutputStream;
1616
import java.io.File;
1717
import java.io.PrintStream;
18+
import java.nio.file.Files;
19+
import java.nio.file.Path;
1820
import java.util.List;
1921
import java.util.Optional;
22+
import javax.tools.ToolProvider;
2023

2124
import static org.assertj.core.api.Assertions.assertThat;
2225
import static org.assertj.core.api.Assertions.assertThatThrownBy;
@@ -181,6 +184,45 @@ public class Foo {
181184
assertThat(field.type()).isInstanceOf(UnknownTypeUsage.class);
182185
}
183186

187+
@Test
188+
void shouldResolveTypesFromClasspath() throws Exception {
189+
// Compile a helper class to a temp directory, then pass that directory as the classpath.
190+
// Without classpath support the field type would be UnknownTypeUsage.
191+
final Path classpathDir = Files.createTempDirectory("jdk-initializer-test-cp");
192+
193+
final var helperSource = JavaFileObjects.forSourceString(
194+
"com.example.Helper",
195+
"package com.example; public class Helper {}");
196+
final var compiler = ToolProvider.getSystemJavaCompiler();
197+
try (final var fm = compiler.getStandardFileManager(null, null, null)) {
198+
compiler.getTask(null, fm, diagnostic -> {},
199+
List.of("-d", classpathDir.toString()), null, List.of(helperSource)).call();
200+
}
201+
202+
final var consumer = JavaFileObjects.forSourceString(
203+
"com.example.Consumer",
204+
"""
205+
package com.example;
206+
public class Consumer {
207+
private com.example.Helper helper;
208+
}
209+
""");
210+
211+
final var codeModel = runInternal(
212+
new JdkInitializer(List.of(), List.of(), List.of(consumer), List.of(classpathDir), List.of()));
213+
214+
final var typeName = codeModel.getNameProvider().getTypeName(Optional.empty(), "com.example.Consumer");
215+
final var descriptor = codeModel.getTypeDescriptor(typeName).orElseThrow();
216+
final var field = descriptor.traits(FieldDescriptor.class)
217+
.filter(f -> f.fieldName().toString().equals("helper"))
218+
.findFirst()
219+
.orElseThrow();
220+
221+
assertThat(field.type())
222+
.as("type from classpath entry should resolve, not degrade to UnknownTypeUsage")
223+
.isNotInstanceOf(UnknownTypeUsage.class);
224+
}
225+
184226
@Test
185227
void shouldCaptureAnnotationsOnParameters() {
186228
final var source = JavaFileObjects.forSourceString(

0 commit comments

Comments
 (0)