Skip to content

Commit 3284e21

Browse files
committed
Refactored class resolution logic
- Introduced `ResolvedClass` for encapsulating class and method resolution. - Enhanced `ResolverContext` to manage class loading and reuse resolved classes. - Streamlined test execution and parsing logic in `MetaIRTestExecutor` and associated tests.
1 parent 426b77e commit 3284e21

4 files changed

Lines changed: 89 additions & 33 deletions

File tree

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
package de.mirkosertic.metair.ir;
2+
3+
import java.lang.classfile.ClassFile;
4+
import java.lang.classfile.ClassModel;
5+
6+
public class ResolvedClass {
7+
8+
private final ResolverContext resolverContext;
9+
private ClassFile classFile;
10+
private ClassModel classModel;
11+
private boolean loaded;
12+
13+
public ResolvedClass(final ResolverContext resolverContext) {
14+
this.loaded = false;
15+
this.resolverContext = resolverContext;
16+
}
17+
18+
public boolean isLoaded() {
19+
return loaded;
20+
}
21+
22+
public void loaded(final ClassFile classFile, final ClassModel classModel) {
23+
this.classFile = classFile;
24+
this.classModel = classModel;
25+
this.loaded = true;
26+
}
27+
28+
public ClassModel classModel() {
29+
return classModel;
30+
}
31+
}

src/main/java/de/mirkosertic/metair/ir/ResolverContext.java

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,51 @@
11
package de.mirkosertic.metair.ir;
22

3+
import java.io.File;
4+
import java.io.IOException;
5+
import java.io.InputStream;
6+
import java.lang.classfile.ClassFile;
7+
import java.lang.classfile.ClassModel;
38
import java.lang.constant.ClassDesc;
49
import java.lang.constant.MethodTypeDesc;
10+
import java.net.URL;
11+
import java.util.HashMap;
12+
import java.util.Map;
513

614
public class ResolverContext {
715

16+
private final ClassLoader classLoader;
17+
private final Map<String, ResolvedClass> resolvedClasses;
18+
19+
public ResolverContext(final ClassLoader aClassLoader) {
20+
this.classLoader = aClassLoader;
21+
this.resolvedClasses = new HashMap<>();
22+
}
23+
24+
public ResolverContext() {
25+
this(ResolverContext.class.getClassLoader());
26+
}
27+
28+
public ResolvedClass resolveClass(final String className) throws IOException {
29+
final ResolvedClass resolved = resolvedClasses.computeIfAbsent(className, k -> new ResolvedClass(this));
30+
31+
if (!resolved.isLoaded()) {
32+
final URL resource = classLoader.getResource(className.replace('.', File.separatorChar) + ".class");
33+
if (resource == null) {
34+
throw new IllegalStateException("Cannot find class file for " + className);
35+
}
36+
37+
try (final InputStream inputStream = resource.openStream()) {
38+
final byte[] data = inputStream.readAllBytes();
39+
40+
final ClassFile cf = ClassFile.of();
41+
final ClassModel model = cf.parse(data);
42+
43+
resolved.loaded(cf, model);
44+
}
45+
}
46+
return resolved;
47+
}
48+
849
public IRType.MetaClass resolveType(final ClassDesc desc) {
950
return IRType.MetaClass.of(desc);
1051
}

src/main/java/de/mirkosertic/metair/ir/test/MetaIRTestExecutor.java

Lines changed: 9 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,14 @@
11
package de.mirkosertic.metair.ir.test;
22

3+
import de.mirkosertic.metair.ir.ResolvedClass;
4+
import de.mirkosertic.metair.ir.ResolverContext;
35
import org.junit.platform.engine.ExecutionRequest;
46
import org.junit.platform.engine.TestDescriptor;
57
import org.junit.platform.engine.TestExecutionResult;
68
import org.junit.platform.engine.support.descriptor.EngineDescriptor;
79

8-
import java.io.File;
9-
import java.io.IOException;
10-
import java.io.InputStream;
11-
import java.lang.classfile.ClassFile;
1210
import java.lang.classfile.ClassModel;
1311
import java.lang.classfile.MethodModel;
14-
import java.net.URL;
1512
import java.nio.file.Path;
1613

1714
public class MetaIRTestExecutor {
@@ -42,28 +39,19 @@ private void executeMethod(final ExecutionRequest request, final MethodTestDescr
4239
try {
4340
final Class<?> origin = descriptor.getTestClass();
4441

45-
final URL resource = origin.getClassLoader().getResource(origin.getName().replace('.', File.separatorChar) + ".class");
46-
if (resource == null) {
47-
throw new IllegalStateException("Cannot find class file for " + origin.getName());
48-
}
49-
50-
try (final InputStream inputStream = resource.openStream()) {
51-
final byte[] data = inputStream.readAllBytes();
42+
final ResolverContext ctx = new ResolverContext();
43+
final ResolvedClass resolvedClass = ctx.resolveClass(origin.getName());
5244

53-
final ClassFile cf = ClassFile.of();
54-
final ClassModel model = cf.parse(data);
45+
final ClassModel model = resolvedClass.classModel();
5546

56-
for (final MethodModel method : model.methods()) {
47+
for (final MethodModel method : model.methods()) {
5748

58-
if (method.methodName().stringValue().equals(descriptor.getMethodName())) {
49+
if (method.methodName().stringValue().equals(descriptor.getMethodName())) {
5950

60-
final Path targetDir = request.getOutputDirectoryProvider().createOutputDirectory(descriptor);
51+
final Path targetDir = request.getOutputDirectoryProvider().createOutputDirectory(descriptor);
6152

62-
new MetaIRTestHelper(targetDir).analyzeAndReport(model, method);
63-
}
53+
new MetaIRTestHelper(targetDir).analyzeAndReport(model, method);
6454
}
65-
} catch (final IOException e) {
66-
throw new RuntimeException("Failed to load class data for " + origin.getName(), e);
6755
}
6856

6957
request.getEngineExecutionListener().executionFinished(descriptor, TestExecutionResult.successful());

src/test/java/de/mirkosertic/metair/ir/SelfParsingProjectTest.java

Lines changed: 8 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -62,26 +62,22 @@ public void testSingleMethod1() {
6262

6363
@TestFactory
6464
public List<DynamicContainer> testAllProjectClasses() {
65+
66+
final ResolverContext resolverContext = new ResolverContext();
67+
6568
return ReflectionSupport.findAllClassesInPackage("de.mirkosertic", _ -> true, s -> true).stream().map(aClass -> {
6669

6770
final List<DynamicTest> tests = new ArrayList<>();
6871

69-
final URL resource = aClass.getClassLoader().getResource(aClass.getName().replace('.', File.separatorChar) + ".class");
70-
if (resource == null) {
71-
throw new IllegalStateException("Cannot find class file for " + aClass.getName());
72-
}
73-
74-
try (final InputStream inputStream = resource.openStream()) {
75-
final byte[] data = inputStream.readAllBytes();
72+
try {
73+
final ResolvedClass resolvedClass = resolverContext.resolveClass(aClass.getName());
7674

77-
final ClassFile cf = ClassFile.of();
78-
final ClassModel model = cf.parse(data);
75+
final ClassModel model = resolvedClass.classModel();
7976

8077
for (final MethodModel method : model.methods()) {
8178

8279
tests.add(DynamicTest.dynamicTest(method.methodName().stringValue() + " " + method.methodType().stringValue(), () -> {
8380
try {
84-
final ResolverContext resolverContext = new ResolverContext();
8581
final MethodAnalyzer analyzer = new MethodAnalyzer(resolverContext, IRType.MetaClass.of(model.thisClass().asSymbol()), method);
8682
} catch (final IllegalParsingStateException e) {
8783
final MethodAnalyzer analyzer = e.getAnalyzer();
@@ -100,12 +96,12 @@ public List<DynamicContainer> testAllProjectClasses() {
10096
}
10197
}));
10298
}
103-
} catch (final IOException e) {
99+
100+
} catch (final Exception e) {
104101
throw new RuntimeException("Failed to load class data for " + aClass.getName(), e);
105102
}
106103

107104
return DynamicContainer.dynamicContainer(aClass.getName(), tests);
108-
109105
}).toList();
110106
}
111107
}

0 commit comments

Comments
 (0)