Java tutorial
/* * @(#)AbstractAnnotationProcessorTest.java 29 May 2009 * * Copyright 2010 Andrew Phillips. * 2014 Dan Hberlein * * ==================================================================== * 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 * * http://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.qrmedia.commons.test.annotation.processing; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; import java.io.File; import java.io.IOException; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.List; import java.util.Locale; import javax.annotation.processing.Processor; import javax.tools.Diagnostic; import javax.tools.DiagnosticCollector; import javax.tools.JavaCompiler; import javax.tools.JavaFileObject; import javax.tools.StandardJavaFileManager; import javax.tools.ToolProvider; import javax.tools.Diagnostic.Kind; import javax.tools.JavaCompiler.CompilationTask; import org.springframework.core.io.ClassPathResource; import org.springframework.util.ClassUtils; /** * A base test class for {@link Processor annotation processor} testing that * attempts to compile source test cases that can be found on the classpath. * <p>dhaeb: I added the method {@link #assertCompilationSuccessfulWithoutWarnings(List)} to check if there were no warning at all in a compilation. * Furthermore, I did some small refactoring.</p> * * @author aphillips * @author dhaeb * * @since 29 May 2014 * */ public abstract class AbstractAnnotationProcessorTest { private static final String SOURCE_FILE_SUFFIX = ".java"; private static final JavaCompiler COMPILER = ToolProvider.getSystemJavaCompiler(); /** * @return the processor instances that should be tested */ protected abstract Collection<Processor> getProcessors(); /** * Attempts to compile the given compilation units using the Java Compiler * API. * <p> * The compilation units and all their dependencies are expected to be on * the classpath. * * @param compilationUnits * the classes to compile * @return the {@link Diagnostic diagnostics} returned by the compilation, * as demonstrated in the documentation for {@link JavaCompiler} * @see #compileTestCase(String...) */ protected List<Diagnostic<? extends JavaFileObject>> compileTestCase(Class<?>... compilationUnits) { assert (compilationUnits != null); String[] compilationUnitPaths = new String[compilationUnits.length]; for (int i = 0; i < compilationUnitPaths.length; i++) { assert (compilationUnits[i] != null); compilationUnitPaths[i] = toResourcePath(compilationUnits[i]); } return compileTestCase(compilationUnitPaths); } private static String toResourcePath(Class<?> clazz) { return ClassUtils.convertClassNameToResourcePath(clazz.getName()) + SOURCE_FILE_SUFFIX; } /** * Attempts to compile the given compilation units using the Java Compiler API. * <p> * The compilation units and all their dependencies are expected to be on the classpath. * * @param compilationUnitPaths * the paths of the source files to compile, as would be expected * by {@link ClassLoader#getResource(String)} * @return the {@link Diagnostic diagnostics} returned by the compilation, * as demonstrated in the documentation for {@link JavaCompiler} * @see #compileTestCase(Class...) * */ protected List<Diagnostic<? extends JavaFileObject>> compileTestCase(String... compilationUnitPaths) { assert (compilationUnitPaths != null); Collection<File> compilationUnits; try { compilationUnits = findClasspathFiles(compilationUnitPaths); } catch (IOException exception) { throw new IllegalArgumentException("Unable to resolve compilation units " + Arrays.toString(compilationUnitPaths) + " due to: " + exception.getMessage(), exception); } DiagnosticCollector<JavaFileObject> diagnosticCollector = new DiagnosticCollector<JavaFileObject>(); StandardJavaFileManager fileManager = COMPILER.getStandardFileManager(diagnosticCollector, null, null); /* * Call the compiler with the "-proc:only" option. The "class names" * option (which could, in principle, be used instead of compilation * units for annotation processing) isn't useful in this case because * only annotations on the classes being compiled are accessible. * * Information about the classes being compiled (such as what they are annotated * with) is *not* available via the RoundEnvironment. However, if these classes * are annotations, they certainly need to be validated. */ CompilationTask task = COMPILER.getTask(null, fileManager, diagnosticCollector, Arrays.asList("-proc:only"), null, fileManager.getJavaFileObjectsFromFiles(compilationUnits)); task.setProcessors(getProcessors()); task.call(); try { fileManager.close(); } catch (IOException exception) { } return diagnosticCollector.getDiagnostics(); } private static Collection<File> findClasspathFiles(String[] filenames) throws IOException { Collection<File> classpathFiles = new ArrayList<File>(filenames.length); for (String filename : filenames) { classpathFiles.add(new ClassPathResource(filename).getFile()); } return classpathFiles; } /** * Asserts that the compilation produced no errors, i.e. no diagnostics of * type {@link Kind#ERROR}. * * @param diagnostics the result of the compilation * @see #assertCompilationReturned(Kind, long, List) * @see #assertCompilationReturned(Kind[], long[], List) */ protected static void assertCompilationSuccessful(List<Diagnostic<? extends JavaFileObject>> diagnostics) { assert (diagnostics != null); assertNotContains(diagnostics, Kind.ERROR, "Expected no Errors"); } /** * Asserts that the compilation produced no errors AND warning, i.e. no diagnostics of * type {@link Kind#ERROR} or {@link Kind#WARNING}. * * @param diagnostics the result of the compilation * @see #assertCompilationReturned(Kind, long, List) * @see #assertCompilationReturned(Kind[], long[], List) */ protected static void assertCompilationSuccessfulWithoutWarnings( List<Diagnostic<? extends JavaFileObject>> diagnostics) { assertCompilationSuccessful(diagnostics); assertNotContains(diagnostics, Kind.WARNING, "Expected no Warnings"); } private static void assertNotContains(List<Diagnostic<? extends JavaFileObject>> diagnostics, Kind kind, String errorMessage) { for (Diagnostic<? extends JavaFileObject> diagnostic : diagnostics) { assertFalse(String.format("%s, found on line %d: %s", errorMessage, diagnostic.getLineNumber(), diagnostic.getMessage(Locale.getDefault())), diagnostic.getKind().equals(kind)); } } /** * Asserts that the compilation produced results of the following * {@link Kind Kinds} at the given line numbers, where the <em>n</em>th kind * is expected at the <em>n</em>th line number. * <p> * Does not check that these is the <em>only</em> diagnostic kinds returned! * * @param expectedDiagnosticKinds * the kinds of diagnostic expected * @param expectedLineNumber * the line numbers at which the diagnostics are expected * @param diagnostics * the result of the compilation * @see #assertCompilationSuccessful(List) * @see #assertCompilationReturned(Kind, long, List) */ protected static void assertCompilationReturned(Kind[] expectedDiagnosticKinds, long[] expectedLineNumbers, List<Diagnostic<? extends JavaFileObject>> diagnostics) { assert ((expectedDiagnosticKinds != null) && (expectedLineNumbers != null) && (expectedDiagnosticKinds.length == expectedLineNumbers.length)); for (int i = 0; i < expectedDiagnosticKinds.length; i++) { assertCompilationReturned(expectedDiagnosticKinds[i], expectedLineNumbers[i], diagnostics); } } /** * Asserts that the compilation produced a result of the following * {@link Kind} at the given line number. * <p> * Does not check that this is the <em>only</em> diagnostic kind returned! * * @param expectedDiagnosticKind * the kind of diagnostic expected * @param expectedLineNumber * the line number at which the diagnostic is expected * @param diagnostics * the result of the compilation * @see #assertCompilationSuccessful(List) * @see #assertCompilationReturned(Kind[], long[], List) */ protected static void assertCompilationReturned(Kind expectedDiagnosticKind, long expectedLineNumber, List<Diagnostic<? extends JavaFileObject>> diagnostics) { assert ((expectedDiagnosticKind != null) && (diagnostics != null)); boolean expectedDiagnosticFound = false; for (Diagnostic<? extends JavaFileObject> diagnostic : diagnostics) { if (diagnostic.getKind().equals(expectedDiagnosticKind) && (diagnostic.getLineNumber() == expectedLineNumber)) { expectedDiagnosticFound = true; } } assertTrue("Expected a result of kind " + expectedDiagnosticKind + " at line " + expectedLineNumber, expectedDiagnosticFound); } }