Polish "Add module to support testing of generated code"
See gh-28120 Co-authored-by: Andy Wilkinson <wilkinsona@vmware.com>
This commit is contained in:
parent
653dc5951d
commit
7255a8b48e
|
@ -1,5 +1,3 @@
|
||||||
import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar
|
|
||||||
|
|
||||||
description = "Spring Core Test"
|
description = "Spring Core Test"
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
|
|
|
@ -25,6 +25,7 @@ import org.springframework.aot.test.generator.file.ResourceFile;
|
||||||
import org.springframework.aot.test.generator.file.ResourceFiles;
|
import org.springframework.aot.test.generator.file.ResourceFiles;
|
||||||
import org.springframework.aot.test.generator.file.SourceFile;
|
import org.springframework.aot.test.generator.file.SourceFile;
|
||||||
import org.springframework.aot.test.generator.file.SourceFiles;
|
import org.springframework.aot.test.generator.file.SourceFiles;
|
||||||
|
import org.springframework.lang.Nullable;
|
||||||
import org.springframework.util.Assert;
|
import org.springframework.util.Assert;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -42,6 +43,7 @@ public class Compiled {
|
||||||
|
|
||||||
private final ResourceFiles resourceFiles;
|
private final ResourceFiles resourceFiles;
|
||||||
|
|
||||||
|
@Nullable
|
||||||
private List<Class<?>> compiledClasses;
|
private List<Class<?>> compiledClasses;
|
||||||
|
|
||||||
|
|
||||||
|
@ -107,8 +109,7 @@ public class Compiled {
|
||||||
* @throws IllegalStateException if no instance can be found or instantiated
|
* @throws IllegalStateException if no instance can be found or instantiated
|
||||||
*/
|
*/
|
||||||
public <T> T getInstance(Class<T> type) {
|
public <T> T getInstance(Class<T> type) {
|
||||||
List<Class<?>> matching = getAllCompiledClasses().stream().filter(
|
List<Class<?>> matching = getAllCompiledClasses().stream().filter(type::isAssignableFrom).toList();
|
||||||
candidate -> type.isAssignableFrom(candidate)).toList();
|
|
||||||
Assert.state(!matching.isEmpty(), () -> "No instance found of type " + type.getName());
|
Assert.state(!matching.isEmpty(), () -> "No instance found of type " + type.getName());
|
||||||
Assert.state(matching.size() == 1, () -> "Multiple instances found of type " + type.getName());
|
Assert.state(matching.size() == 1, () -> "Multiple instances found of type " + type.getName());
|
||||||
return newInstance(matching.get(0));
|
return newInstance(matching.get(0));
|
||||||
|
|
|
@ -17,7 +17,6 @@
|
||||||
package org.springframework.aot.test.generator.compile;
|
package org.springframework.aot.test.generator.compile;
|
||||||
|
|
||||||
import java.io.ByteArrayOutputStream;
|
import java.io.ByteArrayOutputStream;
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.OutputStream;
|
import java.io.OutputStream;
|
||||||
import java.net.URI;
|
import java.net.URI;
|
||||||
|
|
||||||
|
@ -32,7 +31,7 @@ import javax.tools.SimpleJavaFileObject;
|
||||||
*/
|
*/
|
||||||
class DynamicClassFileObject extends SimpleJavaFileObject {
|
class DynamicClassFileObject extends SimpleJavaFileObject {
|
||||||
|
|
||||||
private volatile byte[] bytes;
|
private volatile byte[] bytes = new byte[0];
|
||||||
|
|
||||||
|
|
||||||
DynamicClassFileObject(String className) {
|
DynamicClassFileObject(String className) {
|
||||||
|
@ -42,7 +41,7 @@ class DynamicClassFileObject extends SimpleJavaFileObject {
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public OutputStream openOutputStream() throws IOException {
|
public OutputStream openOutputStream() {
|
||||||
return new JavaClassOutputStream();
|
return new JavaClassOutputStream();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -54,7 +53,7 @@ class DynamicClassFileObject extends SimpleJavaFileObject {
|
||||||
class JavaClassOutputStream extends ByteArrayOutputStream {
|
class JavaClassOutputStream extends ByteArrayOutputStream {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void close() throws IOException {
|
public void close() {
|
||||||
DynamicClassFileObject.this.bytes = toByteArray();
|
DynamicClassFileObject.this.bytes = toByteArray();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -23,6 +23,7 @@ import java.lang.System.Logger;
|
||||||
import java.lang.System.Logger.Level;
|
import java.lang.System.Logger.Level;
|
||||||
import java.lang.invoke.MethodHandles;
|
import java.lang.invoke.MethodHandles;
|
||||||
import java.lang.invoke.MethodHandles.Lookup;
|
import java.lang.invoke.MethodHandles.Lookup;
|
||||||
|
import java.lang.reflect.Modifier;
|
||||||
import java.net.MalformedURLException;
|
import java.net.MalformedURLException;
|
||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
import java.net.URLConnection;
|
import java.net.URLConnection;
|
||||||
|
@ -35,17 +36,18 @@ import org.springframework.aot.test.generator.file.ResourceFile;
|
||||||
import org.springframework.aot.test.generator.file.ResourceFiles;
|
import org.springframework.aot.test.generator.file.ResourceFiles;
|
||||||
import org.springframework.aot.test.generator.file.SourceFile;
|
import org.springframework.aot.test.generator.file.SourceFile;
|
||||||
import org.springframework.aot.test.generator.file.SourceFiles;
|
import org.springframework.aot.test.generator.file.SourceFiles;
|
||||||
|
import org.springframework.lang.Nullable;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* {@link ClassLoader} used to expose dynamically generated content.
|
* {@link ClassLoader} used to expose dynamically generated content.
|
||||||
*
|
*
|
||||||
* @author Phillip Webb
|
* @author Phillip Webb
|
||||||
|
* @author Andy Wilkinson
|
||||||
* @since 6.0
|
* @since 6.0
|
||||||
*/
|
*/
|
||||||
public class DynamicClassLoader extends ClassLoader {
|
public class DynamicClassLoader extends ClassLoader {
|
||||||
|
|
||||||
private static final Logger logger = System.getLogger(
|
private static final Logger logger = System.getLogger(DynamicClassLoader.class.getName());
|
||||||
DynamicClassLoader.class.getName());
|
|
||||||
|
|
||||||
|
|
||||||
private final SourceFiles sourceFiles;
|
private final SourceFiles sourceFiles;
|
||||||
|
@ -54,10 +56,13 @@ public class DynamicClassLoader extends ClassLoader {
|
||||||
|
|
||||||
private final Map<String, DynamicClassFileObject> classFiles;
|
private final Map<String, DynamicClassFileObject> classFiles;
|
||||||
|
|
||||||
|
private final ClassLoader sourceLoader;
|
||||||
|
|
||||||
public DynamicClassLoader(ClassLoader parent, SourceFiles sourceFiles,
|
|
||||||
|
public DynamicClassLoader(ClassLoader sourceLoader, SourceFiles sourceFiles,
|
||||||
ResourceFiles resourceFiles, Map<String, DynamicClassFileObject> classFiles) {
|
ResourceFiles resourceFiles, Map<String, DynamicClassFileObject> classFiles) {
|
||||||
super(parent);
|
super(sourceLoader.getParent());
|
||||||
|
this.sourceLoader = sourceLoader;
|
||||||
this.sourceFiles = sourceFiles;
|
this.sourceFiles = sourceFiles;
|
||||||
this.resourceFiles = resourceFiles;
|
this.resourceFiles = resourceFiles;
|
||||||
this.classFiles = classFiles;
|
this.classFiles = classFiles;
|
||||||
|
@ -70,7 +75,22 @@ public class DynamicClassLoader extends ClassLoader {
|
||||||
if (classFile != null) {
|
if (classFile != null) {
|
||||||
return defineClass(name, classFile);
|
return defineClass(name, classFile);
|
||||||
}
|
}
|
||||||
return super.findClass(name);
|
try {
|
||||||
|
Class<?> fromSourceLoader = this.sourceLoader.loadClass(name);
|
||||||
|
if (Modifier.isPublic(fromSourceLoader.getModifiers())) {
|
||||||
|
return fromSourceLoader;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex) {
|
||||||
|
// Continue
|
||||||
|
}
|
||||||
|
try (InputStream classStream = this.sourceLoader.getResourceAsStream(name.replace(".", "/") + ".class")) {
|
||||||
|
byte[] bytes = classStream.readAllBytes();
|
||||||
|
return defineClass(name, bytes, 0, bytes.length, null);
|
||||||
|
}
|
||||||
|
catch (IOException ex) {
|
||||||
|
throw new ClassNotFoundException(name);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private Class<?> defineClass(String name, DynamicClassFileObject classFile) {
|
private Class<?> defineClass(String name, DynamicClassFileObject classFile) {
|
||||||
|
@ -101,6 +121,7 @@ public class DynamicClassLoader extends ClassLoader {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@Nullable
|
||||||
protected URL findResource(String name) {
|
protected URL findResource(String name) {
|
||||||
ResourceFile file = this.resourceFiles.get(name);
|
ResourceFile file = this.resourceFiles.get(name);
|
||||||
if (file != null) {
|
if (file != null) {
|
||||||
|
@ -118,10 +139,11 @@ public class DynamicClassLoader extends ClassLoader {
|
||||||
|
|
||||||
private static class SingletonEnumeration<E> implements Enumeration<E> {
|
private static class SingletonEnumeration<E> implements Enumeration<E> {
|
||||||
|
|
||||||
|
@Nullable
|
||||||
private E element;
|
private E element;
|
||||||
|
|
||||||
|
|
||||||
SingletonEnumeration(E element) {
|
SingletonEnumeration(@Nullable E element) {
|
||||||
this.element = element;
|
this.element = element;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -132,6 +154,7 @@ public class DynamicClassLoader extends ClassLoader {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@Nullable
|
||||||
public E nextElement() {
|
public E nextElement() {
|
||||||
E next = this.element;
|
E next = this.element;
|
||||||
this.element = null;
|
this.element = null;
|
||||||
|
|
|
@ -42,7 +42,6 @@ class DynamicJavaFileManager extends ForwardingJavaFileManager<JavaFileManager>
|
||||||
new LinkedHashMap<>());
|
new LinkedHashMap<>());
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
DynamicJavaFileManager(JavaFileManager fileManager, ClassLoader classLoader) {
|
DynamicJavaFileManager(JavaFileManager fileManager, ClassLoader classLoader) {
|
||||||
super(fileManager);
|
super(fileManager);
|
||||||
this.classLoader = classLoader;
|
this.classLoader = classLoader;
|
||||||
|
|
|
@ -16,7 +16,6 @@
|
||||||
|
|
||||||
package org.springframework.aot.test.generator.compile;
|
package org.springframework.aot.test.generator.compile;
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.net.URI;
|
import java.net.URI;
|
||||||
|
|
||||||
import javax.tools.JavaFileObject;
|
import javax.tools.JavaFileObject;
|
||||||
|
@ -43,7 +42,7 @@ class DynamicJavaFileObject extends SimpleJavaFileObject {
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public CharSequence getCharContent(boolean ignoreEncodingErrors) throws IOException {
|
public CharSequence getCharContent(boolean ignoreEncodingErrors) {
|
||||||
return this.sourceFile.getContent();
|
return this.sourceFile.getContent();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -33,6 +33,7 @@ import org.springframework.aot.test.generator.file.ResourceFiles;
|
||||||
import org.springframework.aot.test.generator.file.SourceFile;
|
import org.springframework.aot.test.generator.file.SourceFile;
|
||||||
import org.springframework.aot.test.generator.file.SourceFiles;
|
import org.springframework.aot.test.generator.file.SourceFiles;
|
||||||
import org.springframework.aot.test.generator.file.WritableContent;
|
import org.springframework.aot.test.generator.file.WritableContent;
|
||||||
|
import org.springframework.lang.Nullable;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Utility that can be used to dynamically compile and test Java source code.
|
* Utility that can be used to dynamically compile and test Java source code.
|
||||||
|
@ -43,6 +44,7 @@ import org.springframework.aot.test.generator.file.WritableContent;
|
||||||
*/
|
*/
|
||||||
public final class TestCompiler {
|
public final class TestCompiler {
|
||||||
|
|
||||||
|
@Nullable
|
||||||
private final ClassLoader classLoader;
|
private final ClassLoader classLoader;
|
||||||
|
|
||||||
private final JavaCompiler compiler;
|
private final JavaCompiler compiler;
|
||||||
|
@ -52,7 +54,7 @@ public final class TestCompiler {
|
||||||
private final ResourceFiles resourceFiles;
|
private final ResourceFiles resourceFiles;
|
||||||
|
|
||||||
|
|
||||||
private TestCompiler(ClassLoader classLoader, JavaCompiler compiler,
|
private TestCompiler(@Nullable ClassLoader classLoader, JavaCompiler compiler,
|
||||||
SourceFiles sourceFiles, ResourceFiles resourceFiles) {
|
SourceFiles sourceFiles, ResourceFiles resourceFiles) {
|
||||||
this.classLoader = classLoader;
|
this.classLoader = classLoader;
|
||||||
this.compiler = compiler;
|
this.compiler = compiler;
|
||||||
|
@ -186,14 +188,14 @@ public final class TestCompiler {
|
||||||
}
|
}
|
||||||
|
|
||||||
private DynamicClassLoader compile() {
|
private DynamicClassLoader compile() {
|
||||||
ClassLoader classLoader = (this.classLoader != null) ? this.classLoader
|
ClassLoader classLoaderToUse = (this.classLoader != null) ? this.classLoader
|
||||||
: Thread.currentThread().getContextClassLoader();
|
: Thread.currentThread().getContextClassLoader();
|
||||||
List<DynamicJavaFileObject> compilationUnits = this.sourceFiles.stream().map(
|
List<DynamicJavaFileObject> compilationUnits = this.sourceFiles.stream().map(
|
||||||
DynamicJavaFileObject::new).toList();
|
DynamicJavaFileObject::new).toList();
|
||||||
StandardJavaFileManager standardFileManager = this.compiler.getStandardFileManager(
|
StandardJavaFileManager standardFileManager = this.compiler.getStandardFileManager(
|
||||||
null, null, null);
|
null, null, null);
|
||||||
DynamicJavaFileManager fileManager = new DynamicJavaFileManager(
|
DynamicJavaFileManager fileManager = new DynamicJavaFileManager(
|
||||||
standardFileManager, classLoader);
|
standardFileManager, classLoaderToUse);
|
||||||
if (!this.sourceFiles.isEmpty()) {
|
if (!this.sourceFiles.isEmpty()) {
|
||||||
Errors errors = new Errors();
|
Errors errors = new Errors();
|
||||||
CompilationTask task = this.compiler.getTask(null, fileManager, errors, null,
|
CompilationTask task = this.compiler.getTask(null, fileManager, errors, null,
|
||||||
|
@ -203,7 +205,7 @@ public final class TestCompiler {
|
||||||
throw new CompilationException("Unable to compile source" + errors);
|
throw new CompilationException("Unable to compile source" + errors);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return new DynamicClassLoader(this.classLoader, this.sourceFiles,
|
return new DynamicClassLoader(classLoaderToUse, this.sourceFiles,
|
||||||
this.resourceFiles, fileManager.getClassFiles());
|
this.resourceFiles, fileManager.getClassFiles());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -223,8 +225,8 @@ public final class TestCompiler {
|
||||||
this.message.append(" ");
|
this.message.append(" ");
|
||||||
this.message.append(diagnostic.getSource().getName());
|
this.message.append(diagnostic.getSource().getName());
|
||||||
this.message.append(" ");
|
this.message.append(" ");
|
||||||
this.message.append(
|
this.message.append(diagnostic.getLineNumber()).append(":")
|
||||||
diagnostic.getLineNumber() + ":" + diagnostic.getColumnNumber());
|
.append(diagnostic.getColumnNumber());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,9 @@
|
||||||
|
/**
|
||||||
|
* Support classes for compiling and testing generated code.
|
||||||
|
*/
|
||||||
|
@NonNullApi
|
||||||
|
@NonNullFields
|
||||||
|
package org.springframework.aot.test.generator.compile;
|
||||||
|
|
||||||
|
import org.springframework.lang.NonNullApi;
|
||||||
|
import org.springframework.lang.NonNullFields;
|
|
@ -19,7 +19,7 @@ package org.springframework.aot.test.generator.file;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
|
|
||||||
import org.assertj.core.util.Strings;
|
import org.springframework.util.Assert;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Abstract base class for dynamically generated files.
|
* Abstract base class for dynamically generated files.
|
||||||
|
@ -29,7 +29,7 @@ import org.assertj.core.util.Strings;
|
||||||
* @see SourceFile
|
* @see SourceFile
|
||||||
* @see ResourceFile
|
* @see ResourceFile
|
||||||
*/
|
*/
|
||||||
public abstract sealed class DynamicFile permits SourceFile,ResourceFile {
|
public abstract sealed class DynamicFile permits SourceFile, ResourceFile {
|
||||||
|
|
||||||
|
|
||||||
private final String path;
|
private final String path;
|
||||||
|
@ -38,21 +38,14 @@ public abstract sealed class DynamicFile permits SourceFile,ResourceFile {
|
||||||
|
|
||||||
|
|
||||||
protected DynamicFile(String path, String content) {
|
protected DynamicFile(String path, String content) {
|
||||||
if (Strings.isNullOrEmpty(content)) {
|
Assert.hasText(path, "Path must not be empty");
|
||||||
throw new IllegalArgumentException("'path' must not to be empty");
|
Assert.hasText(content, "Content must not be empty");
|
||||||
}
|
|
||||||
if (Strings.isNullOrEmpty(content)) {
|
|
||||||
throw new IllegalArgumentException("'content' must not to be empty");
|
|
||||||
}
|
|
||||||
this.path = path;
|
this.path = path;
|
||||||
this.content = content;
|
this.content = content;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
protected static String toString(WritableContent writableContent) {
|
protected static String toString(WritableContent writableContent) {
|
||||||
if (writableContent == null) {
|
|
||||||
throw new IllegalArgumentException("'writableContent' must not to be empty");
|
|
||||||
}
|
|
||||||
try {
|
try {
|
||||||
StringBuilder stringBuilder = new StringBuilder();
|
StringBuilder stringBuilder = new StringBuilder();
|
||||||
writableContent.writeTo(stringBuilder);
|
writableContent.writeTo(stringBuilder);
|
||||||
|
|
|
@ -18,6 +18,8 @@ package org.springframework.aot.test.generator.file;
|
||||||
|
|
||||||
import org.assertj.core.api.AbstractAssert;
|
import org.assertj.core.api.AbstractAssert;
|
||||||
|
|
||||||
|
import org.springframework.lang.Nullable;
|
||||||
|
|
||||||
import static org.assertj.core.api.Assertions.assertThat;
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -42,7 +44,7 @@ public class DynamicFileAssert<A extends DynamicFileAssert<A, F>, F extends Dyna
|
||||||
return this.myself;
|
return this.myself;
|
||||||
}
|
}
|
||||||
|
|
||||||
public A isEqualTo(Object expected) {
|
public A isEqualTo(@Nullable Object expected) {
|
||||||
if (expected instanceof DynamicFile) {
|
if (expected instanceof DynamicFile) {
|
||||||
return super.isEqualTo(expected);
|
return super.isEqualTo(expected);
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,6 +27,8 @@ import com.thoughtworks.qdox.model.JavaType;
|
||||||
import org.assertj.core.error.BasicErrorMessageFactory;
|
import org.assertj.core.error.BasicErrorMessageFactory;
|
||||||
import org.assertj.core.internal.Failures;
|
import org.assertj.core.internal.Failures;
|
||||||
|
|
||||||
|
import org.springframework.lang.Nullable;
|
||||||
|
|
||||||
import static org.assertj.core.api.Assertions.assertThat;
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -43,11 +45,11 @@ public class SourceFileAssert extends DynamicFileAssert<SourceFileAssert, Source
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public SourceFileAssert implementsInterface(Class<?> type) {
|
public SourceFileAssert implementsInterface(@Nullable Class<?> type) {
|
||||||
return implementsInterface((type != null) ? type.getName() : (String) null);
|
return implementsInterface((type != null ? type.getName() : null));
|
||||||
}
|
}
|
||||||
|
|
||||||
public SourceFileAssert implementsInterface(String name) {
|
public SourceFileAssert implementsInterface(@Nullable String name) {
|
||||||
JavaClass javaClass = getJavaClass();
|
JavaClass javaClass = getJavaClass();
|
||||||
assertThat(javaClass.getImplements()).as("implements").map(
|
assertThat(javaClass.getImplements()).as("implements").map(
|
||||||
JavaType::getFullyQualifiedName).contains(name);
|
JavaType::getFullyQualifiedName).contains(name);
|
||||||
|
|
|
@ -0,0 +1,11 @@
|
||||||
|
/**
|
||||||
|
* Support classes for running assertions on generated files.
|
||||||
|
*
|
||||||
|
* @author Stephane Nicoll
|
||||||
|
*/
|
||||||
|
@NonNullApi
|
||||||
|
@NonNullFields
|
||||||
|
package org.springframework.aot.test.generator.file;
|
||||||
|
|
||||||
|
import org.springframework.lang.NonNullApi;
|
||||||
|
import org.springframework.lang.NonNullFields;
|
|
@ -0,0 +1,26 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2002-2022 the original author or authors.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* https://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.example;
|
||||||
|
|
||||||
|
|
||||||
|
class PackagePrivate {
|
||||||
|
|
||||||
|
String perform() {
|
||||||
|
return "Hello from PackagePrivate";
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,23 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2002-2022 the original author or authors.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* https://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.example;
|
||||||
|
|
||||||
|
public interface PublicInterface {
|
||||||
|
|
||||||
|
String perform();
|
||||||
|
|
||||||
|
}
|
|
@ -18,6 +18,7 @@ package org.springframework.aot.test.generator.compile;
|
||||||
|
|
||||||
import java.util.function.Supplier;
|
import java.util.function.Supplier;
|
||||||
|
|
||||||
|
import com.example.PublicInterface;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
import org.springframework.aot.test.generator.file.ResourceFile;
|
import org.springframework.aot.test.generator.file.ResourceFile;
|
||||||
|
@ -33,6 +34,7 @@ import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
|
||||||
* Tests for {@link TestCompiler}.
|
* Tests for {@link TestCompiler}.
|
||||||
*
|
*
|
||||||
* @author Phillip Webb
|
* @author Phillip Webb
|
||||||
|
* @author Andy Wilkinson
|
||||||
*/
|
*/
|
||||||
class TestCompilerTests {
|
class TestCompilerTests {
|
||||||
|
|
||||||
|
@ -106,7 +108,7 @@ class TestCompilerTests {
|
||||||
assertThatExceptionOfType(CompilationException.class).isThrownBy(
|
assertThatExceptionOfType(CompilationException.class).isThrownBy(
|
||||||
() -> TestCompiler.forSystem().withSources(
|
() -> TestCompiler.forSystem().withSources(
|
||||||
SourceFile.of(HELLO_BAD)).compile(compiled -> {
|
SourceFile.of(HELLO_BAD)).compile(compiled -> {
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -167,6 +169,24 @@ class TestCompilerTests {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void compiledCodeCanAccessExistingPackagePrivateClass() {
|
||||||
|
SourceFiles sourceFiles = SourceFiles.of(SourceFile.of("""
|
||||||
|
package com.example;
|
||||||
|
|
||||||
|
public class Test implements PublicInterface {
|
||||||
|
|
||||||
|
public String perform() {
|
||||||
|
return new PackagePrivate().perform();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
"""));
|
||||||
|
TestCompiler.forSystem().compile(sourceFiles, compiled -> assertThat(
|
||||||
|
compiled.getInstance(PublicInterface.class, "com.example.Test").perform())
|
||||||
|
.isEqualTo("Hello from PackagePrivate"));
|
||||||
|
}
|
||||||
|
|
||||||
private void assertSuppliesHelloWorld(Compiled compiled) {
|
private void assertSuppliesHelloWorld(Compiled compiled) {
|
||||||
assertThat(compiled.getInstance(Supplier.class).get()).isEqualTo("Hello World!");
|
assertThat(compiled.getInstance(Supplier.class).get()).isEqualTo("Hello World!");
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,7 +22,6 @@ import com.thoughtworks.qdox.model.JavaSource;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
import static org.assertj.core.api.Assertions.assertThat;
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;
|
|
||||||
import static org.assertj.core.api.Assertions.assertThatIllegalStateException;
|
import static org.assertj.core.api.Assertions.assertThatIllegalStateException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -42,13 +41,6 @@ class SourceFileTests {
|
||||||
}
|
}
|
||||||
""";
|
""";
|
||||||
|
|
||||||
@Test
|
|
||||||
void ofWhenContentIsNullThrowsException() {
|
|
||||||
assertThatIllegalArgumentException().isThrownBy(
|
|
||||||
() -> SourceFile.of((WritableContent) null)).withMessage(
|
|
||||||
"'writableContent' must not to be empty");
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void ofWhenContentIsEmptyThrowsException() {
|
void ofWhenContentIsEmptyThrowsException() {
|
||||||
assertThatIllegalStateException().isThrownBy(() -> SourceFile.of("")).withMessage(
|
assertThatIllegalStateException().isThrownBy(() -> SourceFile.of("")).withMessage(
|
||||||
|
|
Loading…
Reference in New Issue