Merge branch '4.1.x' into 4.2.x

This commit is contained in:
Marcin Grzejszczak
2025-02-17 16:23:36 +01:00
4 changed files with 126 additions and 22 deletions

View File

@@ -66,7 +66,6 @@
<xerces.version>2.12.2</xerces.version>
<jacoco-maven-plugin.version>0.8.8</jacoco-maven-plugin.version>
<exec-maven-plugin.version>1.6.0</exec-maven-plugin.version>
<InMemoryJavaCompiler.version>1.3.0</InMemoryJavaCompiler.version>
<contract.kotlin.version>1.8.22</contract.kotlin.version>
<commons-beanutils.version>1.9.4</commons-beanutils.version>

View File

@@ -247,12 +247,6 @@
<artifactId>spring-boot-starter-jersey</artifactId>
<scope>test</scope>
</dependency>-->
<dependency>
<groupId>org.mdkt.compiler</groupId>
<artifactId>InMemoryJavaCompiler</artifactId>
<version>${InMemoryJavaCompiler.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<artifactId>jetty-ee10-servlet</artifactId>
<groupId>org.eclipse.jetty.ee10</groupId>

View File

@@ -17,7 +17,6 @@
package org.springframework.cloud.contract.verifier.builder
import org.junit.Rule
import org.mdkt.compiler.CompilationException
import spock.lang.Issue
import spock.lang.Shared
import spock.lang.Specification
@@ -238,7 +237,7 @@ class MockMvcMethodBodyBuilderWithMatchersSpec extends Specification implements
try {
SyntaxChecker.tryToCompileWithoutCompileStatic(methodBuilderName, test)
}
catch (CompilationException classFormatError) {
catch (Exception classFormatError) {
String output = classFormatError.message
assert output.contains('cannot find symbol')
assert output.contains('assertThatValueIsANumber')

View File

@@ -19,6 +19,16 @@ package org.springframework.cloud.contract.verifier.util
import java.lang.reflect.Method
import javax.inject.Inject
import javax.tools.Diagnostic
import javax.tools.DiagnosticCollector
import javax.tools.FileObject
import javax.tools.ForwardingJavaFileManager
import javax.tools.JavaCompiler
import javax.tools.JavaFileManager
import javax.tools.JavaFileObject
import javax.tools.SimpleJavaFileObject
import javax.tools.StandardJavaFileManager
import javax.tools.ToolProvider
import javax.ws.rs.client.Entity
import javax.ws.rs.client.WebTarget
import javax.ws.rs.core.Response
@@ -35,7 +45,6 @@ import org.codehaus.groovy.control.customizers.ASTTransformationCustomizer
import org.codehaus.groovy.control.customizers.ImportCustomizer
import org.junit.Rule
import org.junit.Test
import org.mdkt.compiler.InMemoryJavaCompiler
import org.w3c.dom.Document
import org.xml.sax.InputSource
@@ -46,6 +55,7 @@ import org.springframework.cloud.contract.verifier.messaging.internal.ContractVe
import org.springframework.cloud.contract.verifier.messaging.internal.ContractVerifierObjectMapper
import org.springframework.cloud.contract.verifier.messaging.util.ContractVerifierMessagingUtil
import org.springframework.util.ReflectionUtils
/**
* checking the syntax of produced scripts
*/
@@ -110,8 +120,7 @@ private void test(String test) {
try {
if (builderName.toLowerCase().contains("spock")) {
tryToCompileGroovy(builderName, test)
}
else {
} else {
tryToCompileJava(builderName, test)
}
} catch (Throwable t) {
@@ -125,8 +134,7 @@ private void test(String test) {
if (builderName.toLowerCase().contains("spock")) {
Script script = tryToCompileGroovy(builderName, test)
script.invokeMethod("validate_method()", null)
}
else {
} else {
Class clazz = tryToCompileJava(builderName, test)
Method method = ReflectionUtils.findMethod(clazz, "validate_method")
method.invoke(clazz.newInstance())
@@ -141,8 +149,7 @@ private void test(String test) {
static void tryToCompileWithoutCompileStatic(String builderName, String test) {
if (builderName.toLowerCase().contains("spock")) {
tryToCompileGroovy(builderName, test, false)
}
else {
} else {
tryToCompileJava(builderName, test)
}
}
@@ -162,7 +169,7 @@ private void test(String test) {
private static String updatedTest(String test, String className) {
test.replaceAll("class FooTest", "class " + className)
.replaceAll("import javax.ws.rs.core.Response", "import javax.ws.rs.core.Response; import javax.ws.rs.client.WebTarget;")
.replaceAll("import javax.ws.rs.core.Response", "import javax.ws.rs.core.Response; import javax.ws.rs.client.WebTarget;")
}
private static GString getStaticImports(String builderName) {
@@ -176,15 +183,43 @@ private void test(String test) {
String className = className(test)
String fqnClassName = "com.example.${className}"
test = test.replaceAll("class FooTest", "class " + className)
.replaceAll("import javax.ws.rs.core.Response", "import javax.ws.rs.core.Response; import javax.ws.rs.client.WebTarget;")
.replaceAll("import javax.ws.rs.core.Response", "import javax.ws.rs.core.Response; import javax.ws.rs.client.WebTarget;")
return compileJava(fqnClassName, test)
}
private static Class<?> compileJava(String fqnClassName, String test) {
return InMemoryJavaCompiler.newInstance()
.ignoreWarnings()
.compile(fqnClassName, test)
@CompileStatic
private static Class<?> compileJava(String fqnClassName, String sourceCode) {
JavaCompiler compiler = ToolProvider.getSystemJavaCompiler()
DiagnosticCollector<JavaFileObject> diagnostics = new DiagnosticCollector<>()
InMemoryClassLoader classLoader = new InMemoryClassLoader()
StandardJavaFileManager standardFileManager = compiler.getStandardFileManager(diagnostics, null, null)
JavaFileManager fileManager = new InMemoryFileManager(standardFileManager, classLoader)
JavaFileObject javaFile = new InMemorySourceFile(fqnClassName, sourceCode)
JavaCompiler.CompilationTask task = compiler.getTask(
new StringWriter(),
fileManager,
diagnostics,
null,
null,
Collections.singletonList(javaFile)
)
boolean success = task.call()
if (!success) {
StringBuilder errorMsg = new StringBuilder("Compilation failed:")
for (Diagnostic<? extends JavaFileObject> diagnostic : diagnostics.getDiagnostics()) {
errorMsg.append("\nLine ").append(diagnostic.getLineNumber())
.append(": ").append(diagnostic.getMessage(null))
}
throw new IllegalStateException(errorMsg.toString())
}
try {
return classLoader.loadClass(fqnClassName)
} catch (ClassNotFoundException e) {
throw new IllegalStateException("Failed to load compiled class", e)
}
}
private static String className(String test) {
@@ -210,4 +245,81 @@ private void test(String test) {
return true
}
@CompileStatic
private static class InMemorySourceFile extends SimpleJavaFileObject {
private final String sourceCode
InMemorySourceFile(String className, String sourceCode) {
super(URI.create("string:///" + className.replace('.', '/') + Kind.SOURCE.extension),
Kind.SOURCE)
this.sourceCode = sourceCode
}
@Override
CharSequence getCharContent(boolean ignoreEncodingErrors) {
return sourceCode
}
}
@CompileStatic
private static class InMemoryClassLoader extends ClassLoader {
private final Map<String, byte[]> classData = new HashMap<>()
void addClass(String name, byte[] data) {
classData.put(name, data)
}
@Override
protected Class<?> findClass(String name) throws ClassNotFoundException {
byte[] data = classData.get(name)
if (data == null) {
throw new ClassNotFoundException(name)
}
return defineClass(name, data, 0, data.length)
}
}
@CompileStatic
private static class InMemoryFileManager extends ForwardingJavaFileManager<StandardJavaFileManager> {
private final InMemoryClassLoader classLoader
InMemoryFileManager(StandardJavaFileManager fileManager, InMemoryClassLoader classLoader) {
super(fileManager)
this.classLoader = classLoader
}
@Override
JavaFileObject getJavaFileForOutput(Location location,
String className,
JavaFileObject.Kind kind,
FileObject sibling) {
return new InMemoryClassFile(className, classLoader)
}
}
@CompileStatic
private static class InMemoryClassFile extends SimpleJavaFileObject {
private final String className
private final InMemoryClassLoader classLoader
private final ByteArrayOutputStream outputStream = new ByteArrayOutputStream()
InMemoryClassFile(String className, InMemoryClassLoader classLoader) {
super(URI.create("byte:///" + className.replace('.', '/') + Kind.CLASS.extension),
Kind.CLASS)
this.className = className
this.classLoader = classLoader
}
@Override
OutputStream openOutputStream() {
outputStream.reset()
return new FilterOutputStream(outputStream) {
@Override
void close() throws IOException {
super.close()
classLoader.addClass(className, outputStream.toByteArray())
}
}
}
}
}