Add support for custom locale to render compiler messages

Closes gh-31408
This commit is contained in:
Stéphane Nicoll 2023-10-11 08:53:51 +02:00
parent ae88bbaac3
commit 93206c3f6e
2 changed files with 57 additions and 30 deletions

View File

@ -53,6 +53,8 @@ public final class TestCompiler {
private final JavaCompiler compiler; private final JavaCompiler compiler;
private final Locale locale;
private final SourceFiles sourceFiles; private final SourceFiles sourceFiles;
private final ResourceFiles resourceFiles; private final ResourceFiles resourceFiles;
@ -64,12 +66,13 @@ public final class TestCompiler {
private final List<String> compilerOptions; private final List<String> compilerOptions;
private TestCompiler(@Nullable ClassLoader classLoader, JavaCompiler compiler, private TestCompiler(@Nullable ClassLoader classLoader, JavaCompiler compiler, Locale locale,
SourceFiles sourceFiles, ResourceFiles resourceFiles, ClassFiles classFiles, SourceFiles sourceFiles, ResourceFiles resourceFiles, ClassFiles classFiles, List<Processor> processors,
List<Processor> processors, List<String> compilerOptions) { List<String> compilerOptions) {
this.classLoader = classLoader; this.classLoader = classLoader;
this.compiler = compiler; this.compiler = compiler;
this.locale = locale;
this.sourceFiles = sourceFiles; this.sourceFiles = sourceFiles;
this.resourceFiles = resourceFiles; this.resourceFiles = resourceFiles;
this.classFiles = classFiles; this.classFiles = classFiles;
@ -92,8 +95,9 @@ public final class TestCompiler {
* @return a new {@code TestCompiler} instance * @return a new {@code TestCompiler} instance
*/ */
public static TestCompiler forCompiler(JavaCompiler javaCompiler) { public static TestCompiler forCompiler(JavaCompiler javaCompiler) {
return new TestCompiler(null, javaCompiler, SourceFiles.none(), return new TestCompiler(null, javaCompiler, Locale.getDefault(),
ResourceFiles.none(), ClassFiles.none(), Collections.emptyList(), Collections.emptyList()); SourceFiles.none(), ResourceFiles.none(),
ClassFiles.none(), Collections.emptyList(), Collections.emptyList());
} }
/** /**
@ -105,13 +109,26 @@ public final class TestCompiler {
return customizer.apply(this); return customizer.apply(this);
} }
/**
* Create a new {@code TestCompiler} instance that uses the specified {@link Locale}
* to render compiler messages.
* @param locale the locale to use
* @return a new {@code TestCompiler} instance
* @since 6.1
*/
public TestCompiler withLocale(Locale locale) {
return new TestCompiler(this.classLoader, this.compiler, locale,
this.sourceFiles, this.resourceFiles,
this.classFiles, this.processors, this.compilerOptions);
}
/** /**
* Create a new {@code TestCompiler} instance with additional source files. * Create a new {@code TestCompiler} instance with additional source files.
* @param sourceFiles the additional source files * @param sourceFiles the additional source files
* @return a new {@code TestCompiler} instance * @return a new {@code TestCompiler} instance
*/ */
public TestCompiler withSources(SourceFile... sourceFiles) { public TestCompiler withSources(SourceFile... sourceFiles) {
return new TestCompiler(this.classLoader, this.compiler, return new TestCompiler(this.classLoader, this.compiler, this.locale,
this.sourceFiles.and(sourceFiles), this.resourceFiles, this.sourceFiles.and(sourceFiles), this.resourceFiles,
this.classFiles, this.processors, this.compilerOptions); this.classFiles, this.processors, this.compilerOptions);
} }
@ -122,7 +139,7 @@ public final class TestCompiler {
* @return a new {@code TestCompiler} instance * @return a new {@code TestCompiler} instance
*/ */
public TestCompiler withSources(Iterable<SourceFile> sourceFiles) { public TestCompiler withSources(Iterable<SourceFile> sourceFiles) {
return new TestCompiler(this.classLoader, this.compiler, return new TestCompiler(this.classLoader, this.compiler, this.locale,
this.sourceFiles.and(sourceFiles), this.resourceFiles, this.sourceFiles.and(sourceFiles), this.resourceFiles,
this.classFiles, this.processors, this.compilerOptions); this.classFiles, this.processors, this.compilerOptions);
} }
@ -133,7 +150,7 @@ public final class TestCompiler {
* @return a new {@code TestCompiler} instance * @return a new {@code TestCompiler} instance
*/ */
public TestCompiler withSources(SourceFiles sourceFiles) { public TestCompiler withSources(SourceFiles sourceFiles) {
return new TestCompiler(this.classLoader, this.compiler, return new TestCompiler(this.classLoader, this.compiler, this.locale,
this.sourceFiles.and(sourceFiles), this.resourceFiles, this.sourceFiles.and(sourceFiles), this.resourceFiles,
this.classFiles, this.processors, this.compilerOptions); this.classFiles, this.processors, this.compilerOptions);
} }
@ -144,9 +161,9 @@ public final class TestCompiler {
* @return a new {@code TestCompiler} instance * @return a new {@code TestCompiler} instance
*/ */
public TestCompiler withResources(ResourceFile... resourceFiles) { public TestCompiler withResources(ResourceFile... resourceFiles) {
return new TestCompiler(this.classLoader, this.compiler, this.sourceFiles, return new TestCompiler(this.classLoader, this.compiler, this.locale,
this.resourceFiles.and(resourceFiles), this.classFiles, this.processors, this.sourceFiles, this.resourceFiles.and(resourceFiles),
this.compilerOptions); this.classFiles, this.processors, this.compilerOptions);
} }
/** /**
@ -155,9 +172,9 @@ public final class TestCompiler {
* @return a new {@code TestCompiler} instance * @return a new {@code TestCompiler} instance
*/ */
public TestCompiler withResources(Iterable<ResourceFile> resourceFiles) { public TestCompiler withResources(Iterable<ResourceFile> resourceFiles) {
return new TestCompiler(this.classLoader, this.compiler, this.sourceFiles, return new TestCompiler(this.classLoader, this.compiler, this.locale,
this.resourceFiles.and(resourceFiles), this.classFiles, this.processors, this.sourceFiles, this.resourceFiles.and(resourceFiles),
this.compilerOptions); this.classFiles, this.processors, this.compilerOptions);
} }
/** /**
@ -166,9 +183,9 @@ public final class TestCompiler {
* @return a new {@code TestCompiler} instance * @return a new {@code TestCompiler} instance
*/ */
public TestCompiler withResources(ResourceFiles resourceFiles) { public TestCompiler withResources(ResourceFiles resourceFiles) {
return new TestCompiler(this.classLoader, this.compiler, this.sourceFiles, return new TestCompiler(this.classLoader, this.compiler, this.locale,
this.resourceFiles.and(resourceFiles), this.classFiles, this.processors, this.sourceFiles, this.resourceFiles.and(resourceFiles),
this.compilerOptions); this.classFiles, this.processors, this.compilerOptions);
} }
/** /**
@ -177,9 +194,9 @@ public final class TestCompiler {
* @return a new {@code TestCompiler} instance * @return a new {@code TestCompiler} instance
*/ */
public TestCompiler withClasses(Iterable<ClassFile> classFiles) { public TestCompiler withClasses(Iterable<ClassFile> classFiles) {
return new TestCompiler(this.classLoader, this.compiler, this.sourceFiles, return new TestCompiler(this.classLoader, this.compiler, this.locale,
this.resourceFiles, this.classFiles.and(classFiles), this.processors, this.sourceFiles, this.resourceFiles, this.classFiles.and(classFiles),
this.compilerOptions); this.processors, this.compilerOptions);
} }
/** /**
@ -190,8 +207,9 @@ public final class TestCompiler {
public TestCompiler withProcessors(Processor... processors) { public TestCompiler withProcessors(Processor... processors) {
List<Processor> mergedProcessors = new ArrayList<>(this.processors); List<Processor> mergedProcessors = new ArrayList<>(this.processors);
mergedProcessors.addAll(Arrays.asList(processors)); mergedProcessors.addAll(Arrays.asList(processors));
return new TestCompiler(this.classLoader, this.compiler, this.sourceFiles, return new TestCompiler(this.classLoader, this.compiler, this.locale,
this.resourceFiles, this.classFiles, mergedProcessors, this.compilerOptions); this.sourceFiles, this.resourceFiles, this.classFiles, mergedProcessors,
this.compilerOptions);
} }
/** /**
@ -202,8 +220,9 @@ public final class TestCompiler {
public TestCompiler withProcessors(Iterable<Processor> processors) { public TestCompiler withProcessors(Iterable<Processor> processors) {
List<Processor> mergedProcessors = new ArrayList<>(this.processors); List<Processor> mergedProcessors = new ArrayList<>(this.processors);
processors.forEach(mergedProcessors::add); processors.forEach(mergedProcessors::add);
return new TestCompiler(this.classLoader, this.compiler, this.sourceFiles, return new TestCompiler(this.classLoader, this.compiler, this.locale,
this.resourceFiles, this.classFiles, mergedProcessors, this.compilerOptions); this.sourceFiles, this.resourceFiles, this.classFiles,
mergedProcessors, this.compilerOptions);
} }
/** /**
@ -215,8 +234,9 @@ public final class TestCompiler {
public TestCompiler withCompilerOptions(String... options) { public TestCompiler withCompilerOptions(String... options) {
List<String> mergedCompilerOptions = Stream.concat(this.compilerOptions.stream(), List<String> mergedCompilerOptions = Stream.concat(this.compilerOptions.stream(),
Arrays.stream(options)).distinct().toList(); Arrays.stream(options)).distinct().toList();
return new TestCompiler(this.classLoader, this.compiler, this.sourceFiles, return new TestCompiler(this.classLoader, this.compiler, this.locale,
this.resourceFiles, this.classFiles, this.processors, mergedCompilerOptions); this.sourceFiles, this.resourceFiles, this.classFiles,
this.processors, mergedCompilerOptions);
} }
/** /**
@ -308,7 +328,7 @@ public final class TestCompiler {
DynamicJavaFileManager fileManager = new DynamicJavaFileManager( DynamicJavaFileManager fileManager = new DynamicJavaFileManager(
standardFileManager, classLoaderToUse, this.classFiles, this.resourceFiles); standardFileManager, classLoaderToUse, this.classFiles, this.resourceFiles);
if (!this.sourceFiles.isEmpty()) { if (!this.sourceFiles.isEmpty()) {
Errors errors = new Errors(); Errors errors = new Errors(this.locale);
CompilationTask task = this.compiler.getTask(null, fileManager, errors, CompilationTask task = this.compiler.getTask(null, fileManager, errors,
this.compilerOptions, null, compilationUnits); this.compilerOptions, null, compilationUnits);
if (!this.processors.isEmpty()) { if (!this.processors.isEmpty()) {
@ -349,13 +369,19 @@ public final class TestCompiler {
*/ */
static class Errors implements DiagnosticListener<JavaFileObject> { static class Errors implements DiagnosticListener<JavaFileObject> {
private final Locale locale;
private final StringBuilder message = new StringBuilder(); private final StringBuilder message = new StringBuilder();
Errors(Locale locale) {
this.locale = locale;
}
@Override @Override
public void report(Diagnostic<? extends JavaFileObject> diagnostic) { public void report(Diagnostic<? extends JavaFileObject> diagnostic) {
if (diagnostic.getKind() == Diagnostic.Kind.ERROR) { if (diagnostic.getKind() == Diagnostic.Kind.ERROR) {
this.message.append('\n'); this.message.append('\n');
this.message.append(diagnostic.getMessage(Locale.getDefault())); this.message.append(diagnostic.getMessage(this.locale));
if (diagnostic.getSource() != null) { if (diagnostic.getSource() != null) {
this.message.append(' '); this.message.append(' ');
this.message.append(diagnostic.getSource().getName()); this.message.append(diagnostic.getSource().getName());

View File

@ -19,6 +19,7 @@ package org.springframework.core.test.tools;
import java.io.InputStream; import java.io.InputStream;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Locale;
import java.util.Set; import java.util.Set;
import java.util.function.Supplier; import java.util.function.Supplier;
@ -170,8 +171,8 @@ class TestCompilerTests {
} }
"""); """);
assertThatExceptionOfType(CompilationException.class).isThrownBy( assertThatExceptionOfType(CompilationException.class).isThrownBy(
() -> TestCompiler.forSystem().failOnWarning().withSources( () -> TestCompiler.forSystem().failOnWarning().withLocale(Locale.ENGLISH)
SourceFile.of(HELLO_DEPRECATED), main).compile(compiled -> { .withSources(SourceFile.of(HELLO_DEPRECATED), main).compile(compiled -> {
})).withMessageContaining("warnings found and -Werror specified"); })).withMessageContaining("warnings found and -Werror specified");
} }