mirror of
https://github.com/mapstruct/mapstruct.git
synced 2025-07-12 00:00:08 +08:00
Migrate the processor test infrastructure from Junit 4 to JUnit Jupiter
With JUnit Jupiter it is still not possible to set the ClassLoader for loading the test class.
Therefore, use the ModifiedClassLoaderExtension (heavily inspired by the Spring Boot bde7bd0a1a/spring-boot-project/spring-boot-tools/spring-boot-test-support/src/main/java/org/springframework/boot/testsupport/classpath/ModifiedClassPathExtension.java
).
Once JUnit Jupiter 201 is resolved we can simplify this.
With this extension we can catch all the tests in a class and then run them once the Class Extension Store gets closed with a modified ClassLoader.
The CompilationCache is stored in the GlobalCache with the CompilationRequest as key.
This means that even when methods are not executed in some particular order if they have same WithClasses
then they would reuse the cache.
This commit is contained in:
parent
a6b3cc364a
commit
ff27b2f70d
@ -24,7 +24,7 @@
|
||||
<org.mapstruct.gem.version>1.0.0.Alpha1</org.mapstruct.gem.version>
|
||||
<!-- We can't go to 3.0.0-M2 as it has a regression. See https://issues.apache.org/jira/browse/MENFORCER-306 -->
|
||||
<org.apache.maven.plugins.enforcer.version>3.0.0-M1</org.apache.maven.plugins.enforcer.version>
|
||||
<org.apache.maven.plugins.surefire.version>3.0.0-M3</org.apache.maven.plugins.surefire.version>
|
||||
<org.apache.maven.plugins.surefire.version>3.0.0-M4</org.apache.maven.plugins.surefire.version>
|
||||
<org.apache.maven.plugins.javadoc.version>3.1.0</org.apache.maven.plugins.javadoc.version>
|
||||
<org.springframework.version>4.0.3.RELEASE</org.springframework.version>
|
||||
<org.eclipse.tycho.compiler-jdt.version>0.26.0</org.eclipse.tycho.compiler-jdt.version>
|
||||
|
@ -49,8 +49,13 @@
|
||||
</dependency>
|
||||
<!-- Test -->
|
||||
<dependency>
|
||||
<groupId>junit</groupId>
|
||||
<artifactId>junit</artifactId>
|
||||
<groupId>org.junit.jupiter</groupId>
|
||||
<artifactId>junit-jupiter-api</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.junit.jupiter</groupId>
|
||||
<artifactId>junit-jupiter-engine</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
@ -104,6 +109,12 @@
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.junit.platform</groupId>
|
||||
<artifactId>junit-platform-launcher</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<!-- There is no compile dependency to Joda-Time; It's only required for testing the Joda conversions -->
|
||||
<dependency>
|
||||
<groupId>joda-time</groupId>
|
||||
|
@ -0,0 +1,52 @@
|
||||
/*
|
||||
* Copyright MapStruct Authors.
|
||||
*
|
||||
* Licensed under the Apache License version 2.0, available at http://www.apache.org/licenses/LICENSE-2.0
|
||||
*/
|
||||
package org.mapstruct.ap.testutil;
|
||||
|
||||
import java.lang.annotation.Documented;
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
import org.junit.jupiter.api.TestTemplate;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
import org.mapstruct.ap.testutil.runner.Compiler;
|
||||
import org.mapstruct.ap.testutil.runner.ModifiedClassLoaderExtension;
|
||||
import org.mapstruct.ap.testutil.runner.ProcessorTestExtension;
|
||||
|
||||
/**
|
||||
* JUnit Jupiter test template for the MapStruct Processor tests.
|
||||
* <p>
|
||||
* Test classes are safe to be executed in parallel, but test methods are not safe to be executed in parallel.
|
||||
* <p>
|
||||
* By default this template would generate tests for the JDK and Eclipse Compiler.
|
||||
* If only a single compiler is needed then specify the compiler in the value.
|
||||
* <p>
|
||||
* The classes to be compiled for a given test method must be specified via {@link WithClasses}. In addition the
|
||||
* following things can be configured optionally :
|
||||
* <ul>
|
||||
* <li>Processor options to be considered during compilation via
|
||||
* {@link org.mapstruct.ap.testutil.compilation.annotation.ProcessorOption ProcessorOption}.</li>
|
||||
* <li>The expected compilation outcome and expected diagnostics can be specified via
|
||||
* {@link org.mapstruct.ap.testutil.compilation.annotation.ExpectedCompilationOutcome ExpectedCompilationOutcome}.
|
||||
* If no outcome is specified, a successful compilation is assumed.</li>
|
||||
* </ul>
|
||||
*
|
||||
* @author Filip Hrisafov
|
||||
*/
|
||||
@Target({ ElementType.ANNOTATION_TYPE, ElementType.METHOD })
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Documented
|
||||
@TestTemplate
|
||||
@ExtendWith(ProcessorTestExtension.class)
|
||||
@ExtendWith(ModifiedClassLoaderExtension.class)
|
||||
public @interface ProcessorTest {
|
||||
|
||||
Compiler[] value() default {
|
||||
Compiler.JDK,
|
||||
Compiler.ECLIPSE
|
||||
};
|
||||
}
|
@ -1,157 +0,0 @@
|
||||
/*
|
||||
* Copyright MapStruct Authors.
|
||||
*
|
||||
* Licensed under the Apache License version 2.0, available at http://www.apache.org/licenses/LICENSE-2.0
|
||||
*/
|
||||
package org.mapstruct.ap.testutil.runner;
|
||||
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import org.junit.runner.Description;
|
||||
import org.junit.runner.Runner;
|
||||
import org.junit.runner.manipulation.Filter;
|
||||
import org.junit.runner.manipulation.NoTestsRemainException;
|
||||
import org.junit.runner.notification.RunNotifier;
|
||||
import org.junit.runners.BlockJUnit4ClassRunner;
|
||||
import org.junit.runners.ParentRunner;
|
||||
import org.mapstruct.ap.testutil.WithClasses;
|
||||
import org.mapstruct.ap.testutil.compilation.annotation.ExpectedCompilationOutcome;
|
||||
import org.mapstruct.ap.testutil.compilation.annotation.ProcessorOption;
|
||||
|
||||
/**
|
||||
* A JUnit4 runner for Annotation Processor tests.
|
||||
* <p>
|
||||
* Test classes are safe to be executed in parallel, but test methods are not safe to be executed in parallel.
|
||||
* <p>
|
||||
* The classes to be compiled for a given test method must be specified via {@link WithClasses}. In addition the
|
||||
* following things can be configured optionally :
|
||||
* <ul>
|
||||
* <li>Processor options to be considered during compilation via {@link ProcessorOption}.</li>
|
||||
* <li>The expected compilation outcome and expected diagnostics can be specified via {@link ExpectedCompilationOutcome}
|
||||
* . If no outcome is specified, a successful compilation is assumed.</li>
|
||||
* </ul>
|
||||
*
|
||||
* @author Gunnar Morling
|
||||
* @author Andreas Gudian
|
||||
*/
|
||||
public class AnnotationProcessorTestRunner extends ParentRunner<Runner> {
|
||||
|
||||
private static final boolean IS_AT_LEAST_JAVA_9 = isIsAtLeastJava9();
|
||||
|
||||
private static boolean isIsAtLeastJava9() {
|
||||
try {
|
||||
Runtime.class.getMethod( "version" );
|
||||
return true;
|
||||
}
|
||||
catch ( NoSuchMethodException e ) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private final List<Runner> runners;
|
||||
|
||||
/**
|
||||
* @param klass the test class
|
||||
*
|
||||
* @throws Exception see {@link BlockJUnit4ClassRunner#BlockJUnit4ClassRunner(Class)}
|
||||
*/
|
||||
public AnnotationProcessorTestRunner(Class<?> klass) throws Exception {
|
||||
super( klass );
|
||||
|
||||
runners = createRunners( klass );
|
||||
}
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
private List<Runner> createRunners(Class<?> klass) throws Exception {
|
||||
WithSingleCompiler singleCompiler = klass.getAnnotation( WithSingleCompiler.class );
|
||||
|
||||
if (singleCompiler != null) {
|
||||
return Arrays.asList( new InnerAnnotationProcessorRunner( klass, singleCompiler.value() ) );
|
||||
}
|
||||
else if ( IS_AT_LEAST_JAVA_9 ) {
|
||||
// Current tycho-compiler-jdt (0.26.0) is not compatible with Java 11
|
||||
// Updating to latest version 1.3.0 fails some tests
|
||||
// Once https://github.com/mapstruct/mapstruct/pull/1587 is resolved we can remove this line
|
||||
return Arrays.asList( new InnerAnnotationProcessorRunner( klass, Compiler.JDK11 ) );
|
||||
}
|
||||
|
||||
return Arrays.asList(
|
||||
new InnerAnnotationProcessorRunner( klass, Compiler.JDK ),
|
||||
new InnerAnnotationProcessorRunner( klass, Compiler.ECLIPSE )
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected List<Runner> getChildren() {
|
||||
return runners;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Description describeChild(Runner child) {
|
||||
return child.getDescription();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void runChild(Runner child, RunNotifier notifier) {
|
||||
child.run( notifier );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void filter(Filter filter) throws NoTestsRemainException {
|
||||
super.filter( new FilterDecorator( filter ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows to only execute selected methods, even if the executing framework is not aware of parameterized tests
|
||||
* (e.g. some versions of IntelliJ, Netbeans, Eclipse).
|
||||
*/
|
||||
private static final class FilterDecorator extends Filter {
|
||||
private final Filter delegate;
|
||||
|
||||
private FilterDecorator(Filter delegate) {
|
||||
this.delegate = delegate;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean shouldRun(Description description) {
|
||||
boolean shouldRun = delegate.shouldRun( description );
|
||||
if ( !shouldRun ) {
|
||||
return delegate.shouldRun( withoutParameterizedName( description ) );
|
||||
}
|
||||
|
||||
return shouldRun;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String describe() {
|
||||
return delegate.describe();
|
||||
}
|
||||
|
||||
private Description withoutParameterizedName(Description description) {
|
||||
String cleanDisplayName = removeParameter( description.getDisplayName() );
|
||||
Description cleanDescription =
|
||||
Description.createSuiteDescription(
|
||||
cleanDisplayName,
|
||||
description.getAnnotations().toArray( new Annotation[description.getAnnotations().size()] ) );
|
||||
|
||||
for ( Description child : description.getChildren() ) {
|
||||
cleanDescription.addChild( withoutParameterizedName( child ) );
|
||||
}
|
||||
|
||||
return cleanDescription;
|
||||
}
|
||||
|
||||
private String removeParameter(String name) {
|
||||
if ( name.startsWith( "[" ) ) {
|
||||
return name;
|
||||
}
|
||||
|
||||
// remove "[compiler]" from "method[compiler](class)"
|
||||
int open = name.indexOf( '[' );
|
||||
int close = name.indexOf( ']' ) + 1;
|
||||
return name.substring( 0, open ) + name.substring( close );
|
||||
}
|
||||
}
|
||||
}
|
@ -13,11 +13,13 @@ import java.util.Set;
|
||||
* Represents a compilation task for a number of sources with given processor options.
|
||||
*/
|
||||
public class CompilationRequest {
|
||||
private final Compiler compiler;
|
||||
private final Set<Class<?>> sourceClasses;
|
||||
private final Map<Class<?>, Class<?>> services;
|
||||
private final List<String> processorOptions;
|
||||
|
||||
CompilationRequest(Set<Class<?>> sourceClasses, Map<Class<?>, Class<?>> services, List<String> processorOptions) {
|
||||
CompilationRequest(Compiler compiler, Set<Class<?>> sourceClasses, Map<Class<?>, Class<?>> services, List<String> processorOptions) {
|
||||
this.compiler = compiler;
|
||||
this.sourceClasses = sourceClasses;
|
||||
this.services = services;
|
||||
this.processorOptions = processorOptions;
|
||||
@ -27,6 +29,7 @@ public class CompilationRequest {
|
||||
public int hashCode() {
|
||||
final int prime = 31;
|
||||
int result = 1;
|
||||
result = prime * result + ( ( compiler == null ) ? 0 : compiler.hashCode() );
|
||||
result = prime * result + ( ( processorOptions == null ) ? 0 : processorOptions.hashCode() );
|
||||
result = prime * result + ( ( services == null ) ? 0 : services.hashCode() );
|
||||
result = prime * result + ( ( sourceClasses == null ) ? 0 : sourceClasses.hashCode() );
|
||||
@ -46,7 +49,8 @@ public class CompilationRequest {
|
||||
}
|
||||
CompilationRequest other = (CompilationRequest) obj;
|
||||
|
||||
return processorOptions.equals( other.processorOptions )
|
||||
return compiler.equals( other.compiler )
|
||||
&& processorOptions.equals( other.processorOptions )
|
||||
&& services.equals( other.services )
|
||||
&& sourceClasses.equals( other.sourceClasses );
|
||||
}
|
||||
|
@ -5,10 +5,30 @@
|
||||
*/
|
||||
package org.mapstruct.ap.testutil.runner;
|
||||
|
||||
import org.junit.jupiter.api.condition.JRE;
|
||||
|
||||
/**
|
||||
* @author Andreas Gudian
|
||||
*
|
||||
* @author Filip Hrisafov
|
||||
*/
|
||||
public enum Compiler {
|
||||
JDK, JDK11, ECLIPSE;
|
||||
JDK,
|
||||
// Current tycho-compiler-jdt (0.26.0) is not compatible with Java 11
|
||||
// Updating to latest version 1.6.0 fails some tests
|
||||
// Once https://github.com/mapstruct/mapstruct/pull/1587 is resolved we can remove the max JRE
|
||||
ECLIPSE( JRE.JAVA_8 );
|
||||
|
||||
private final JRE max;
|
||||
|
||||
Compiler() {
|
||||
this( JRE.OTHER );
|
||||
}
|
||||
|
||||
Compiler(JRE max) {
|
||||
this.max = max;
|
||||
}
|
||||
|
||||
public JRE maxJre() {
|
||||
return max;
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,40 @@
|
||||
/*
|
||||
* Copyright MapStruct Authors.
|
||||
*
|
||||
* Licensed under the Apache License version 2.0, available at http://www.apache.org/licenses/LICENSE-2.0
|
||||
*/
|
||||
package org.mapstruct.ap.testutil.runner;
|
||||
|
||||
import org.junit.jupiter.api.extension.ConditionEvaluationResult;
|
||||
import org.junit.jupiter.api.extension.ExecutionCondition;
|
||||
import org.junit.jupiter.api.extension.ExtensionContext;
|
||||
|
||||
import static org.mapstruct.ap.testutil.runner.ProcessorTestInvocationContext.CURRENT_VERSION;
|
||||
|
||||
/**
|
||||
* Every compiler is registered with it's max supported JRE that it can run on.
|
||||
* This condition is used to check if the test for a particular compiler can be run with the current JRE.
|
||||
*
|
||||
* @author Filip Hrisafov
|
||||
*/
|
||||
public class CompilerTestEnabledOnJreCondition implements ExecutionCondition {
|
||||
|
||||
static final ConditionEvaluationResult ENABLED_ON_CURRENT_JRE =
|
||||
ConditionEvaluationResult.enabled( "Enabled on JRE version: " + System.getProperty( "java.version" ) );
|
||||
|
||||
static final ConditionEvaluationResult DISABLED_ON_CURRENT_JRE =
|
||||
ConditionEvaluationResult.disabled( "Disabled on JRE version: " + System.getProperty( "java.version" ) );
|
||||
|
||||
protected final Compiler compiler;
|
||||
|
||||
public CompilerTestEnabledOnJreCondition(Compiler compiler) {
|
||||
this.compiler = compiler;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ConditionEvaluationResult evaluateExecutionCondition(ExtensionContext context) {
|
||||
// If the max JRE is greater or equal to the current version the test is enabled
|
||||
return compiler.maxJre().compareTo( CURRENT_VERSION ) >= 0 ? ENABLED_ON_CURRENT_JRE :
|
||||
DISABLED_ON_CURRENT_JRE;
|
||||
}
|
||||
}
|
@ -5,16 +5,14 @@
|
||||
*/
|
||||
package org.mapstruct.ap.testutil.runner;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.File;
|
||||
import java.io.FileWriter;
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
@ -25,35 +23,40 @@ import java.util.Properties;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import com.puppycrawl.tools.checkstyle.api.AutomaticBean;
|
||||
import org.junit.runners.model.FrameworkMethod;
|
||||
import org.junit.runners.model.Statement;
|
||||
import org.mapstruct.ap.testutil.WithClasses;
|
||||
import org.mapstruct.ap.testutil.WithServiceImplementation;
|
||||
import org.mapstruct.ap.testutil.WithServiceImplementations;
|
||||
import org.mapstruct.ap.testutil.compilation.annotation.CompilationResult;
|
||||
import org.mapstruct.ap.testutil.compilation.annotation.DisableCheckstyle;
|
||||
import org.mapstruct.ap.testutil.compilation.annotation.ExpectedCompilationOutcome;
|
||||
import org.mapstruct.ap.testutil.compilation.annotation.ExpectedNote;
|
||||
import org.mapstruct.ap.testutil.compilation.annotation.ProcessorOption;
|
||||
import org.mapstruct.ap.testutil.compilation.annotation.ProcessorOptions;
|
||||
import org.mapstruct.ap.testutil.compilation.model.CompilationOutcomeDescriptor;
|
||||
import org.mapstruct.ap.testutil.compilation.model.DiagnosticDescriptor;
|
||||
import org.xml.sax.InputSource;
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
import com.google.common.io.ByteStreams;
|
||||
import com.puppycrawl.tools.checkstyle.Checker;
|
||||
import com.puppycrawl.tools.checkstyle.ConfigurationLoader;
|
||||
import com.puppycrawl.tools.checkstyle.DefaultLogger;
|
||||
import com.puppycrawl.tools.checkstyle.PropertiesExpander;
|
||||
import com.puppycrawl.tools.checkstyle.api.AutomaticBean;
|
||||
import org.junit.jupiter.api.extension.BeforeEachCallback;
|
||||
import org.junit.jupiter.api.extension.ExtensionContext;
|
||||
import org.mapstruct.ap.testutil.WithClasses;
|
||||
import org.mapstruct.ap.testutil.WithServiceImplementation;
|
||||
import org.mapstruct.ap.testutil.compilation.annotation.CompilationResult;
|
||||
import org.mapstruct.ap.testutil.compilation.annotation.DisableCheckstyle;
|
||||
import org.mapstruct.ap.testutil.compilation.annotation.ExpectedCompilationOutcome;
|
||||
import org.mapstruct.ap.testutil.compilation.annotation.ExpectedNote;
|
||||
import org.mapstruct.ap.testutil.compilation.annotation.ProcessorOption;
|
||||
import org.mapstruct.ap.testutil.compilation.model.CompilationOutcomeDescriptor;
|
||||
import org.mapstruct.ap.testutil.compilation.model.DiagnosticDescriptor;
|
||||
import org.xml.sax.InputSource;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.junit.platform.commons.support.AnnotationSupport.findAnnotation;
|
||||
import static org.junit.platform.commons.support.AnnotationSupport.findRepeatableAnnotations;
|
||||
import static org.mapstruct.ap.testutil.runner.ModifiedClassLoaderExtension.isModifiedClassPathClassLoader;
|
||||
|
||||
/**
|
||||
* A JUnit4 statement that performs source generation using the annotation processor and compiles those sources.
|
||||
* A JUnit Jupiter Extension that performs source generation using the annotation processor and compiles those sources.
|
||||
*
|
||||
* @author Andreas Gudian
|
||||
* @author Filip Hrisafov
|
||||
*/
|
||||
abstract class CompilingStatement extends Statement {
|
||||
abstract class CompilingExtension implements BeforeEachCallback {
|
||||
|
||||
static final ExtensionContext.Namespace NAMESPACE = ExtensionContext.Namespace.create( new Object() );
|
||||
|
||||
private static final String TARGET_COMPILATION_TESTS = "/target/compilation-tests/";
|
||||
|
||||
@ -67,46 +70,20 @@ abstract class CompilingStatement extends Statement {
|
||||
|
||||
protected static final List<String> PROCESSOR_CLASSPATH = buildProcessorClasspath();
|
||||
|
||||
private final FrameworkMethod method;
|
||||
private final CompilationCache compilationCache;
|
||||
private final boolean runCheckstyle;
|
||||
private Statement next;
|
||||
|
||||
private String classOutputDir;
|
||||
private String sourceOutputDir;
|
||||
private String additionalCompilerClasspath;
|
||||
private CompilationRequest compilationRequest;
|
||||
private final Compiler compiler;
|
||||
|
||||
CompilingStatement(FrameworkMethod method, CompilationCache compilationCache) {
|
||||
this.method = method;
|
||||
this.compilationCache = compilationCache;
|
||||
this.runCheckstyle = !method.getMethod().getDeclaringClass().isAnnotationPresent( DisableCheckstyle.class );
|
||||
|
||||
this.compilationRequest = new CompilationRequest( getTestClasses(), getServices(), getProcessorOptions() );
|
||||
protected CompilingExtension(Compiler compiler) {
|
||||
this.compiler = compiler;
|
||||
}
|
||||
|
||||
void setNextStatement(Statement next) {
|
||||
this.next = next;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void evaluate() throws Throwable {
|
||||
generateMapperImplementation();
|
||||
|
||||
GeneratedSource.setCompilingStatement( this );
|
||||
next.evaluate();
|
||||
GeneratedSource.clearCompilingStatement();
|
||||
}
|
||||
|
||||
String getSourceOutputDir() {
|
||||
return compilationCache.getLastSourceOutputDir();
|
||||
}
|
||||
|
||||
protected void setupDirectories() {
|
||||
protected void setupDirectories(Method testMethod, Class<?> testClass) {
|
||||
String compilationRoot = getBasePath()
|
||||
+ TARGET_COMPILATION_TESTS
|
||||
+ method.getDeclaringClass().getName()
|
||||
+ "/" + method.getName()
|
||||
+ testClass.getName()
|
||||
+ "/" + testMethod.getName()
|
||||
+ getPathSuffix();
|
||||
|
||||
classOutputDir = compilationRoot + "/classes";
|
||||
@ -118,7 +95,9 @@ abstract class CompilingStatement extends Statement {
|
||||
( (ModifiableURLClassLoader) Thread.currentThread().getContextClassLoader() ).withPath( classOutputDir );
|
||||
}
|
||||
|
||||
protected abstract String getPathSuffix();
|
||||
protected String getPathSuffix() {
|
||||
return "_" + compiler.name().toLowerCase();
|
||||
}
|
||||
|
||||
private static List<String> buildTestCompilationClasspath() {
|
||||
String[] whitelist =
|
||||
@ -169,14 +148,25 @@ abstract class CompilingStatement extends Statement {
|
||||
return Stream.of( whitelist ).anyMatch( path::contains );
|
||||
}
|
||||
|
||||
protected void generateMapperImplementation() throws Exception {
|
||||
CompilationOutcomeDescriptor actualResult = compile();
|
||||
@Override
|
||||
public void beforeEach(ExtensionContext context) throws Exception {
|
||||
if ( !isModifiedClassPathClassLoader( context ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
CompilationOutcomeDescriptor actualResult = compile( context );
|
||||
assertResult( actualResult, context );
|
||||
}
|
||||
|
||||
private void assertResult(CompilationOutcomeDescriptor actualResult, ExtensionContext context) throws Exception {
|
||||
Method testMethod = context.getRequiredTestMethod();
|
||||
Class<?> testClass = context.getRequiredTestClass();
|
||||
|
||||
CompilationOutcomeDescriptor expectedResult =
|
||||
CompilationOutcomeDescriptor.forExpectedCompilationResult(
|
||||
method.getAnnotation( ExpectedCompilationOutcome.class ),
|
||||
method.getAnnotation( ExpectedNote.ExpectedNotes.class ),
|
||||
method.getAnnotation( ExpectedNote.class )
|
||||
findAnnotation( testMethod, ExpectedCompilationOutcome.class ).orElse( null ),
|
||||
findAnnotation( testMethod, ExpectedNote.ExpectedNotes.class ).orElse( null ),
|
||||
findAnnotation( testMethod, ExpectedNote.class ).orElse( null )
|
||||
);
|
||||
|
||||
if ( expectedResult.getCompilationResult() == CompilationResult.SUCCEEDED ) {
|
||||
@ -195,7 +185,7 @@ abstract class CompilingStatement extends Statement {
|
||||
assertDiagnostics( actualResult.getDiagnostics(), expectedResult.getDiagnostics() );
|
||||
assertNotes( actualResult.getNotes(), expectedResult.getNotes() );
|
||||
|
||||
if ( runCheckstyle ) {
|
||||
if ( !findAnnotation( testClass, DisableCheckstyle.class ).isPresent() ) {
|
||||
assertCheckstyleRules();
|
||||
}
|
||||
}
|
||||
@ -335,18 +325,14 @@ abstract class CompilingStatement extends Statement {
|
||||
*
|
||||
* @return A set containing the classes to be compiled for this test
|
||||
*/
|
||||
private Set<Class<?>> getTestClasses() {
|
||||
private Set<Class<?>> getTestClasses(Method testMethod, Class<?> testClass) {
|
||||
Set<Class<?>> testClasses = new HashSet<>();
|
||||
|
||||
WithClasses withClasses = method.getAnnotation( WithClasses.class );
|
||||
if ( withClasses != null ) {
|
||||
testClasses.addAll( Arrays.asList( withClasses.value() ) );
|
||||
}
|
||||
findAnnotation( testMethod, WithClasses.class )
|
||||
.ifPresent( withClasses -> testClasses.addAll( Arrays.asList( withClasses.value() ) ) );
|
||||
|
||||
withClasses = method.getMethod().getDeclaringClass().getAnnotation( WithClasses.class );
|
||||
if ( withClasses != null ) {
|
||||
testClasses.addAll( Arrays.asList( withClasses.value() ) );
|
||||
}
|
||||
findAnnotation( testClass, WithClasses.class )
|
||||
.ifPresent( withClasses -> testClasses.addAll( Arrays.asList( withClasses.value() ) ) );
|
||||
|
||||
if ( testClasses.isEmpty() ) {
|
||||
throw new IllegalStateException(
|
||||
@ -363,24 +349,19 @@ abstract class CompilingStatement extends Statement {
|
||||
* @return A map containing the package were to look for a resource (key) and the resource (value) to be compiled
|
||||
* for this test
|
||||
*/
|
||||
private Map<Class<?>, Class<?>> getServices() {
|
||||
private Map<Class<?>, Class<?>> getServices(Method testMethod, Class<?> testClass) {
|
||||
Map<Class<?>, Class<?>> services = new HashMap<>();
|
||||
|
||||
addServices( services, method.getAnnotation( WithServiceImplementations.class ) );
|
||||
addService( services, method.getAnnotation( WithServiceImplementation.class ) );
|
||||
addServices( services, findRepeatableAnnotations( testMethod, WithServiceImplementation.class ) );
|
||||
|
||||
Class<?> declaringClass = method.getMethod().getDeclaringClass();
|
||||
addServices( services, declaringClass.getAnnotation( WithServiceImplementations.class ) );
|
||||
addService( services, declaringClass.getAnnotation( WithServiceImplementation.class ) );
|
||||
addServices( services, findRepeatableAnnotations( testClass, WithServiceImplementation.class ) );
|
||||
|
||||
return services;
|
||||
}
|
||||
|
||||
private void addServices(Map<Class<?>, Class<?>> services, WithServiceImplementations withImplementations) {
|
||||
if ( withImplementations != null ) {
|
||||
for ( WithServiceImplementation resource : withImplementations.value() ) {
|
||||
addService( services, resource );
|
||||
}
|
||||
private void addServices(Map<Class<?>, Class<?>> services, List<WithServiceImplementation> withImplementations) {
|
||||
for ( WithServiceImplementation withImplementation : withImplementations ) {
|
||||
addService( services, withImplementation );
|
||||
}
|
||||
}
|
||||
|
||||
@ -411,17 +392,11 @@ abstract class CompilingStatement extends Statement {
|
||||
*
|
||||
* @return A list containing the processor options to be used for this test
|
||||
*/
|
||||
private List<String> getProcessorOptions() {
|
||||
List<ProcessorOption> processorOptions =
|
||||
getProcessorOptions(
|
||||
method.getAnnotation( ProcessorOptions.class ),
|
||||
method.getAnnotation( ProcessorOption.class ) );
|
||||
private List<String> getProcessorOptions(Method testMethod, Class<?> testClass) {
|
||||
List<ProcessorOption> processorOptions = findRepeatableAnnotations( testMethod, ProcessorOption.class );
|
||||
|
||||
if ( processorOptions.isEmpty() ) {
|
||||
processorOptions =
|
||||
getProcessorOptions(
|
||||
method.getMethod().getDeclaringClass().getAnnotation( ProcessorOptions.class ),
|
||||
method.getMethod().getDeclaringClass().getAnnotation( ProcessorOption.class ) );
|
||||
processorOptions = findRepeatableAnnotations( testClass, ProcessorOption.class );
|
||||
}
|
||||
|
||||
List<String> result = new ArrayList<>( processorOptions.size() );
|
||||
@ -435,17 +410,6 @@ abstract class CompilingStatement extends Statement {
|
||||
return result;
|
||||
}
|
||||
|
||||
private List<ProcessorOption> getProcessorOptions(ProcessorOptions options, ProcessorOption option) {
|
||||
if ( options != null ) {
|
||||
return Arrays.asList( options.value() );
|
||||
}
|
||||
else if ( option != null ) {
|
||||
return Arrays.asList( option );
|
||||
}
|
||||
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
private String asOptionString(ProcessorOption processorOption) {
|
||||
return String.format( "-A%s=%s", processorOption.name(), processorOption.value() );
|
||||
}
|
||||
@ -465,17 +429,31 @@ abstract class CompilingStatement extends Statement {
|
||||
return sourceFiles;
|
||||
}
|
||||
|
||||
private CompilationOutcomeDescriptor compile()
|
||||
throws Exception {
|
||||
private CompilationOutcomeDescriptor compile(ExtensionContext context) {
|
||||
Method testMethod = context.getRequiredTestMethod();
|
||||
Class<?> testClass = context.getRequiredTestClass();
|
||||
|
||||
if ( !needsRecompilation() ) {
|
||||
CompilationRequest compilationRequest = new CompilationRequest(
|
||||
compiler,
|
||||
getTestClasses( testMethod, testClass ),
|
||||
getServices( testMethod, testClass ),
|
||||
getProcessorOptions( testMethod, testClass )
|
||||
);
|
||||
|
||||
ExtensionContext.Store rootStore = context.getRoot().getStore( NAMESPACE );
|
||||
|
||||
context.getStore( NAMESPACE ).put( context.getUniqueId() + "-compilationRequest", compilationRequest );
|
||||
CompilationCache compilationCache = rootStore
|
||||
.getOrComputeIfAbsent( compilationRequest, request -> new CompilationCache(), CompilationCache.class );
|
||||
|
||||
if ( !needsRecompilation( compilationRequest, compilationCache ) ) {
|
||||
return compilationCache.getLastResult();
|
||||
}
|
||||
|
||||
setupDirectories();
|
||||
setupDirectories( testMethod, testClass );
|
||||
compilationCache.setLastSourceOutputDir( sourceOutputDir );
|
||||
|
||||
boolean needsAdditionalCompilerClasspath = prepareServices();
|
||||
boolean needsAdditionalCompilerClasspath = prepareServices( compilationRequest );
|
||||
CompilationOutcomeDescriptor resultHolder;
|
||||
|
||||
resultHolder = compileWithSpecificCompiler(
|
||||
@ -503,7 +481,7 @@ abstract class CompilingStatement extends Statement {
|
||||
String classOutputDir,
|
||||
String additionalCompilerClasspath);
|
||||
|
||||
boolean needsRecompilation() {
|
||||
boolean needsRecompilation(CompilationRequest compilationRequest, CompilationCache compilationCache) {
|
||||
return !compilationRequest.equals( compilationCache.getLastRequest() );
|
||||
}
|
||||
|
||||
@ -545,7 +523,7 @@ abstract class CompilingStatement extends Statement {
|
||||
path.delete();
|
||||
}
|
||||
|
||||
private boolean prepareServices() {
|
||||
private boolean prepareServices(CompilationRequest compilationRequest) {
|
||||
if ( !compilationRequest.getServices().isEmpty() ) {
|
||||
String servicesDir =
|
||||
additionalCompilerClasspath + File.separator + "META-INF" + File.separator + "services";
|
@ -1,26 +0,0 @@
|
||||
/*
|
||||
* Copyright MapStruct Authors.
|
||||
*
|
||||
* Licensed under the Apache License version 2.0, available at http://www.apache.org/licenses/LICENSE-2.0
|
||||
*/
|
||||
package org.mapstruct.ap.testutil.runner;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* This should be used with care.
|
||||
* This is similar to the JUnit 5 DisabledOnJre (once we have JUnit 5 we can replace this one)
|
||||
*
|
||||
* @author Filip Hrisafov
|
||||
*/
|
||||
@Target(ElementType.METHOD)
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface DisabledOnCompiler {
|
||||
/**
|
||||
* @return The compiler to use.
|
||||
*/
|
||||
Compiler value();
|
||||
}
|
@ -14,16 +14,16 @@ import org.codehaus.plexus.compiler.CompilerException;
|
||||
import org.codehaus.plexus.compiler.CompilerResult;
|
||||
import org.codehaus.plexus.logging.console.ConsoleLogger;
|
||||
import org.eclipse.tycho.compiler.jdt.JDTCompiler;
|
||||
import org.junit.runners.model.FrameworkMethod;
|
||||
import org.mapstruct.ap.MappingProcessor;
|
||||
import org.mapstruct.ap.testutil.compilation.model.CompilationOutcomeDescriptor;
|
||||
|
||||
/**
|
||||
* Statement that uses the Eclipse JDT compiler to compile.
|
||||
* Extension that uses the Eclipse JDT compiler to compile.
|
||||
*
|
||||
* @author Andreas Gudian
|
||||
* @author Filip Hrisafov
|
||||
*/
|
||||
class EclipseCompilingStatement extends CompilingStatement {
|
||||
class EclipseCompilingExtension extends CompilingExtension {
|
||||
|
||||
private static final List<String> ECLIPSE_COMPILER_CLASSPATH = buildEclipseCompilerClasspath();
|
||||
|
||||
@ -33,8 +33,8 @@ class EclipseCompilingStatement extends CompilingStatement {
|
||||
.withPaths( PROCESSOR_CLASSPATH )
|
||||
.withOriginOf( ClassLoaderExecutor.class );
|
||||
|
||||
EclipseCompilingStatement(FrameworkMethod method, CompilationCache compilationCache) {
|
||||
super( method, compilationCache );
|
||||
EclipseCompilingExtension() {
|
||||
super( Compiler.ECLIPSE );
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -140,9 +140,4 @@ class EclipseCompilingStatement extends CompilingStatement {
|
||||
|
||||
return filterBootClassPath( whitelist );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getPathSuffix() {
|
||||
return "_eclipse";
|
||||
}
|
||||
}
|
@ -1,26 +0,0 @@
|
||||
/*
|
||||
* Copyright MapStruct Authors.
|
||||
*
|
||||
* Licensed under the Apache License version 2.0, available at http://www.apache.org/licenses/LICENSE-2.0
|
||||
*/
|
||||
package org.mapstruct.ap.testutil.runner;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* This should be used with care.
|
||||
* This is similar to the JUnit 5 EnabledOnJre (once we have JUnit 5 we can replace this one)
|
||||
*
|
||||
* @author Filip Hrisafov
|
||||
*/
|
||||
@Target(ElementType.METHOD)
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface EnabledOnCompiler {
|
||||
/**
|
||||
* @return The compiler to use.
|
||||
*/
|
||||
Compiler value();
|
||||
}
|
@ -13,48 +13,67 @@ import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import org.junit.rules.TestRule;
|
||||
import org.junit.runner.Description;
|
||||
import org.junit.runners.model.Statement;
|
||||
import org.junit.jupiter.api.extension.AfterTestExecutionCallback;
|
||||
import org.junit.jupiter.api.extension.BeforeTestExecutionCallback;
|
||||
import org.junit.jupiter.api.extension.ExtensionContext;
|
||||
import org.mapstruct.ap.testutil.assertions.JavaFileAssert;
|
||||
|
||||
import static org.assertj.core.api.Assertions.fail;
|
||||
import static org.mapstruct.ap.testutil.runner.CompilingExtension.NAMESPACE;
|
||||
import static org.mapstruct.ap.testutil.runner.ModifiedClassLoaderExtension.isModifiedClassPathClassLoader;
|
||||
|
||||
/**
|
||||
* A {@link TestRule} to perform assertions on generated source files.
|
||||
* A {@link org.junit.jupiter.api.extension.RegisterExtension RegisterExtension} to perform assertions on generated
|
||||
* source files.
|
||||
* <p>
|
||||
* To add it to the test, use:
|
||||
*
|
||||
* <pre>
|
||||
* @Rule
|
||||
* public GeneratedSource generatedSources = new GeneratedSource();
|
||||
* @RegisterExtension
|
||||
* final GeneratedSource generatedSources = new GeneratedSource();
|
||||
* </pre>
|
||||
*
|
||||
* @author Andreas Gudian
|
||||
*/
|
||||
public class GeneratedSource implements TestRule {
|
||||
public class GeneratedSource implements BeforeTestExecutionCallback, AfterTestExecutionCallback {
|
||||
|
||||
private static final String FIXTURES_ROOT = "fixtures/";
|
||||
|
||||
/**
|
||||
* static ThreadLocal, as the {@link CompilingStatement} must inject itself statically for this rule to gain access
|
||||
* to the statement's information. As test execution of different classes in parallel is supported.
|
||||
* ThreadLocal, as the source dir must be injected for this extension to gain access
|
||||
* to the compilation information. As test execution of different classes in parallel is supported.
|
||||
*/
|
||||
private static ThreadLocal<CompilingStatement> compilingStatement = new ThreadLocal<>();
|
||||
private ThreadLocal<String> sourceOutputDir = new ThreadLocal<>();
|
||||
|
||||
private List<Class<?>> fixturesFor = new ArrayList<>();
|
||||
|
||||
@Override
|
||||
public Statement apply(Statement base, Description description) {
|
||||
return new GeneratedSourceStatement( base );
|
||||
public void beforeTestExecution(ExtensionContext context) throws Exception {
|
||||
if ( !isModifiedClassPathClassLoader( context ) ) {
|
||||
return;
|
||||
}
|
||||
CompilationRequest compilationRequest = context.getStore( NAMESPACE )
|
||||
.get( context.getUniqueId() + "-compilationRequest", CompilationRequest.class );
|
||||
setSourceOutputDir( context.getStore( NAMESPACE )
|
||||
.get( compilationRequest, CompilationCache.class )
|
||||
.getLastSourceOutputDir() );
|
||||
}
|
||||
|
||||
static void setCompilingStatement(CompilingStatement compilingStatement) {
|
||||
GeneratedSource.compilingStatement.set( compilingStatement );
|
||||
@Override
|
||||
public void afterTestExecution(ExtensionContext context) throws Exception {
|
||||
if ( !isModifiedClassPathClassLoader( context ) ) {
|
||||
return;
|
||||
}
|
||||
handleFixtureComparison();
|
||||
clearSourceOutputDir();
|
||||
}
|
||||
|
||||
static void clearCompilingStatement() {
|
||||
GeneratedSource.compilingStatement.remove();
|
||||
private void setSourceOutputDir(String sourceOutputDir) {
|
||||
this.sourceOutputDir.set( sourceOutputDir );
|
||||
}
|
||||
|
||||
private void clearSourceOutputDir() {
|
||||
this.sourceOutputDir.remove();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -101,21 +120,7 @@ public class GeneratedSource implements TestRule {
|
||||
* @return an assert for the file specified by the given path
|
||||
*/
|
||||
public JavaFileAssert forJavaFile(String path) {
|
||||
return new JavaFileAssert( new File( compilingStatement.get().getSourceOutputDir() + "/" + path ) );
|
||||
}
|
||||
|
||||
private class GeneratedSourceStatement extends Statement {
|
||||
private final Statement next;
|
||||
|
||||
private GeneratedSourceStatement(Statement next) {
|
||||
this.next = next;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void evaluate() throws Throwable {
|
||||
next.evaluate();
|
||||
handleFixtureComparison();
|
||||
}
|
||||
return new JavaFileAssert( new File( sourceOutputDir.get() + "/" + path ) );
|
||||
}
|
||||
|
||||
private void handleFixtureComparison() throws UnsupportedEncodingException {
|
||||
|
@ -1,137 +0,0 @@
|
||||
/*
|
||||
* Copyright MapStruct Authors.
|
||||
*
|
||||
* Licensed under the Apache License version 2.0, available at http://www.apache.org/licenses/LICENSE-2.0
|
||||
*/
|
||||
package org.mapstruct.ap.testutil.runner;
|
||||
|
||||
import org.junit.runners.BlockJUnit4ClassRunner;
|
||||
import org.junit.runners.model.FrameworkMethod;
|
||||
import org.junit.runners.model.Statement;
|
||||
import org.junit.runners.model.TestClass;
|
||||
|
||||
/**
|
||||
* Internal test runner that runs the tests of one class for one specific compiler implementation.
|
||||
*
|
||||
* @author Andreas Gudian
|
||||
*/
|
||||
class InnerAnnotationProcessorRunner extends BlockJUnit4ClassRunner {
|
||||
static final ModifiableURLClassLoader TEST_CLASS_LOADER = new ModifiableURLClassLoader();
|
||||
private final Class<?> klass;
|
||||
private final Compiler compiler;
|
||||
private final CompilationCache compilationCache;
|
||||
private Class<?> klassToUse;
|
||||
private ReplacableTestClass replacableTestClass;
|
||||
|
||||
/**
|
||||
* @param klass the test class
|
||||
*
|
||||
* @throws Exception see {@link BlockJUnit4ClassRunner#BlockJUnit4ClassRunner(Class)}
|
||||
*/
|
||||
InnerAnnotationProcessorRunner(Class<?> klass, Compiler compiler) throws Exception {
|
||||
super( klass );
|
||||
this.klass = klass;
|
||||
this.compiler = compiler;
|
||||
this.compilationCache = new CompilationCache();
|
||||
}
|
||||
|
||||
/**
|
||||
* newly loads the class with the test class loader and sets that loader as context class loader of the thread
|
||||
*
|
||||
* @param klass the class to replace
|
||||
*
|
||||
* @return the class loaded with the test class loader
|
||||
*/
|
||||
private static Class<?> replaceClassLoaderAndClass(Class<?> klass) {
|
||||
replaceContextClassLoader( klass );
|
||||
|
||||
try {
|
||||
return Thread.currentThread().getContextClassLoader().loadClass( klass.getName() );
|
||||
}
|
||||
catch ( ClassNotFoundException e ) {
|
||||
throw new RuntimeException( e );
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private static void replaceContextClassLoader(Class<?> klass) {
|
||||
ModifiableURLClassLoader testClassLoader = new ModifiableURLClassLoader().withOriginOf( klass );
|
||||
|
||||
Thread.currentThread().setContextClassLoader( testClassLoader );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean isIgnored(FrameworkMethod child) {
|
||||
return super.isIgnored( child ) || isIgnoredForCompiler( child );
|
||||
}
|
||||
|
||||
protected boolean isIgnoredForCompiler(FrameworkMethod child) {
|
||||
EnabledOnCompiler enabledOnCompiler = child.getAnnotation( EnabledOnCompiler.class );
|
||||
if ( enabledOnCompiler != null ) {
|
||||
return enabledOnCompiler.value() != compiler;
|
||||
}
|
||||
|
||||
DisabledOnCompiler disabledOnCompiler = child.getAnnotation( DisabledOnCompiler.class );
|
||||
if ( disabledOnCompiler != null ) {
|
||||
return disabledOnCompiler.value() == compiler;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected TestClass createTestClass(final Class<?> testClass) {
|
||||
replacableTestClass = new ReplacableTestClass( testClass );
|
||||
return replacableTestClass;
|
||||
}
|
||||
|
||||
private FrameworkMethod replaceFrameworkMethod(FrameworkMethod m) {
|
||||
try {
|
||||
return new FrameworkMethod(
|
||||
klassToUse.getDeclaredMethod( m.getName(), m.getMethod().getParameterTypes() ) );
|
||||
}
|
||||
catch ( NoSuchMethodException e ) {
|
||||
throw new RuntimeException( e );
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Statement methodBlock(FrameworkMethod method) {
|
||||
CompilingStatement statement = createCompilingStatement( method );
|
||||
if ( statement.needsRecompilation() ) {
|
||||
klassToUse = replaceClassLoaderAndClass( klass );
|
||||
|
||||
replacableTestClass.replaceClass( klassToUse );
|
||||
}
|
||||
|
||||
method = replaceFrameworkMethod( method );
|
||||
|
||||
Statement next = super.methodBlock( method );
|
||||
|
||||
statement.setNextStatement( next );
|
||||
|
||||
return statement;
|
||||
}
|
||||
|
||||
private CompilingStatement createCompilingStatement(FrameworkMethod method) {
|
||||
if ( compiler == Compiler.JDK ) {
|
||||
return new JdkCompilingStatement( method, compilationCache );
|
||||
}
|
||||
else if ( compiler == Compiler.JDK11 ) {
|
||||
return new Jdk11CompilingStatement( method, compilationCache );
|
||||
}
|
||||
else {
|
||||
return new EclipseCompilingStatement( method, compilationCache );
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getName() {
|
||||
return "[" + compiler.name().toLowerCase() + "]";
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String testName(FrameworkMethod method) {
|
||||
return method.getName() + getName();
|
||||
}
|
||||
}
|
@ -1,37 +0,0 @@
|
||||
/*
|
||||
* Copyright MapStruct Authors.
|
||||
*
|
||||
* Licensed under the Apache License version 2.0, available at http://www.apache.org/licenses/LICENSE-2.0
|
||||
*/
|
||||
package org.mapstruct.ap.testutil.runner;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.junit.runners.model.FrameworkMethod;
|
||||
import org.mapstruct.ap.testutil.compilation.model.DiagnosticDescriptor;
|
||||
|
||||
/**
|
||||
* Statement that uses the JDK compiler to compile.
|
||||
*
|
||||
* @author Filip Hrisafov
|
||||
*/
|
||||
class Jdk11CompilingStatement extends JdkCompilingStatement {
|
||||
|
||||
Jdk11CompilingStatement(FrameworkMethod method, CompilationCache compilationCache) {
|
||||
super( method, compilationCache );
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* The JDK 11 compiler reports all ERROR diagnostics properly. Also when there are multiple per line.
|
||||
*/
|
||||
@Override
|
||||
protected List<DiagnosticDescriptor> filterExpectedDiagnostics(List<DiagnosticDescriptor> expectedDiagnostics) {
|
||||
return expectedDiagnostics;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getPathSuffix() {
|
||||
return "_jdk";
|
||||
}
|
||||
}
|
@ -11,7 +11,6 @@ import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
import javax.annotation.processing.Processor;
|
||||
import javax.tools.Diagnostic.Kind;
|
||||
import javax.tools.DiagnosticCollector;
|
||||
@ -22,17 +21,20 @@ import javax.tools.StandardJavaFileManager;
|
||||
import javax.tools.StandardLocation;
|
||||
import javax.tools.ToolProvider;
|
||||
|
||||
import org.junit.runners.model.FrameworkMethod;
|
||||
import org.junit.jupiter.api.condition.JRE;
|
||||
import org.mapstruct.ap.MappingProcessor;
|
||||
import org.mapstruct.ap.testutil.compilation.model.CompilationOutcomeDescriptor;
|
||||
import org.mapstruct.ap.testutil.compilation.model.DiagnosticDescriptor;
|
||||
|
||||
import static org.mapstruct.ap.testutil.runner.ProcessorTestInvocationContext.CURRENT_VERSION;
|
||||
|
||||
/**
|
||||
* Statement that uses the JDK compiler to compile.
|
||||
* Extension that uses the JDK compiler to compile.
|
||||
*
|
||||
* @author Andreas Gudian
|
||||
* @author Filip Hrisafov
|
||||
*/
|
||||
class JdkCompilingStatement extends CompilingStatement {
|
||||
class JdkCompilingExtension extends CompilingExtension {
|
||||
|
||||
private static final List<File> COMPILER_CLASSPATH_FILES = asFiles( TEST_COMPILATION_CLASSPATH );
|
||||
|
||||
@ -40,8 +42,8 @@ class JdkCompilingStatement extends CompilingStatement {
|
||||
new ModifiableURLClassLoader( new FilteringParentClassLoader( "org.mapstruct." ) )
|
||||
.withPaths( PROCESSOR_CLASSPATH );
|
||||
|
||||
JdkCompilingStatement(FrameworkMethod method, CompilationCache compilationCache) {
|
||||
super( method, compilationCache );
|
||||
JdkCompilingExtension() {
|
||||
super( Compiler.JDK );
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -107,14 +109,20 @@ class JdkCompilingStatement extends CompilingStatement {
|
||||
}
|
||||
|
||||
/**
|
||||
* The JDK compiler only reports the first message of kind ERROR that is reported for one source file line, so we
|
||||
* filter out the surplus diagnostics. The input list is already sorted by file name and line number, with the order
|
||||
* for the diagnostics in the same line being kept at the order as given in the test.
|
||||
* The JDK 8 compiler needs some special treatment for the diagnostics.
|
||||
* See comment in the function.
|
||||
*/
|
||||
@Override
|
||||
protected List<DiagnosticDescriptor> filterExpectedDiagnostics(List<DiagnosticDescriptor> expectedDiagnostics) {
|
||||
List<DiagnosticDescriptor> filtered = new ArrayList<>( expectedDiagnostics.size() );
|
||||
if ( CURRENT_VERSION != JRE.JAVA_8 ) {
|
||||
// The JDK 8+ compilers report all ERROR diagnostics properly. Also when there are multiple per line.
|
||||
return expectedDiagnostics;
|
||||
}
|
||||
List<DiagnosticDescriptor> filtered = new ArrayList<DiagnosticDescriptor>( expectedDiagnostics.size() );
|
||||
|
||||
// The JDK 8 compiler only reports the first message of kind ERROR that is reported for one source file line,
|
||||
// so we filter out the surplus diagnostics. The input list is already sorted by file name and line number,
|
||||
// with the order for the diagnostics in the same line being kept at the order as given in the test.
|
||||
DiagnosticDescriptor previous = null;
|
||||
for ( DiagnosticDescriptor diag : expectedDiagnostics ) {
|
||||
if ( diag.getKind() != Kind.ERROR
|
||||
@ -129,8 +137,4 @@ class JdkCompilingStatement extends CompilingStatement {
|
||||
return filtered;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getPathSuffix() {
|
||||
return "_jdk";
|
||||
}
|
||||
}
|
@ -0,0 +1,178 @@
|
||||
/*
|
||||
* Copyright MapStruct Authors.
|
||||
*
|
||||
* Licensed under the Apache License version 2.0, available at http://www.apache.org/licenses/LICENSE-2.0
|
||||
*/
|
||||
package org.mapstruct.ap.testutil.runner;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.net.URLClassLoader;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.junit.jupiter.api.extension.ExtensionContext;
|
||||
import org.junit.jupiter.api.extension.InvocationInterceptor;
|
||||
import org.junit.jupiter.api.extension.ReflectiveInvocationContext;
|
||||
import org.junit.platform.engine.DiscoverySelector;
|
||||
import org.junit.platform.engine.discovery.DiscoverySelectors;
|
||||
import org.junit.platform.launcher.Launcher;
|
||||
import org.junit.platform.launcher.LauncherDiscoveryRequest;
|
||||
import org.junit.platform.launcher.TestPlan;
|
||||
import org.junit.platform.launcher.core.LauncherDiscoveryRequestBuilder;
|
||||
import org.junit.platform.launcher.core.LauncherFactory;
|
||||
import org.junit.platform.launcher.listeners.SummaryGeneratingListener;
|
||||
import org.junit.platform.launcher.listeners.TestExecutionSummary;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
|
||||
import static org.mapstruct.ap.testutil.runner.CompilingExtension.NAMESPACE;
|
||||
|
||||
// CHECKSTYLE:OFF
|
||||
/**
|
||||
* Special extension which is responsible for making sure that the tests are run with the
|
||||
* {@link ModifiableURLClassLoader}.
|
||||
* Otherwise, methods and classes might not be properly shared.
|
||||
* <p>
|
||||
* It intercepts all methods and if the test class was not loaded with the {@link ModifiableURLClassLoader}
|
||||
* then registers a selector for the test case to be run once the test is done.
|
||||
* The run is done by setting the Thread Context ClassLoader and manually invoking the {@link Launcher}
|
||||
* for the needed tests and test templates.
|
||||
* In order to be able to reuse the compilation caching we are running all tests once the current Class Extension
|
||||
* Context is closed.
|
||||
* <p>
|
||||
* This mechanism is needed since there is no way to register a custom ClassLoader for creating the test instance
|
||||
* in JUnit Jupiter (see <a href="https://github.com/junit-team/junit5/issues/201">junit-test/junit5#201</a>
|
||||
* for more information). Once there is support for registering a custom class loader we can simplify this.
|
||||
* <p>
|
||||
* This logic was heavily inspired and is really similar to the Spring Boot
|
||||
* <a href="https://github.com/spring-projects/spring-boot/blob/bde7bd0a1a310f48fb877b9a0d4a05b8d829d6c0/spring-boot-project/spring-boot-tools/spring-boot-test-support/src/main/java/org/springframework/boot/testsupport/classpath/ModifiedClassPathExtension.java">ModifiedClassPathExtension</a>.
|
||||
*
|
||||
* @author Filip Hrisafov
|
||||
* @see ModifiableURLClassLoader
|
||||
*/
|
||||
// CHECKSTYLE:ON
|
||||
public class ModifiedClassLoaderExtension implements InvocationInterceptor {
|
||||
|
||||
@Override
|
||||
public void interceptBeforeAllMethod(Invocation<Void> invocation,
|
||||
ReflectiveInvocationContext<Method> invocationContext, ExtensionContext extensionContext) throws Throwable {
|
||||
intercept( invocation, extensionContext );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void interceptBeforeEachMethod(Invocation<Void> invocation,
|
||||
ReflectiveInvocationContext<Method> invocationContext, ExtensionContext extensionContext) throws Throwable {
|
||||
intercept( invocation, extensionContext );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void interceptAfterEachMethod(Invocation<Void> invocation,
|
||||
ReflectiveInvocationContext<Method> invocationContext, ExtensionContext extensionContext) throws Throwable {
|
||||
intercept( invocation, extensionContext );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void interceptAfterAllMethod(Invocation<Void> invocation,
|
||||
ReflectiveInvocationContext<Method> invocationContext, ExtensionContext extensionContext) throws Throwable {
|
||||
intercept( invocation, extensionContext );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void interceptTestMethod(Invocation<Void> invocation, ReflectiveInvocationContext<Method> invocationContext,
|
||||
ExtensionContext extensionContext) throws Throwable {
|
||||
if ( isModifiedClassPathClassLoader( extensionContext ) ) {
|
||||
invocation.proceed();
|
||||
return;
|
||||
}
|
||||
invocation.skip();
|
||||
// For normal Tests the path to the Class Store is:
|
||||
// method -> class
|
||||
// This will most likely never be the case for a processor test.
|
||||
ExtensionContext.Store store = extensionContext.getParent()
|
||||
.orElseThrow( () -> new IllegalStateException( extensionContext + " has no parent store " ) )
|
||||
.getStore( NAMESPACE );
|
||||
registerSelector( extensionContext, store );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void interceptTestTemplateMethod(Invocation<Void> invocation,
|
||||
ReflectiveInvocationContext<Method> invocationContext, ExtensionContext extensionContext) throws Throwable {
|
||||
if ( isModifiedClassPathClassLoader( extensionContext ) ) {
|
||||
invocation.proceed();
|
||||
return;
|
||||
}
|
||||
invocation.skip();
|
||||
// For TestTemplates the path to the Class Store is:
|
||||
// method -> testTemplate -> class
|
||||
ExtensionContext.Store store = extensionContext.getParent()
|
||||
.flatMap( ExtensionContext::getParent )
|
||||
.orElseThrow( () -> new IllegalStateException( extensionContext + " has no parent store " ) )
|
||||
.getStore( NAMESPACE );
|
||||
registerSelector( extensionContext, store );
|
||||
}
|
||||
|
||||
private void registerSelector(ExtensionContext context, ExtensionContext.Store store) {
|
||||
store.getOrComputeIfAbsent(
|
||||
context.getRequiredTestClass() + "-discoverySelectors",
|
||||
s -> new SelectorsToRun( context.getRequiredTestClass() ),
|
||||
SelectorsToRun.class
|
||||
).discoverySelectors.add( DiscoverySelectors.selectUniqueId( context.getUniqueId() ) );
|
||||
}
|
||||
|
||||
private static void runTestWithModifiedClassPath(Class<?> testClass, List<? extends DiscoverySelector> selectors)
|
||||
throws Throwable {
|
||||
ClassLoader originalClassLoader = Thread.currentThread().getContextClassLoader();
|
||||
URLClassLoader modifiedClassLoader =
|
||||
new ModifiableURLClassLoader().withOriginOf( testClass );
|
||||
Thread.currentThread().setContextClassLoader( modifiedClassLoader );
|
||||
try {
|
||||
runTest( selectors );
|
||||
}
|
||||
finally {
|
||||
Thread.currentThread().setContextClassLoader( originalClassLoader );
|
||||
}
|
||||
}
|
||||
|
||||
private static void runTest(List<? extends DiscoverySelector> selectors) throws Throwable {
|
||||
LauncherDiscoveryRequest request = LauncherDiscoveryRequestBuilder.request()
|
||||
.selectors( selectors )
|
||||
.build();
|
||||
Launcher launcher = LauncherFactory.create();
|
||||
TestPlan testPlan = launcher.discover( request );
|
||||
SummaryGeneratingListener listener = new SummaryGeneratingListener();
|
||||
launcher.registerTestExecutionListeners( listener );
|
||||
launcher.execute( testPlan );
|
||||
TestExecutionSummary summary = listener.getSummary();
|
||||
if ( !CollectionUtils.isEmpty( summary.getFailures() ) ) {
|
||||
throw summary.getFailures().get( 0 ).getException();
|
||||
}
|
||||
}
|
||||
|
||||
private void intercept(Invocation<Void> invocation, ExtensionContext extensionContext) throws Throwable {
|
||||
if ( isModifiedClassPathClassLoader( extensionContext ) ) {
|
||||
invocation.proceed();
|
||||
return;
|
||||
}
|
||||
invocation.skip();
|
||||
}
|
||||
|
||||
static boolean isModifiedClassPathClassLoader(ExtensionContext extensionContext) {
|
||||
Class<?> testClass = extensionContext.getRequiredTestClass();
|
||||
ClassLoader classLoader = testClass.getClassLoader();
|
||||
return classLoader.getClass().getName().equals( ModifiableURLClassLoader.class.getName() );
|
||||
}
|
||||
|
||||
static class SelectorsToRun implements ExtensionContext.Store.CloseableResource {
|
||||
|
||||
private final Class<?> testClass;
|
||||
private final List<DiscoverySelector> discoverySelectors = new ArrayList<>();
|
||||
|
||||
SelectorsToRun(Class<?> testClass) {
|
||||
this.testClass = testClass;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() throws Throwable {
|
||||
runTestWithModifiedClassPath( testClass, discoverySelectors );
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,48 @@
|
||||
/*
|
||||
* Copyright MapStruct Authors.
|
||||
*
|
||||
* Licensed under the Apache License version 2.0, available at http://www.apache.org/licenses/LICENSE-2.0
|
||||
*/
|
||||
package org.mapstruct.ap.testutil.runner;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.Optional;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import org.junit.jupiter.api.extension.ExtensionContext;
|
||||
import org.junit.jupiter.api.extension.TestTemplateInvocationContext;
|
||||
import org.junit.jupiter.api.extension.TestTemplateInvocationContextProvider;
|
||||
import org.junit.platform.commons.support.AnnotationSupport;
|
||||
import org.mapstruct.ap.testutil.ProcessorTest;
|
||||
|
||||
/**
|
||||
* The provider of the processor tests based on the defined compilers.
|
||||
*
|
||||
* @author Filip Hrisafov
|
||||
*/
|
||||
public class ProcessorTestExtension implements TestTemplateInvocationContextProvider {
|
||||
|
||||
@Override
|
||||
public boolean supportsTestTemplate(ExtensionContext context) {
|
||||
return AnnotationSupport.isAnnotated( context.getTestMethod(), ProcessorTest.class );
|
||||
}
|
||||
|
||||
@Override
|
||||
public Stream<TestTemplateInvocationContext> provideTestTemplateInvocationContexts(ExtensionContext context) {
|
||||
Optional<Compiler> withSingleCompiler = AnnotationSupport.findAnnotation(
|
||||
context.getTestClass(),
|
||||
WithSingleCompiler.class
|
||||
).map( WithSingleCompiler::value );
|
||||
|
||||
if ( withSingleCompiler.isPresent() ) {
|
||||
return Stream.of( new ProcessorTestInvocationContext( withSingleCompiler.get() ) );
|
||||
}
|
||||
|
||||
Method testMethod = context.getRequiredTestMethod();
|
||||
ProcessorTest processorTest = AnnotationSupport.findAnnotation( testMethod, ProcessorTest.class )
|
||||
.orElseThrow( () -> new RuntimeException( "Failed to get CompilerTest on " + testMethod ) );
|
||||
|
||||
return Stream.of( processorTest.value() )
|
||||
.map( ProcessorTestInvocationContext::new );
|
||||
}
|
||||
}
|
@ -0,0 +1,60 @@
|
||||
/*
|
||||
* Copyright MapStruct Authors.
|
||||
*
|
||||
* Licensed under the Apache License version 2.0, available at http://www.apache.org/licenses/LICENSE-2.0
|
||||
*/
|
||||
package org.mapstruct.ap.testutil.runner;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.junit.jupiter.api.condition.JRE;
|
||||
import org.junit.jupiter.api.extension.Extension;
|
||||
import org.junit.jupiter.api.extension.TestTemplateInvocationContext;
|
||||
|
||||
/**
|
||||
* The template invocation processor responsible for providing the appropriate extensions for the different compilers.
|
||||
*
|
||||
* @author Filip Hrisafov
|
||||
*/
|
||||
public class ProcessorTestInvocationContext implements TestTemplateInvocationContext {
|
||||
|
||||
static final JRE CURRENT_VERSION;
|
||||
|
||||
static {
|
||||
JRE currentVersion = JRE.OTHER;
|
||||
for ( JRE jre : JRE.values() ) {
|
||||
if ( jre.isCurrentVersion() ) {
|
||||
currentVersion = jre;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
CURRENT_VERSION = currentVersion;
|
||||
}
|
||||
|
||||
protected Compiler compiler;
|
||||
|
||||
public ProcessorTestInvocationContext(Compiler compiler) {
|
||||
this.compiler = compiler;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDisplayName(int invocationIndex) {
|
||||
return "[" + compiler.name().toLowerCase() + "]";
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Extension> getAdditionalExtensions() {
|
||||
List<Extension> extensions = new ArrayList<>();
|
||||
extensions.add( new CompilerTestEnabledOnJreCondition( compiler ) );
|
||||
if ( compiler == Compiler.JDK ) {
|
||||
extensions.add( new JdkCompilingExtension() );
|
||||
}
|
||||
else if ( compiler == Compiler.ECLIPSE ) {
|
||||
extensions.add( new EclipseCompilingExtension() );
|
||||
}
|
||||
|
||||
return extensions;
|
||||
}
|
||||
}
|
@ -1,199 +0,0 @@
|
||||
/*
|
||||
* Copyright MapStruct Authors.
|
||||
*
|
||||
* Licensed under the Apache License version 2.0, available at http://www.apache.org/licenses/LICENSE-2.0
|
||||
*/
|
||||
package org.mapstruct.ap.testutil.runner;
|
||||
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.util.List;
|
||||
|
||||
import org.junit.runners.model.FrameworkField;
|
||||
import org.junit.runners.model.FrameworkMethod;
|
||||
import org.junit.runners.model.TestClass;
|
||||
|
||||
/**
|
||||
* A {@link TestClass} where the wrapped Class can be replaced
|
||||
*
|
||||
* @author Andreas Gudian
|
||||
*/
|
||||
class ReplacableTestClass extends TestClass {
|
||||
private TestClass delegate;
|
||||
|
||||
/**
|
||||
* @see TestClass#TestClass(Class)
|
||||
*/
|
||||
ReplacableTestClass(Class<?> clazz) {
|
||||
super( clazz );
|
||||
}
|
||||
|
||||
/**
|
||||
* @param clazz the new class
|
||||
*/
|
||||
void replaceClass(Class<?> clazz) {
|
||||
delegate = new TestClass( clazz );
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<FrameworkMethod> getAnnotatedMethods() {
|
||||
if ( null == delegate ) {
|
||||
return super.getAnnotatedMethods();
|
||||
}
|
||||
else {
|
||||
return delegate.getAnnotatedMethods();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<FrameworkMethod> getAnnotatedMethods(Class<? extends Annotation> annotationClass) {
|
||||
if ( null == delegate ) {
|
||||
return super.getAnnotatedMethods( annotationClass );
|
||||
}
|
||||
else {
|
||||
return delegate.getAnnotatedMethods( annotationClass );
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<FrameworkField> getAnnotatedFields() {
|
||||
if ( null == delegate ) {
|
||||
return super.getAnnotatedFields();
|
||||
}
|
||||
else {
|
||||
return delegate.getAnnotatedFields();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<FrameworkField> getAnnotatedFields(Class<? extends Annotation> annotationClass) {
|
||||
if ( null == delegate ) {
|
||||
return super.getAnnotatedFields( annotationClass );
|
||||
}
|
||||
else {
|
||||
return delegate.getAnnotatedFields( annotationClass );
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<?> getJavaClass() {
|
||||
if ( null == delegate ) {
|
||||
return super.getJavaClass();
|
||||
}
|
||||
else {
|
||||
return delegate.getJavaClass();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
if ( null == delegate ) {
|
||||
return super.getName();
|
||||
}
|
||||
else {
|
||||
return delegate.getName();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Constructor<?> getOnlyConstructor() {
|
||||
if ( null == delegate ) {
|
||||
return super.getOnlyConstructor();
|
||||
}
|
||||
else {
|
||||
return delegate.getOnlyConstructor();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Annotation[] getAnnotations() {
|
||||
if ( null == delegate ) {
|
||||
return super.getAnnotations();
|
||||
}
|
||||
else {
|
||||
return delegate.getAnnotations();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T extends Annotation> T getAnnotation(Class<T> annotationType) {
|
||||
if ( null == delegate ) {
|
||||
return super.getAnnotation( annotationType );
|
||||
}
|
||||
else {
|
||||
return delegate.getAnnotation( annotationType );
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> List<T> getAnnotatedFieldValues(Object test, Class<? extends Annotation> annotationClass,
|
||||
Class<T> valueClass) {
|
||||
if ( null == delegate ) {
|
||||
return super.getAnnotatedFieldValues( test, annotationClass, valueClass );
|
||||
}
|
||||
else {
|
||||
return delegate.getAnnotatedFieldValues( test, annotationClass, valueClass );
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> List<T> getAnnotatedMethodValues(Object test, Class<? extends Annotation> annotationClass,
|
||||
Class<T> valueClass) {
|
||||
if ( null == delegate ) {
|
||||
return super.getAnnotatedMethodValues( test, annotationClass, valueClass );
|
||||
}
|
||||
else {
|
||||
return delegate.getAnnotatedMethodValues( test, annotationClass, valueClass );
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
if ( null == delegate ) {
|
||||
return super.toString();
|
||||
}
|
||||
else {
|
||||
return delegate.toString();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isPublic() {
|
||||
if ( null == delegate ) {
|
||||
return super.isPublic();
|
||||
}
|
||||
else {
|
||||
return delegate.isPublic();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isANonStaticInnerClass() {
|
||||
if ( null == delegate ) {
|
||||
return super.isANonStaticInnerClass();
|
||||
}
|
||||
else {
|
||||
return delegate.isANonStaticInnerClass();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
if ( null == delegate ) {
|
||||
return super.hashCode();
|
||||
}
|
||||
else {
|
||||
return delegate.hashCode();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if ( null == delegate ) {
|
||||
return super.equals( obj );
|
||||
}
|
||||
else {
|
||||
return delegate.equals( obj );
|
||||
}
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user