mirror of
https://github.com/mapstruct/mapstruct.git
synced 2025-07-12 00:00:08 +08:00
#338 update to JUnit 4.12 and fix classloader leaks among the tests.
This commit is contained in:
parent
668f66eb73
commit
6201e6d61d
@ -119,7 +119,7 @@
|
|||||||
<dependency>
|
<dependency>
|
||||||
<groupId>junit</groupId>
|
<groupId>junit</groupId>
|
||||||
<artifactId>junit</artifactId>
|
<artifactId>junit</artifactId>
|
||||||
<version>4.11</version>
|
<version>4.12</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<!-- CDI, Weld, Arquillian -->
|
<!-- CDI, Weld, Arquillian -->
|
||||||
|
@ -23,6 +23,7 @@ import java.net.URL;
|
|||||||
import org.junit.runners.BlockJUnit4ClassRunner;
|
import org.junit.runners.BlockJUnit4ClassRunner;
|
||||||
import org.junit.runners.model.FrameworkMethod;
|
import org.junit.runners.model.FrameworkMethod;
|
||||||
import org.junit.runners.model.Statement;
|
import org.junit.runners.model.Statement;
|
||||||
|
import org.junit.runners.model.TestClass;
|
||||||
import org.mapstruct.ap.testutil.WithClasses;
|
import org.mapstruct.ap.testutil.WithClasses;
|
||||||
import org.mapstruct.ap.testutil.compilation.annotation.ExpectedCompilationOutcome;
|
import org.mapstruct.ap.testutil.compilation.annotation.ExpectedCompilationOutcome;
|
||||||
import org.mapstruct.ap.testutil.compilation.annotation.ProcessorOption;
|
import org.mapstruct.ap.testutil.compilation.annotation.ProcessorOption;
|
||||||
@ -45,6 +46,9 @@ import org.mapstruct.ap.testutil.compilation.annotation.ProcessorOption;
|
|||||||
*/
|
*/
|
||||||
public class AnnotationProcessorTestRunner extends BlockJUnit4ClassRunner {
|
public class AnnotationProcessorTestRunner extends BlockJUnit4ClassRunner {
|
||||||
static final ModifiableURLClassLoader TEST_CLASS_LOADER = new ModifiableURLClassLoader();
|
static final ModifiableURLClassLoader TEST_CLASS_LOADER = new ModifiableURLClassLoader();
|
||||||
|
private final Class<?> klass;
|
||||||
|
private Class<?> klassToUse;
|
||||||
|
private ReplacableTestClass replacableTestClass;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param klass the test class
|
* @param klass the test class
|
||||||
@ -52,7 +56,8 @@ public class AnnotationProcessorTestRunner extends BlockJUnit4ClassRunner {
|
|||||||
* @throws Exception see {@link BlockJUnit4ClassRunner#BlockJUnit4ClassRunner(Class)}
|
* @throws Exception see {@link BlockJUnit4ClassRunner#BlockJUnit4ClassRunner(Class)}
|
||||||
*/
|
*/
|
||||||
public AnnotationProcessorTestRunner(Class<?> klass) throws Exception {
|
public AnnotationProcessorTestRunner(Class<?> klass) throws Exception {
|
||||||
super( replaceClassLoaderAndClass( klass ) );
|
super( klass );
|
||||||
|
this.klass = klass;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -63,17 +68,10 @@ public class AnnotationProcessorTestRunner extends BlockJUnit4ClassRunner {
|
|||||||
* @return the class loaded with the test class loader
|
* @return the class loaded with the test class loader
|
||||||
*/
|
*/
|
||||||
private static Class<?> replaceClassLoaderAndClass(Class<?> klass) {
|
private static Class<?> replaceClassLoaderAndClass(Class<?> klass) {
|
||||||
String classFileName = klass.getName().replace( ".", "/" ) + ".class";
|
replaceContextClassLoader( klass );
|
||||||
URL classResource = klass.getClassLoader().getResource( classFileName );
|
|
||||||
String fullyQualifiedUrl = classResource.toExternalForm();
|
|
||||||
String basePath = fullyQualifiedUrl.substring( 0, fullyQualifiedUrl.length() - classFileName.length() );
|
|
||||||
|
|
||||||
TEST_CLASS_LOADER.addURL( basePath );
|
|
||||||
|
|
||||||
Thread.currentThread().setContextClassLoader( TEST_CLASS_LOADER );
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
return TEST_CLASS_LOADER.loadClass( klass.getName() );
|
return Thread.currentThread().getContextClassLoader().loadClass( klass.getName() );
|
||||||
}
|
}
|
||||||
catch ( ClassNotFoundException e ) {
|
catch ( ClassNotFoundException e ) {
|
||||||
throw new RuntimeException( e );
|
throw new RuntimeException( e );
|
||||||
@ -81,10 +79,48 @@ public class AnnotationProcessorTestRunner extends BlockJUnit4ClassRunner {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static void replaceContextClassLoader(Class<?> klass) {
|
||||||
|
String classFileName = klass.getName().replace( ".", "/" ) + ".class";
|
||||||
|
URL classResource = klass.getClassLoader().getResource( classFileName );
|
||||||
|
String fullyQualifiedUrl = classResource.toExternalForm();
|
||||||
|
String basePath = fullyQualifiedUrl.substring( 0, fullyQualifiedUrl.length() - classFileName.length() );
|
||||||
|
|
||||||
|
ModifiableURLClassLoader testClassLoader = new ModifiableURLClassLoader();
|
||||||
|
testClassLoader.addURL( basePath );
|
||||||
|
|
||||||
|
Thread.currentThread().setContextClassLoader( testClassLoader );
|
||||||
|
}
|
||||||
|
|
||||||
|
@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
|
@Override
|
||||||
protected Statement methodBlock(FrameworkMethod method) {
|
protected Statement methodBlock(FrameworkMethod method) {
|
||||||
Statement statement = super.methodBlock( method );
|
CompilingStatement statement = new CompilingStatement( method );
|
||||||
statement = new CompilingStatement( statement, method, TEST_CLASS_LOADER );
|
if ( statement.needsRecompilation() ) {
|
||||||
|
klassToUse = replaceClassLoaderAndClass( klass );
|
||||||
|
|
||||||
|
replacableTestClass.replaceClass( klassToUse );
|
||||||
|
}
|
||||||
|
|
||||||
|
method = replaceFrameworkMethod( method );
|
||||||
|
|
||||||
|
Statement next = super.methodBlock( method );
|
||||||
|
|
||||||
|
statement.setNextStatement( next );
|
||||||
|
|
||||||
return statement;
|
return statement;
|
||||||
}
|
}
|
||||||
|
@ -30,6 +30,7 @@ import java.util.Iterator;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.concurrent.atomic.AtomicInteger;
|
import java.util.concurrent.atomic.AtomicInteger;
|
||||||
|
|
||||||
import javax.tools.DiagnosticCollector;
|
import javax.tools.DiagnosticCollector;
|
||||||
import javax.tools.JavaCompiler;
|
import javax.tools.JavaCompiler;
|
||||||
import javax.tools.JavaCompiler.CompilationTask;
|
import javax.tools.JavaCompiler.CompilationTask;
|
||||||
@ -94,20 +95,24 @@ class CompilingStatement extends Statement {
|
|||||||
"joda-time.jar"
|
"joda-time.jar"
|
||||||
);
|
);
|
||||||
|
|
||||||
private final Statement next;
|
private Statement next;
|
||||||
private final FrameworkMethod method;
|
private final FrameworkMethod method;
|
||||||
private final ModifiableURLClassLoader classloader;
|
|
||||||
|
|
||||||
private JavaCompiler compiler;
|
private JavaCompiler compiler;
|
||||||
private String sourceDir;
|
private String sourceDir;
|
||||||
private String classOutputDir;
|
private String classOutputDir;
|
||||||
private String sourceOutputDir;
|
private String sourceOutputDir;
|
||||||
private List<File> classPath;
|
private List<File> classPath;
|
||||||
|
private CompilationRequest compilationRequest;
|
||||||
|
|
||||||
public CompilingStatement(Statement next, FrameworkMethod method, ModifiableURLClassLoader classloader) {
|
public CompilingStatement(FrameworkMethod method) {
|
||||||
this.next = next;
|
|
||||||
this.method = method;
|
this.method = method;
|
||||||
this.classloader = classloader;
|
|
||||||
|
this.compilationRequest = new CompilationRequest( getTestClasses(), getProcessorOptions() );
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setNextStatement(Statement next) {
|
||||||
|
this.next = next;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -141,11 +146,11 @@ class CompilingStatement extends Statement {
|
|||||||
|
|
||||||
createOutputDirs();
|
createOutputDirs();
|
||||||
|
|
||||||
classloader.addOutputDir( classOutputDir );
|
( (ModifiableURLClassLoader) Thread.currentThread().getContextClassLoader() ).addOutputDir( classOutputDir );
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void generateMapperImplementation() throws Exception {
|
protected void generateMapperImplementation() throws Exception {
|
||||||
CompilationResultHolder compilationResult = compile( getTestClasses(), getProcessorOptions() );
|
CompilationResultHolder compilationResult = compile();
|
||||||
|
|
||||||
CompilationOutcomeDescriptor actualResult =
|
CompilationOutcomeDescriptor actualResult =
|
||||||
CompilationOutcomeDescriptor.forResult(
|
CompilationOutcomeDescriptor.forResult(
|
||||||
@ -285,12 +290,11 @@ class CompilingStatement extends Statement {
|
|||||||
return sourceFiles;
|
return sourceFiles;
|
||||||
}
|
}
|
||||||
|
|
||||||
private CompilationResultHolder compile(Set<Class<?>> sourceClasses, List<String> processorOptions)
|
private CompilationResultHolder compile()
|
||||||
throws Exception {
|
throws Exception {
|
||||||
CompilationRequest request = new CompilationRequest( sourceClasses, processorOptions );
|
|
||||||
|
|
||||||
CompilationCache cache = COMPILATION_CACHE.get();
|
CompilationCache cache = COMPILATION_CACHE.get();
|
||||||
if ( request.equals( cache.lastRequest ) ) {
|
if ( !needsRecompilation() ) {
|
||||||
return cache.lastResult;
|
return cache.lastResult;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -301,7 +305,7 @@ class CompilingStatement extends Statement {
|
|||||||
StandardJavaFileManager fileManager = compiler.getStandardFileManager( null, null, null );
|
StandardJavaFileManager fileManager = compiler.getStandardFileManager( null, null, null );
|
||||||
|
|
||||||
Iterable<? extends JavaFileObject> compilationUnits =
|
Iterable<? extends JavaFileObject> compilationUnits =
|
||||||
fileManager.getJavaFileObjectsFromFiles( getSourceFiles( sourceClasses ) );
|
fileManager.getJavaFileObjectsFromFiles( getSourceFiles( compilationRequest.sourceClasses ) );
|
||||||
|
|
||||||
try {
|
try {
|
||||||
fileManager.setLocation( StandardLocation.CLASS_PATH, classPath );
|
fileManager.setLocation( StandardLocation.CLASS_PATH, classPath );
|
||||||
@ -313,16 +317,27 @@ class CompilingStatement extends Statement {
|
|||||||
}
|
}
|
||||||
|
|
||||||
CompilationTask task =
|
CompilationTask task =
|
||||||
compiler.getTask( null, fileManager, diagnostics, processorOptions, null, compilationUnits );
|
compiler.getTask(
|
||||||
|
null,
|
||||||
|
fileManager,
|
||||||
|
diagnostics,
|
||||||
|
compilationRequest.processorOptions,
|
||||||
|
null,
|
||||||
|
compilationUnits );
|
||||||
|
|
||||||
task.setProcessors( Arrays.asList( new MappingProcessor() ) );
|
task.setProcessors( Arrays.asList( new MappingProcessor() ) );
|
||||||
|
|
||||||
CompilationResultHolder resultHolder = new CompilationResultHolder( diagnostics, task.call() );
|
CompilationResultHolder resultHolder = new CompilationResultHolder( diagnostics, task.call() );
|
||||||
|
|
||||||
cache.lastRequest = request;
|
cache.lastRequest = compilationRequest;
|
||||||
cache.lastResult = resultHolder;
|
cache.lastResult = resultHolder;
|
||||||
return resultHolder;
|
return resultHolder;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean needsRecompilation() {
|
||||||
|
return !compilationRequest.equals( COMPILATION_CACHE.get().lastRequest );
|
||||||
|
}
|
||||||
|
|
||||||
private String getBasePath() {
|
private String getBasePath() {
|
||||||
try {
|
try {
|
||||||
return new File( "." ).getCanonicalPath();
|
return new File( "." ).getCanonicalPath();
|
||||||
|
@ -36,6 +36,9 @@ public class ModifiableURLClassLoader extends URLClassLoader {
|
|||||||
|
|
||||||
private static final String ORG_MAPSTRUCT_AP_TEST = "org.mapstruct.ap.test.";
|
private static final String ORG_MAPSTRUCT_AP_TEST = "org.mapstruct.ap.test.";
|
||||||
|
|
||||||
|
private static final FilteringParentClassLoader PARENT_CLASS_LOADER = new FilteringParentClassLoader(
|
||||||
|
ORG_MAPSTRUCT_AP_TEST );
|
||||||
|
|
||||||
static {
|
static {
|
||||||
tryRegisterAsParallelCapable();
|
tryRegisterAsParallelCapable();
|
||||||
}
|
}
|
||||||
@ -43,7 +46,7 @@ public class ModifiableURLClassLoader extends URLClassLoader {
|
|||||||
private final ConcurrentMap<URL, URL> addedURLs = new ConcurrentHashMap<URL, URL>();
|
private final ConcurrentMap<URL, URL> addedURLs = new ConcurrentHashMap<URL, URL>();
|
||||||
|
|
||||||
public ModifiableURLClassLoader() {
|
public ModifiableURLClassLoader() {
|
||||||
super( new URL[] { }, new FilteringParentClassLoader() );
|
super( new URL[] { }, PARENT_CLASS_LOADER );
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -96,9 +99,15 @@ public class ModifiableURLClassLoader extends URLClassLoader {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private static final class FilteringParentClassLoader extends ClassLoader {
|
private static final class FilteringParentClassLoader extends ClassLoader {
|
||||||
|
private String excludedPackage;
|
||||||
|
|
||||||
|
public FilteringParentClassLoader(String excludedPackage) {
|
||||||
|
this.excludedPackage = excludedPackage;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException {
|
protected Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException {
|
||||||
if ( name.startsWith( ORG_MAPSTRUCT_AP_TEST ) ) {
|
if ( name.startsWith( excludedPackage ) ) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -0,0 +1,212 @@
|
|||||||
|
/**
|
||||||
|
* Copyright 2012-2014 Gunnar Morling (http://www.gunnarmorling.de/)
|
||||||
|
* and/or other contributors as indicated by the @authors tag. See the
|
||||||
|
* copyright.txt file in the distribution for a full listing of all
|
||||||
|
* contributors.
|
||||||
|
*
|
||||||
|
* 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 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