Allow TestCompiler DynamicClassLoader to resolve '.class' resources

Update `DynamicClassLoader` so that `findResource(...)` also considered
compiled class bytecode.

Closes gh-29347
This commit is contained in:
Phillip Webb
2022-10-18 11:14:57 -07:00
parent d17cdf98bb
commit 327eec09ae
2 changed files with 30 additions and 10 deletions

View File

@@ -31,6 +31,7 @@ import java.util.function.Supplier;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;
import org.springframework.util.ReflectionUtils;
/**
@@ -91,15 +92,7 @@ public class DynamicClassLoader extends ClassLoader {
return super.findClass(name);
}
@Nullable
private byte[] findClassBytes(String name) {
ClassFile classFile = this.classFiles.get(name);
if (classFile != null) {
return classFile.getContent();
}
DynamicClassFileObject dynamicClassFile = this.dynamicClassFiles.get(name);
return (dynamicClassFile != null) ? dynamicClassFile.getBytes() : null;
}
private Class<?> defineClass(String name, byte[] bytes) {
if (this.defineClassMethod != null) {
@@ -109,7 +102,6 @@ public class DynamicClassLoader extends ClassLoader {
return defineClass(name, bytes, 0, bytes.length);
}
@Override
protected Enumeration<URL> findResources(String name) throws IOException {
URL resource = findResource(name);
@@ -122,6 +114,14 @@ public class DynamicClassLoader extends ClassLoader {
@Override
@Nullable
protected URL findResource(String name) {
if (name.endsWith(ClassUtils.CLASS_FILE_SUFFIX)) {
String className = ClassUtils.convertResourcePathToClassName(name.substring(0,
name.length() - ClassUtils.CLASS_FILE_SUFFIX.length()));
byte[] classBytes = findClassBytes(className);
if (classBytes != null) {
return createResourceUrl(name, () -> classBytes);
}
}
ResourceFile resourceFile = this.resourceFiles.get(name);
if (resourceFile != null) {
return createResourceUrl(resourceFile.getPath(), resourceFile::getBytes);
@@ -133,6 +133,16 @@ public class DynamicClassLoader extends ClassLoader {
return super.findResource(name);
}
@Nullable
private byte[] findClassBytes(String name) {
ClassFile classFile = this.classFiles.get(name);
if (classFile != null) {
return classFile.getContent();
}
DynamicClassFileObject dynamicClassFile = this.dynamicClassFiles.get(name);
return (dynamicClassFile != null) ? dynamicClassFile.getBytes() : null;
}
private URL createResourceUrl(String name, Supplier<byte[]> bytesSupplier) {
try {
return new URL(null, "resource:///" + name,

View File

@@ -16,6 +16,7 @@
package org.springframework.core.test.tools;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
@@ -278,6 +279,15 @@ class TestCompilerTests {
compiled.getInstance(PublicInterface.class, "com.example.Test").perform()).isEqualTo("Hello from subpackage"));
}
@Test
void getResourceForCompiledBytecode() {
SourceFile sourceFile = SourceFile.of(HELLO_WORLD);
TestCompiler.forSystem().compile(sourceFile, compiled -> {
InputStream stream = compiled.getClassLoader().getResourceAsStream("com/example/Hello.class");
assertThat(stream).isNotNull();
});
}
private void assertSuppliesHelloWorld(Compiled compiled) {
assertThat(compiled.getInstance(Supplier.class).get()).isEqualTo("Hello World!");
}