Browse Source

Add support for specifying compiler options

This commit is a prerequisite to help suppressing deprecating warnings
by allowing tests to validate that the compiler does not encounter them.

See gh-29597
pull/31407/head
Stéphane Nicoll 1 year ago
parent
commit
4b14a0b42c
  1. 60
      spring-core-test/src/main/java/org/springframework/core/test/tools/TestCompiler.java
  2. 81
      spring-core-test/src/test/java/org/springframework/core/test/tools/TestCompilerTests.java

60
spring-core-test/src/main/java/org/springframework/core/test/tools/TestCompiler.java

@ -24,6 +24,7 @@ import java.util.List; @@ -24,6 +24,7 @@ import java.util.List;
import java.util.Locale;
import java.util.function.Consumer;
import java.util.function.UnaryOperator;
import java.util.stream.Stream;
import javax.annotation.processing.Processor;
import javax.tools.Diagnostic;
@ -41,6 +42,7 @@ import org.springframework.lang.Nullable; @@ -41,6 +42,7 @@ import org.springframework.lang.Nullable;
*
* @author Phillip Webb
* @author Scott Frederick
* @author Stephane Nicoll
* @since 6.0
* @see #forSystem()
*/
@ -59,10 +61,12 @@ public final class TestCompiler { @@ -59,10 +61,12 @@ public final class TestCompiler {
private final List<Processor> processors;
private final List<String> compilerOptions;
private TestCompiler(@Nullable ClassLoader classLoader, JavaCompiler compiler,
SourceFiles sourceFiles, ResourceFiles resourceFiles, ClassFiles classFiles,
List<Processor> processors) {
List<Processor> processors, List<String> compilerOptions) {
this.classLoader = classLoader;
this.compiler = compiler;
@ -70,6 +74,7 @@ public final class TestCompiler { @@ -70,6 +74,7 @@ public final class TestCompiler {
this.resourceFiles = resourceFiles;
this.classFiles = classFiles;
this.processors = processors;
this.compilerOptions = compilerOptions;
}
@ -88,7 +93,7 @@ public final class TestCompiler { @@ -88,7 +93,7 @@ public final class TestCompiler {
*/
public static TestCompiler forCompiler(JavaCompiler javaCompiler) {
return new TestCompiler(null, javaCompiler, SourceFiles.none(),
ResourceFiles.none(), ClassFiles.none(), Collections.emptyList());
ResourceFiles.none(), ClassFiles.none(), Collections.emptyList(), Collections.emptyList());
}
/**
@ -108,7 +113,7 @@ public final class TestCompiler { @@ -108,7 +113,7 @@ public final class TestCompiler {
public TestCompiler withSources(SourceFile... sourceFiles) {
return new TestCompiler(this.classLoader, this.compiler,
this.sourceFiles.and(sourceFiles), this.resourceFiles,
this.classFiles, this.processors);
this.classFiles, this.processors, this.compilerOptions);
}
/**
@ -119,7 +124,7 @@ public final class TestCompiler { @@ -119,7 +124,7 @@ public final class TestCompiler {
public TestCompiler withSources(Iterable<SourceFile> sourceFiles) {
return new TestCompiler(this.classLoader, this.compiler,
this.sourceFiles.and(sourceFiles), this.resourceFiles,
this.classFiles, this.processors);
this.classFiles, this.processors, this.compilerOptions);
}
/**
@ -130,7 +135,7 @@ public final class TestCompiler { @@ -130,7 +135,7 @@ public final class TestCompiler {
public TestCompiler withSources(SourceFiles sourceFiles) {
return new TestCompiler(this.classLoader, this.compiler,
this.sourceFiles.and(sourceFiles), this.resourceFiles,
this.classFiles, this.processors);
this.classFiles, this.processors, this.compilerOptions);
}
/**
@ -140,7 +145,8 @@ public final class TestCompiler { @@ -140,7 +145,8 @@ public final class TestCompiler {
*/
public TestCompiler withResources(ResourceFile... resourceFiles) {
return new TestCompiler(this.classLoader, this.compiler, this.sourceFiles,
this.resourceFiles.and(resourceFiles), this.classFiles, this.processors);
this.resourceFiles.and(resourceFiles), this.classFiles, this.processors,
this.compilerOptions);
}
/**
@ -150,7 +156,8 @@ public final class TestCompiler { @@ -150,7 +156,8 @@ public final class TestCompiler {
*/
public TestCompiler withResources(Iterable<ResourceFile> resourceFiles) {
return new TestCompiler(this.classLoader, this.compiler, this.sourceFiles,
this.resourceFiles.and(resourceFiles), this.classFiles, this.processors);
this.resourceFiles.and(resourceFiles), this.classFiles, this.processors,
this.compilerOptions);
}
/**
@ -160,7 +167,8 @@ public final class TestCompiler { @@ -160,7 +167,8 @@ public final class TestCompiler {
*/
public TestCompiler withResources(ResourceFiles resourceFiles) {
return new TestCompiler(this.classLoader, this.compiler, this.sourceFiles,
this.resourceFiles.and(resourceFiles), this.classFiles, this.processors);
this.resourceFiles.and(resourceFiles), this.classFiles, this.processors,
this.compilerOptions);
}
/**
@ -170,7 +178,8 @@ public final class TestCompiler { @@ -170,7 +178,8 @@ public final class TestCompiler {
*/
public TestCompiler withClasses(Iterable<ClassFile> classFiles) {
return new TestCompiler(this.classLoader, this.compiler, this.sourceFiles,
this.resourceFiles, this.classFiles.and(classFiles), this.processors);
this.resourceFiles, this.classFiles.and(classFiles), this.processors,
this.compilerOptions);
}
/**
@ -182,7 +191,7 @@ public final class TestCompiler { @@ -182,7 +191,7 @@ public final class TestCompiler {
List<Processor> mergedProcessors = new ArrayList<>(this.processors);
mergedProcessors.addAll(Arrays.asList(processors));
return new TestCompiler(this.classLoader, this.compiler, this.sourceFiles,
this.resourceFiles, this.classFiles, mergedProcessors);
this.resourceFiles, this.classFiles, mergedProcessors, this.compilerOptions);
}
/**
@ -194,7 +203,32 @@ public final class TestCompiler { @@ -194,7 +203,32 @@ public final class TestCompiler {
List<Processor> mergedProcessors = new ArrayList<>(this.processors);
processors.forEach(mergedProcessors::add);
return new TestCompiler(this.classLoader, this.compiler, this.sourceFiles,
this.resourceFiles, this.classFiles, mergedProcessors);
this.resourceFiles, this.classFiles, mergedProcessors, this.compilerOptions);
}
/**
* Create a new {@link TestCompiler} instance with the additional compiler options.
* @param options the additional compiler options
* @return a new {@code TestCompiler} instance
* @since 6.1
*/
public TestCompiler withCompilerOptions(String... options) {
List<String> mergedCompilerOptions = Stream.concat(this.compilerOptions.stream(),
Arrays.stream(options)).distinct().toList();
return new TestCompiler(this.classLoader, this.compiler, this.sourceFiles,
this.resourceFiles, this.classFiles, this.processors, mergedCompilerOptions);
}
/**
* Create a new {@link TestCompiler} instance that fails if any warning is
* encountered. This sets the {@code -Xlint:all} and {@code -Werror} compiler
* options.
* @return a new {@code TestCompiler} instance
* @since 6.1
* @see #withCompilerOptions(String...)
*/
public TestCompiler failOnWarning() {
return withCompilerOptions("-Xlint:all", "-Werror");
}
/**
@ -275,8 +309,8 @@ public final class TestCompiler { @@ -275,8 +309,8 @@ public final class TestCompiler {
standardFileManager, classLoaderToUse, this.classFiles, this.resourceFiles);
if (!this.sourceFiles.isEmpty()) {
Errors errors = new Errors();
CompilationTask task = this.compiler.getTask(null, fileManager, errors, null,
null, compilationUnits);
CompilationTask task = this.compiler.getTask(null, fileManager, errors,
this.compilerOptions, null, compilationUnits);
if (!this.processors.isEmpty()) {
task.setProcessors(this.processors);
}

81
spring-core-test/src/test/java/org/springframework/core/test/tools/TestCompilerTests.java

@ -1,5 +1,5 @@ @@ -1,5 +1,5 @@
/*
* Copyright 2002-2022 the original author or authors.
* Copyright 2002-2023 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.
@ -43,6 +43,7 @@ import static org.assertj.core.api.Assertions.assertThatExceptionOfType; @@ -43,6 +43,7 @@ import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
* @author Phillip Webb
* @author Andy Wilkinson
* @author Scott Frederick
* @author Stephane Nicoll
*/
class TestCompilerTests {
@ -87,6 +88,20 @@ class TestCompilerTests { @@ -87,6 +88,20 @@ class TestCompilerTests {
}
""";
private static final String HELLO_DEPRECATED = """
package com.example;
import java.util.function.Supplier;
public class Hello implements Supplier<String> {
@Deprecated
public String get() {
return "Hello Deprecated";
}
}
""";
@Test
@SuppressWarnings("unchecked")
@ -119,6 +134,70 @@ class TestCompilerTests { @@ -119,6 +134,70 @@ class TestCompilerTests {
}));
}
@Test
@SuppressWarnings("unchecked")
void compileWhenSourceUseDeprecateCodeAndNoOptionSet() {
SourceFile main = SourceFile.of("""
package com.example;
public class Main {
public static void main(String[] args) {
new Hello().get();
}
}
""");
TestCompiler.forSystem().withSources(
SourceFile.of(HELLO_DEPRECATED), main).compile(compiled -> {
Supplier<String> supplier = compiled.getInstance(Supplier.class,
"com.example.Hello");
assertThat(supplier.get()).isEqualTo("Hello Deprecated");
});
}
@Test
void compileWhenSourceUseDeprecateCodeAndFailOnWarningIsSet() {
SourceFile main = SourceFile.of("""
package com.example;
public class Main {
public static void main(String[] args) {
new Hello().get();
}
}
""");
assertThatExceptionOfType(CompilationException.class).isThrownBy(
() -> TestCompiler.forSystem().failOnWarning().withSources(
SourceFile.of(HELLO_DEPRECATED), main).compile(compiled -> {
})).withMessageContaining("warnings found and -Werror specified");
}
@Test
@SuppressWarnings("unchecked")
void compileWhenSourceUseDeprecateCodeAndFailOnWarningWithSuppressWarnings() {
SourceFile main = SourceFile.of("""
package com.example;
public class Main {
@SuppressWarnings("deprecation")
public static void main(String[] args) {
new Hello().get();
}
}
""");
TestCompiler.forSystem().failOnWarning().withSources(
SourceFile.of(HELLO_DEPRECATED), main).compile(compiled -> {
Supplier<String> supplier = compiled.getInstance(Supplier.class,
"com.example.Hello");
assertThat(supplier.get()).isEqualTo("Hello Deprecated");
});
}
@Test
void withSourcesArrayAddsSource() {
SourceFile sourceFile = SourceFile.of(HELLO_WORLD);

Loading…
Cancel
Save