From 9fc111f7df40b921d06c72725bceafcb3b8fafba Mon Sep 17 00:00:00 2001 From: Filip Hrisafov Date: Thu, 18 May 2017 00:31:45 +0200 Subject: [PATCH] #1129 Do not use equals and hashCode from TypeMirror --- .../ap/internal/model/EnumMappingMethod.java | 7 +- .../ap/internal/model/ValueMappingMethod.java | 7 +- .../ap/internal/model/common/Type.java | 2 +- .../ap/internal/model/source/BeanMapping.java | 7 +- .../model/source/IterableMapping.java | 7 +- .../ap/internal/model/source/MapMapping.java | 11 +- .../ap/internal/model/source/Mapping.java | 12 +- .../internal/model/source/MethodMatcher.java | 2 +- .../model/source/SelectionParameters.java | 34 +- .../processor/MethodRetrievalProcessor.java | 12 +- .../model/source/SelectionParametersTest.java | 389 ++++++++++++++++++ 11 files changed, 462 insertions(+), 28 deletions(-) create mode 100644 processor/src/test/java/org/mapstruct/ap/internal/model/source/SelectionParametersTest.java diff --git a/processor/src/main/java/org/mapstruct/ap/internal/model/EnumMappingMethod.java b/processor/src/main/java/org/mapstruct/ap/internal/model/EnumMappingMethod.java index 9dffd83af..eb401b56d 100644 --- a/processor/src/main/java/org/mapstruct/ap/internal/model/EnumMappingMethod.java +++ b/processor/src/main/java/org/mapstruct/ap/internal/model/EnumMappingMethod.java @@ -26,6 +26,7 @@ import java.util.List; import java.util.Set; import javax.lang.model.type.TypeMirror; +import javax.lang.model.util.Types; import org.mapstruct.ap.internal.model.common.Parameter; import org.mapstruct.ap.internal.model.source.EnumMapping; @@ -99,7 +100,7 @@ public class EnumMappingMethod extends MappingMethod { } } - SelectionParameters selectionParameters = getSelecionParameters( method ); + SelectionParameters selectionParameters = getSelecionParameters( method, ctx.getTypeUtils() ); Set existingVariables = new HashSet( method.getParameterNames() ); List beforeMappingMethods = @@ -110,13 +111,13 @@ public class EnumMappingMethod extends MappingMethod { return new EnumMappingMethod( method, enumMappings, beforeMappingMethods, afterMappingMethods ); } - private static SelectionParameters getSelecionParameters(SourceMethod method) { + private static SelectionParameters getSelecionParameters(SourceMethod method, Types typeUtils) { BeanMappingPrism beanMappingPrism = BeanMappingPrism.getInstanceOn( method.getExecutable() ); if ( beanMappingPrism != null ) { List qualifiers = beanMappingPrism.qualifiedBy(); List qualifyingNames = beanMappingPrism.qualifiedByName(); TypeMirror resultType = beanMappingPrism.resultType(); - return new SelectionParameters( qualifiers, qualifyingNames, resultType ); + return new SelectionParameters( qualifiers, qualifyingNames, resultType, typeUtils ); } return null; } diff --git a/processor/src/main/java/org/mapstruct/ap/internal/model/ValueMappingMethod.java b/processor/src/main/java/org/mapstruct/ap/internal/model/ValueMappingMethod.java index c7fc97010..2d3789419 100644 --- a/processor/src/main/java/org/mapstruct/ap/internal/model/ValueMappingMethod.java +++ b/processor/src/main/java/org/mapstruct/ap/internal/model/ValueMappingMethod.java @@ -26,6 +26,7 @@ import java.util.List; import java.util.Set; import javax.lang.model.type.TypeMirror; +import javax.lang.model.util.Types; import org.mapstruct.ap.internal.model.common.Parameter; import org.mapstruct.ap.internal.model.source.ForgedMethod; @@ -118,7 +119,7 @@ public class ValueMappingMethod extends MappingMethod { } // do before / after lifecycle mappings - SelectionParameters selectionParameters = getSelectionParameters( method ); + SelectionParameters selectionParameters = getSelectionParameters( method, ctx.getTypeUtils() ); Set existingVariables = new HashSet( method.getParameterNames() ); List beforeMappingMethods = LifecycleCallbackFactory.beforeMappingMethods( method, selectionParameters, ctx, existingVariables ); @@ -185,13 +186,13 @@ public class ValueMappingMethod extends MappingMethod { return mappings; } - private SelectionParameters getSelectionParameters(Method method) { + private SelectionParameters getSelectionParameters(Method method, Types typeUtils) { BeanMappingPrism beanMappingPrism = BeanMappingPrism.getInstanceOn( method.getExecutable() ); if ( beanMappingPrism != null ) { List qualifiers = beanMappingPrism.qualifiedBy(); List qualifyingNames = beanMappingPrism.qualifiedByName(); TypeMirror resultType = beanMappingPrism.resultType(); - return new SelectionParameters( qualifiers, qualifyingNames, resultType ); + return new SelectionParameters( qualifiers, qualifyingNames, resultType, typeUtils ); } return null; } diff --git a/processor/src/main/java/org/mapstruct/ap/internal/model/common/Type.java b/processor/src/main/java/org/mapstruct/ap/internal/model/common/Type.java index 46b884396..4a3350461 100644 --- a/processor/src/main/java/org/mapstruct/ap/internal/model/common/Type.java +++ b/processor/src/main/java/org/mapstruct/ap/internal/model/common/Type.java @@ -572,7 +572,7 @@ public class Type extends ModelElement implements Comparable { continue; } VariableElement arg = executable.getParameters().get( 0 ); - if ( arg.asType().equals( typeArg ) ) { + if ( typeUtils.isSameType( arg.asType(), typeArg ) ) { candidates.add( adder ); } } diff --git a/processor/src/main/java/org/mapstruct/ap/internal/model/source/BeanMapping.java b/processor/src/main/java/org/mapstruct/ap/internal/model/source/BeanMapping.java index dbe0eee27..dccc14f7d 100644 --- a/processor/src/main/java/org/mapstruct/ap/internal/model/source/BeanMapping.java +++ b/processor/src/main/java/org/mapstruct/ap/internal/model/source/BeanMapping.java @@ -20,6 +20,7 @@ package org.mapstruct.ap.internal.model.source; import javax.lang.model.element.ExecutableElement; import javax.lang.model.type.TypeKind; +import javax.lang.model.util.Types; import org.mapstruct.ap.internal.prism.BeanMappingPrism; import org.mapstruct.ap.internal.prism.NullValueMappingStrategyPrism; @@ -39,7 +40,7 @@ public class BeanMapping { private final ReportingPolicyPrism reportingPolicy; public static BeanMapping fromPrism(BeanMappingPrism beanMapping, ExecutableElement method, - FormattingMessager messager) { + FormattingMessager messager, Types typeUtils) { if ( beanMapping == null ) { return null; @@ -61,7 +62,9 @@ public class BeanMapping { SelectionParameters cmp = new SelectionParameters( beanMapping.qualifiedBy(), beanMapping.qualifiedByName(), - resultTypeIsDefined ? beanMapping.resultType() : null ); + resultTypeIsDefined ? beanMapping.resultType() : null, + typeUtils + ); //TODO Do we want to add the reporting policy to the BeanMapping as well? To give more granular support? return new BeanMapping( cmp, nullValueMappingStrategy, null ); diff --git a/processor/src/main/java/org/mapstruct/ap/internal/model/source/IterableMapping.java b/processor/src/main/java/org/mapstruct/ap/internal/model/source/IterableMapping.java index f7cdcdc2e..8e96790a2 100644 --- a/processor/src/main/java/org/mapstruct/ap/internal/model/source/IterableMapping.java +++ b/processor/src/main/java/org/mapstruct/ap/internal/model/source/IterableMapping.java @@ -21,6 +21,7 @@ package org.mapstruct.ap.internal.model.source; import javax.lang.model.element.AnnotationMirror; import javax.lang.model.element.ExecutableElement; import javax.lang.model.type.TypeKind; +import javax.lang.model.util.Types; import org.mapstruct.ap.internal.model.common.FormattingParameters; import org.mapstruct.ap.internal.prism.IterableMappingPrism; @@ -41,7 +42,7 @@ public class IterableMapping { private final NullValueMappingStrategyPrism nullValueMappingStrategy; public static IterableMapping fromPrism(IterableMappingPrism iterableMapping, ExecutableElement method, - FormattingMessager messager) { + FormattingMessager messager, Types typeUtils) { if ( iterableMapping == null ) { return null; } @@ -66,7 +67,9 @@ public class IterableMapping { SelectionParameters selection = new SelectionParameters( iterableMapping.qualifiedBy(), iterableMapping.qualifiedByName(), - elementTargetTypeIsDefined ? iterableMapping.elementTargetType() : null ); + elementTargetTypeIsDefined ? iterableMapping.elementTargetType() : null, + typeUtils + ); FormattingParameters formatting = new FormattingParameters( iterableMapping.dateFormat(), diff --git a/processor/src/main/java/org/mapstruct/ap/internal/model/source/MapMapping.java b/processor/src/main/java/org/mapstruct/ap/internal/model/source/MapMapping.java index ecfe67ff5..adeac692c 100644 --- a/processor/src/main/java/org/mapstruct/ap/internal/model/source/MapMapping.java +++ b/processor/src/main/java/org/mapstruct/ap/internal/model/source/MapMapping.java @@ -21,6 +21,7 @@ package org.mapstruct.ap.internal.model.source; import javax.lang.model.element.AnnotationMirror; import javax.lang.model.element.ExecutableElement; import javax.lang.model.type.TypeKind; +import javax.lang.model.util.Types; import org.mapstruct.ap.internal.model.common.FormattingParameters; import org.mapstruct.ap.internal.prism.MapMappingPrism; @@ -43,7 +44,7 @@ public class MapMapping { private final NullValueMappingStrategyPrism nullValueMappingStrategy; public static MapMapping fromPrism(MapMappingPrism mapMapping, ExecutableElement method, - FormattingMessager messager) { + FormattingMessager messager, Types typeUtils) { if ( mapMapping == null ) { return null; } @@ -74,12 +75,16 @@ public class MapMapping { SelectionParameters keySelection = new SelectionParameters( mapMapping.keyQualifiedBy(), mapMapping.keyQualifiedByName(), - keyTargetTypeIsDefined ? mapMapping.keyTargetType() : null); + keyTargetTypeIsDefined ? mapMapping.keyTargetType() : null, + typeUtils + ); SelectionParameters valueSelection = new SelectionParameters( mapMapping.valueQualifiedBy(), mapMapping.valueQualifiedByName(), - valueTargetTypeIsDefined ? mapMapping.valueTargetType() : null); + valueTargetTypeIsDefined ? mapMapping.valueTargetType() : null, + typeUtils + ); FormattingParameters keyFormatting = new FormattingParameters( mapMapping.keyDateFormat(), diff --git a/processor/src/main/java/org/mapstruct/ap/internal/model/source/Mapping.java b/processor/src/main/java/org/mapstruct/ap/internal/model/source/Mapping.java index 61d1358b5..e26d43126 100644 --- a/processor/src/main/java/org/mapstruct/ap/internal/model/source/Mapping.java +++ b/processor/src/main/java/org/mapstruct/ap/internal/model/source/Mapping.java @@ -32,6 +32,7 @@ import javax.lang.model.element.ExecutableElement; import javax.lang.model.type.DeclaredType; import javax.lang.model.type.TypeKind; import javax.lang.model.type.TypeMirror; +import javax.lang.model.util.Types; import org.mapstruct.ap.internal.model.common.FormattingParameters; import org.mapstruct.ap.internal.model.common.Parameter; @@ -72,12 +73,11 @@ public class Mapping { private TargetReference targetReference; public static Map> fromMappingsPrism(MappingsPrism mappingsAnnotation, - ExecutableElement method, - FormattingMessager messager) { + ExecutableElement method, FormattingMessager messager, Types typeUtils) { Map> mappings = new HashMap>(); for ( MappingPrism mappingPrism : mappingsAnnotation.value() ) { - Mapping mapping = fromMappingPrism( mappingPrism, method, messager ); + Mapping mapping = fromMappingPrism( mappingPrism, method, messager, typeUtils ); if ( mapping != null ) { List mappingsOfProperty = mappings.get( mappingPrism.target() ); if ( mappingsOfProperty == null ) { @@ -97,7 +97,7 @@ public class Mapping { } public static Mapping fromMappingPrism(MappingPrism mappingPrism, ExecutableElement element, - FormattingMessager messager) { + FormattingMessager messager, Types typeUtils) { if ( mappingPrism.target().isEmpty() ) { messager.printMessage( @@ -152,7 +152,9 @@ public class Mapping { SelectionParameters selectionParams = new SelectionParameters( mappingPrism.qualifiedBy(), mappingPrism.qualifiedByName(), - resultTypeIsDefined ? mappingPrism.resultType() : null); + resultTypeIsDefined ? mappingPrism.resultType() : null, + typeUtils + ); return new Mapping( source, diff --git a/processor/src/main/java/org/mapstruct/ap/internal/model/source/MethodMatcher.java b/processor/src/main/java/org/mapstruct/ap/internal/model/source/MethodMatcher.java index 5ae250ecf..91cc15106 100644 --- a/processor/src/main/java/org/mapstruct/ap/internal/model/source/MethodMatcher.java +++ b/processor/src/main/java/org/mapstruct/ap/internal/model/source/MethodMatcher.java @@ -395,7 +395,7 @@ public class MethodMatcher { */ private TypeParameterElement getTypeParamFromCandidate(TypeMirror t) { for ( TypeParameterElement candidateTypeParam : candidateMethod.getExecutable().getTypeParameters() ) { - if ( candidateTypeParam.asType().equals( t ) ) { + if ( typeUtils.isSameType( candidateTypeParam.asType(), t ) ) { return candidateTypeParam; } } diff --git a/processor/src/main/java/org/mapstruct/ap/internal/model/source/SelectionParameters.java b/processor/src/main/java/org/mapstruct/ap/internal/model/source/SelectionParameters.java index f14869903..9c3aa84c3 100644 --- a/processor/src/main/java/org/mapstruct/ap/internal/model/source/SelectionParameters.java +++ b/processor/src/main/java/org/mapstruct/ap/internal/model/source/SelectionParameters.java @@ -20,6 +20,7 @@ package org.mapstruct.ap.internal.model.source; import java.util.List; import javax.lang.model.type.TypeMirror; +import javax.lang.model.util.Types; /** * Holding parameters common to the selection process, common to IterableMapping, BeanMapping, PropertyMapping and @@ -32,11 +33,14 @@ public class SelectionParameters { private final List qualifiers; private final List qualifyingNames; private final TypeMirror resultType; + private final Types typeUtils; - public SelectionParameters(List qualifiers, List qualifyingNames, TypeMirror resultType ) { + public SelectionParameters(List qualifiers, List qualifyingNames, TypeMirror resultType, + Types typeUtils) { this.qualifiers = qualifiers; this.qualifyingNames = qualifyingNames; this.resultType = resultType; + this.typeUtils = typeUtils; } /** @@ -67,9 +71,8 @@ public class SelectionParameters { @Override public int hashCode() { int hash = 3; - hash = 97 * hash + (this.qualifiers != null ? this.qualifiers.hashCode() : 0); hash = 97 * hash + (this.qualifyingNames != null ? this.qualifyingNames.hashCode() : 0); - hash = 97 * hash + (this.resultType != null ? this.resultType.hashCode() : 0); + hash = 97 * hash + (this.resultType != null ? this.resultType.toString().hashCode() : 0); return hash; } @@ -105,4 +108,29 @@ public class SelectionParameters { return object1.equals( object2 ); } } + + private boolean equals(List mirrors1, List mirrors2) { + if ( mirrors1 == null ) { + return (mirrors2 == null); + } + else if ( mirrors2 == null || mirrors1.size() != mirrors2.size() ) { + return false; + } + + for ( int i = 0; i < mirrors1.size(); i++ ) { + if ( !equals( mirrors1.get( i ), mirrors2.get( i ) ) ) { + return false; + } + } + return true; + } + + private boolean equals(TypeMirror mirror1, TypeMirror mirror2) { + if ( mirror1 == null ) { + return (mirror2 == null); + } + else { + return mirror2 != null && typeUtils.isSameType( mirror1, mirror2 ); + } + } } diff --git a/processor/src/main/java/org/mapstruct/ap/internal/processor/MethodRetrievalProcessor.java b/processor/src/main/java/org/mapstruct/ap/internal/processor/MethodRetrievalProcessor.java index 59772cd46..d434aa41b 100644 --- a/processor/src/main/java/org/mapstruct/ap/internal/processor/MethodRetrievalProcessor.java +++ b/processor/src/main/java/org/mapstruct/ap/internal/processor/MethodRetrievalProcessor.java @@ -254,11 +254,13 @@ public class MethodRetrievalProcessor implements ModelElementProcessor() ); } - Mapping mapping = Mapping.fromMappingPrism( mappingAnnotation, method, messager ); + Mapping mapping = Mapping.fromMappingPrism( mappingAnnotation, method, messager, typeUtils ); if ( mapping != null ) { mappings.get( mappingAnnotation.target() ).add( mapping ); } } if ( mappingsAnnotation != null ) { - mappings.putAll( Mapping.fromMappingsPrism( mappingsAnnotation, method, messager ) ); + mappings.putAll( Mapping.fromMappingsPrism( mappingsAnnotation, method, messager, typeUtils ) ); } return mappings; diff --git a/processor/src/test/java/org/mapstruct/ap/internal/model/source/SelectionParametersTest.java b/processor/src/test/java/org/mapstruct/ap/internal/model/source/SelectionParametersTest.java new file mode 100644 index 000000000..b5ff2a7f4 --- /dev/null +++ b/processor/src/test/java/org/mapstruct/ap/internal/model/source/SelectionParametersTest.java @@ -0,0 +1,389 @@ +/** + * Copyright 2012-2017 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.internal.model.source; + +import java.lang.annotation.Annotation; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import javax.lang.model.element.AnnotationMirror; +import javax.lang.model.element.Element; +import javax.lang.model.element.TypeElement; +import javax.lang.model.type.ArrayType; +import javax.lang.model.type.DeclaredType; +import javax.lang.model.type.ExecutableType; +import javax.lang.model.type.NoType; +import javax.lang.model.type.NullType; +import javax.lang.model.type.PrimitiveType; +import javax.lang.model.type.TypeKind; +import javax.lang.model.type.TypeMirror; +import javax.lang.model.type.TypeVisitor; +import javax.lang.model.type.WildcardType; +import javax.lang.model.util.Types; + +import org.junit.Test; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * @author Filip Hrisafov + */ +public class SelectionParametersTest { + + private static class TestTypeMirror implements TypeMirror { + + private final String name; + + private TestTypeMirror(String name) { + this.name = name; + } + + @Override + public TypeKind getKind() { + return null; + } + + @Override + public R accept(TypeVisitor v, P p) { + return null; + } + + @Override + public List getAnnotationMirrors() { + return null; + } + + @Override + public A getAnnotation(Class annotationType) { + return null; + } + + @Override + public A[] getAnnotationsByType(Class annotationType) { + return null; + } + + @Override + public String toString() { + return name; + } + } + + private final Types typeUtils = new Types() { + @Override + public Element asElement(TypeMirror t) { + throw new UnsupportedOperationException( "asElement is not supported" ); + } + + @Override + public boolean isSameType(TypeMirror t1, TypeMirror t2) { + return t1.toString().equals( t2.toString() ); + } + + @Override + public boolean isSubtype(TypeMirror t1, TypeMirror t2) { + throw new UnsupportedOperationException( "isSubType is not supported" ); + } + + @Override + public boolean isAssignable(TypeMirror t1, TypeMirror t2) { + throw new UnsupportedOperationException( "isAssignable is not supported" ); + } + + @Override + public boolean contains(TypeMirror t1, TypeMirror t2) { + throw new UnsupportedOperationException( "contains is not supported" ); + } + + @Override + public boolean isSubsignature(ExecutableType m1, ExecutableType m2) { + throw new UnsupportedOperationException( "isSubSignature is not supported" ); + } + + @Override + public List directSupertypes(TypeMirror t) { + throw new UnsupportedOperationException( "directSupertypes is not supported" ); + } + + @Override + public TypeMirror erasure(TypeMirror t) { + throw new UnsupportedOperationException( "erasure is not supported" ); + } + + @Override + public TypeElement boxedClass(PrimitiveType p) { + throw new UnsupportedOperationException( "boxedClass is not supported" ); + } + + @Override + public PrimitiveType unboxedType(TypeMirror t) { + throw new UnsupportedOperationException( "unboxedType is not supported" ); + } + + @Override + public TypeMirror capture(TypeMirror t) { + throw new UnsupportedOperationException( "capture is not supported" ); + } + + @Override + public PrimitiveType getPrimitiveType(TypeKind kind) { + throw new UnsupportedOperationException( "getPrimitiveType is not supported" ); + } + + @Override + public NullType getNullType() { + throw new UnsupportedOperationException( "nullType is not supported" ); + } + + @Override + public NoType getNoType(TypeKind kind) { + throw new UnsupportedOperationException( "noType is not supported" ); + } + + @Override + public ArrayType getArrayType(TypeMirror componentType) { + throw new UnsupportedOperationException( "getArrayType is not supported" ); + } + + @Override + public WildcardType getWildcardType(TypeMirror extendsBound, TypeMirror superBound) { + throw new UnsupportedOperationException( "getWildCardType is not supported" ); + } + + @Override + public DeclaredType getDeclaredType(TypeElement typeElem, TypeMirror... typeArgs) { + throw new UnsupportedOperationException( "getDeclaredType is not supported" ); + } + + @Override + public DeclaredType getDeclaredType(DeclaredType containing, TypeElement typeElem, TypeMirror... typeArgs) { + throw new UnsupportedOperationException( "getDeclaredType is not supported" ); + } + + @Override + public TypeMirror asMemberOf(DeclaredType containing, Element element) { + throw new UnsupportedOperationException( "asMemberOf is not supported" ); + } + }; + + @Test + public void testGetters() { + List qualifyingNames = Arrays.asList( "language", "german" ); + TypeMirror resultType = new TestTypeMirror( "resultType" ); + List qualifiers = new ArrayList(); + qualifiers.add( new TestTypeMirror( "org.mapstruct.test.SomeType" ) ); + qualifiers.add( new TestTypeMirror( "org.mapstruct.test.SomeOtherType" ) ); + SelectionParameters params = new SelectionParameters( qualifiers, qualifyingNames, resultType, typeUtils ); + + assertThat( params.getResultType() ).isSameAs( resultType ); + assertThat( params.getQualifiers() ).hasSameElementsAs( qualifiers ); + assertThat( params.getQualifyingNames() ).hasSameElementsAs( qualifyingNames ); + } + + @Test + public void testHashCode() { + List qualifyingNames = Arrays.asList( "language", "german" ); + TypeMirror resultType = new TestTypeMirror( "resultType" ); + SelectionParameters params = new SelectionParameters( null, qualifyingNames, resultType, null ); + + int expectedHash = 3 * 97 + qualifyingNames.hashCode(); + expectedHash = 97 * expectedHash + "resultType".hashCode(); + assertThat( params.hashCode() ).as( "Expected HashCode" ).isEqualTo( expectedHash ); + } + + @Test + public void testHashCodeWithAllNulls() { + SelectionParameters params = new SelectionParameters( null, null, null, null ); + + assertThat( params.hashCode() ).as( "All nulls hashCode" ).isEqualTo( 3 * 97 * 97 ); + } + + @Test + public void testHashCodeWithNullQualifyingNames() { + TypeMirror resultType = new TestTypeMirror( "someType" ); + SelectionParameters params = new SelectionParameters( null, null, resultType, null ); + + assertThat( params.hashCode() ) + .as( "QualifyingNames null hashCode" ) + .isEqualTo( 3 * 97 * 97 + "someType".hashCode() ); + } + + @Test + public void testHashCodeWithNullResultType() { + List qualifyingNames = Collections.singletonList( "mapstruct" ); + SelectionParameters params = new SelectionParameters( null, qualifyingNames, null, null ); + + assertThat( params.hashCode() ) + .as( "ResultType nulls hashCode" ) + .isEqualTo( ( 3 * 97 + qualifyingNames.hashCode() ) * 97 ); + } + + @Test + public void testEqualsSameInstance() { + List qualifyingNames = Arrays.asList( "language", "german" ); + TypeMirror resultType = new TestTypeMirror( "resultType" ); + List qualifiers = new ArrayList(); + qualifiers.add( new TestTypeMirror( "org.mapstruct.test.SomeType" ) ); + qualifiers.add( new TestTypeMirror( "org.mapstruct.test.SomeOtherType" ) ); + SelectionParameters params = new SelectionParameters( qualifiers, qualifyingNames, resultType, typeUtils ); + + assertThat( params.equals( params ) ).as( "Self equals" ).isTrue(); + } + + @Test + public void testEqualsWitNull() { + List qualifyingNames = Arrays.asList( "language", "german" ); + TypeMirror resultType = new TestTypeMirror( "resultType" ); + List qualifiers = new ArrayList(); + qualifiers.add( new TestTypeMirror( "org.mapstruct.test.SomeType" ) ); + qualifiers.add( new TestTypeMirror( "org.mapstruct.test.SomeOtherType" ) ); + SelectionParameters params = new SelectionParameters( qualifiers, qualifyingNames, resultType, typeUtils ); + + assertThat( params.equals( null ) ).as( "Equals with null" ).isFalse(); + } + + @Test + public void testEqualsQualifiersOneNull() { + List qualifyingNames = Arrays.asList( "language", "german" ); + TypeMirror resultType = new TestTypeMirror( "resultType" ); + List qualifiers = new ArrayList(); + qualifiers.add( new TestTypeMirror( "org.mapstruct.test.SomeType" ) ); + qualifiers.add( new TestTypeMirror( "org.mapstruct.test.SomeOtherType" ) ); + SelectionParameters params = new SelectionParameters( qualifiers, qualifyingNames, resultType, typeUtils ); + SelectionParameters params2 = new SelectionParameters( null, qualifyingNames, resultType, typeUtils ); + + assertThat( params.equals( params2 ) ).as( "Second null qualifiers" ).isFalse(); + assertThat( params2.equals( params ) ).as( "First null qualifiers" ).isFalse(); + } + + @Test + public void testEqualsQualifiersInDifferentOrder() { + List qualifyingNames = Arrays.asList( "language", "german" ); + TypeMirror resultType = new TestTypeMirror( "resultType" ); + List qualifiers = new ArrayList(); + qualifiers.add( new TestTypeMirror( "org.mapstruct.test.SomeType" ) ); + qualifiers.add( new TestTypeMirror( "org.mapstruct.test.SomeOtherType" ) ); + SelectionParameters params = new SelectionParameters( qualifiers, qualifyingNames, resultType, typeUtils ); + + List qualifiers2 = new ArrayList(); + qualifiers2.add( new TestTypeMirror( "org.mapstruct.test.SomeOtherType" ) ); + qualifiers2.add( new TestTypeMirror( "org.mapstruct.test.SomeType" ) ); + SelectionParameters params2 = new SelectionParameters( qualifiers2, qualifyingNames, resultType, typeUtils ); + + assertThat( params.equals( params2 ) ).as( "Different order for qualifiers" ).isFalse(); + assertThat( params2.equals( params ) ).as( "Different order for qualifiers" ).isFalse(); + } + + @Test + public void testEqualsQualifyingNamesOneNull() { + List qualifyingNames = Arrays.asList( "language", "german" ); + TypeMirror resultType = new TestTypeMirror( "resultType" ); + List qualifiers = new ArrayList(); + qualifiers.add( new TestTypeMirror( "org.mapstruct.test.SomeType" ) ); + qualifiers.add( new TestTypeMirror( "org.mapstruct.test.SomeOtherType" ) ); + SelectionParameters params = new SelectionParameters( qualifiers, qualifyingNames, resultType, typeUtils ); + + List qualifiers2 = new ArrayList(); + qualifiers2.add( new TestTypeMirror( "org.mapstruct.test.SomeType" ) ); + qualifiers2.add( new TestTypeMirror( "org.mapstruct.test.SomeOtherType" ) ); + SelectionParameters params2 = new SelectionParameters( qualifiers2, null, resultType, typeUtils ); + + assertThat( params.equals( params2 ) ).as( "Second null qualifyingNames" ).isFalse(); + assertThat( params2.equals( params ) ).as( "First null qualifyingNames" ).isFalse(); + } + + @Test + public void testEqualsQualifyingNamesInDifferentOrder() { + List qualifyingNames = Arrays.asList( "language", "german" ); + TypeMirror resultType = new TestTypeMirror( "resultType" ); + List qualifiers = new ArrayList(); + qualifiers.add( new TestTypeMirror( "org.mapstruct.test.SomeType" ) ); + qualifiers.add( new TestTypeMirror( "org.mapstruct.test.SomeOtherType" ) ); + SelectionParameters params = new SelectionParameters( qualifiers, qualifyingNames, resultType, typeUtils ); + + List qualifyingNames2 = Arrays.asList( "german", "language" ); + List qualifiers2 = new ArrayList(); + qualifiers2.add( new TestTypeMirror( "org.mapstruct.test.SomeOtherType" ) ); + qualifiers2.add( new TestTypeMirror( "org.mapstruct.test.SomeType" ) ); + SelectionParameters params2 = new SelectionParameters( qualifiers2, qualifyingNames2, resultType, typeUtils ); + + assertThat( params.equals( params2 ) ).as( "Different order for qualifyingNames" ).isFalse(); + assertThat( params2.equals( params ) ).as( "Different order for qualifyingNames" ).isFalse(); + } + + @Test + public void testEqualsResultTypeOneNull() { + List qualifyingNames = Arrays.asList( "language", "german" ); + TypeMirror resultType = new TestTypeMirror( "resultType" ); + List qualifiers = new ArrayList(); + qualifiers.add( new TestTypeMirror( "org.mapstruct.test.SomeType" ) ); + qualifiers.add( new TestTypeMirror( "org.mapstruct.test.SomeOtherType" ) ); + SelectionParameters params = new SelectionParameters( qualifiers, qualifyingNames, resultType, typeUtils ); + + List qualifyingNames2 = Arrays.asList( "language", "german" ); + List qualifiers2 = new ArrayList(); + qualifiers2.add( new TestTypeMirror( "org.mapstruct.test.SomeType" ) ); + qualifiers2.add( new TestTypeMirror( "org.mapstruct.test.SomeOtherType" ) ); + SelectionParameters params2 = new SelectionParameters( qualifiers2, qualifyingNames2, null, typeUtils ); + + assertThat( params.equals( params2 ) ).as( "Second null resultType" ).isFalse(); + assertThat( params2.equals( params ) ).as( "First null resultType" ).isFalse(); + } + + @Test + public void testAllEqual() { + List qualifyingNames = Arrays.asList( "language", "german" ); + TypeMirror resultType = new TestTypeMirror( "resultType" ); + List qualifiers = new ArrayList(); + qualifiers.add( new TestTypeMirror( "org.mapstruct.test.SomeType" ) ); + qualifiers.add( new TestTypeMirror( "org.mapstruct.test.SomeOtherType" ) ); + SelectionParameters params = new SelectionParameters( qualifiers, qualifyingNames, resultType, typeUtils ); + + List qualifyingNames2 = Arrays.asList( "language", "german" ); + TypeMirror resultType2 = new TestTypeMirror( "resultType" ); + List qualifiers2 = new ArrayList(); + qualifiers2.add( new TestTypeMirror( "org.mapstruct.test.SomeType" ) ); + qualifiers2.add( new TestTypeMirror( "org.mapstruct.test.SomeOtherType" ) ); + SelectionParameters params2 = new SelectionParameters( qualifiers2, qualifyingNames2, resultType2, typeUtils ); + + assertThat( params.equals( params2 ) ).as( "All equal" ).isTrue(); + assertThat( params2.equals( params ) ).as( "All equal" ).isTrue(); + } + + @Test + public void testDifferentResultTypes() { + List qualifyingNames = Arrays.asList( "language", "german" ); + TypeMirror resultType = new TestTypeMirror( "resultType" ); + List qualifiers = new ArrayList(); + qualifiers.add( new TestTypeMirror( "org.mapstruct.test.SomeType" ) ); + qualifiers.add( new TestTypeMirror( "org.mapstruct.test.SomeOtherType" ) ); + SelectionParameters params = new SelectionParameters( qualifiers, qualifyingNames, resultType, typeUtils ); + + List qualifyingNames2 = Arrays.asList( "language", "german" ); + TypeMirror resultType2 = new TestTypeMirror( "otherResultType" ); + List qualifiers2 = new ArrayList(); + qualifiers2.add( new TestTypeMirror( "org.mapstruct.test.SomeType" ) ); + qualifiers2.add( new TestTypeMirror( "org.mapstruct.test.SomeOtherType" ) ); + SelectionParameters params2 = new SelectionParameters( qualifiers2, qualifyingNames2, resultType2, typeUtils ); + + assertThat( params.equals( params2 ) ).as( "Different resultType" ).isFalse(); + assertThat( params2.equals( params ) ).as( "Different resultType" ).isFalse(); + } +}