mirror of
https://github.com/mapstruct/mapstruct.git
synced 2025-07-12 00:00:08 +08:00
#341 method annotated with qualifier should not qualify for mappings without qualifiedBy
This commit is contained in:
parent
fd08330b94
commit
e2dbd6ae1d
@ -36,6 +36,19 @@ import org.mapstruct.ap.prism.QualifierPrism;
|
|||||||
/**
|
/**
|
||||||
* This selector selects a best match based on qualifiers name.
|
* This selector selects a best match based on qualifiers name.
|
||||||
*
|
*
|
||||||
|
* <p>
|
||||||
|
* A method is said to be marked with a qualifier annotation if the class in which it resides is annotated with a
|
||||||
|
* qualifier annotation or if the method itself is annotated with a qualifier annotation or both.
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* Rules:
|
||||||
|
* <ol>
|
||||||
|
* <li> 1. If a method is marked with a qualifier annotation, it does not contribute to a match otherwise and
|
||||||
|
* is hence removed from the list of potential mapping methods</li>
|
||||||
|
* <li> 2. If multiple qualifiers (qualifedBy) are specified, all should match to make a match.</li>
|
||||||
|
* </ol>
|
||||||
|
* </p>
|
||||||
* @author Sjaak Derksen
|
* @author Sjaak Derksen
|
||||||
*/
|
*/
|
||||||
public class QualifierSelector implements MethodSelector {
|
public class QualifierSelector implements MethodSelector {
|
||||||
@ -52,12 +65,28 @@ public class QualifierSelector implements MethodSelector {
|
|||||||
Type parameterType, Type returnType,
|
Type parameterType, Type returnType,
|
||||||
List<TypeMirror> qualifiers,
|
List<TypeMirror> qualifiers,
|
||||||
String targetPropertyName) {
|
String targetPropertyName) {
|
||||||
List<T> matches = new ArrayList<T>();
|
|
||||||
|
|
||||||
if ( qualifiers == null || qualifiers.isEmpty() ) {
|
if ( qualifiers == null || qualifiers.isEmpty() ) {
|
||||||
return methods;
|
// remove the method marked as qualifier from the list
|
||||||
|
List<T> nonQualiferAnnotatedMethods = new ArrayList<T>();
|
||||||
|
for ( T candidate : methods ) {
|
||||||
|
|
||||||
|
if ( candidate instanceof SourceMethod ) {
|
||||||
|
Set<TypeMirror> qualifierAnnotations = getQualifierAnnotations( candidate );
|
||||||
|
if ( qualifierAnnotations.isEmpty() ) {
|
||||||
|
nonQualiferAnnotatedMethods.add( candidate );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
nonQualiferAnnotatedMethods.add( candidate );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
return nonQualiferAnnotatedMethods;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
|
||||||
|
List<T> matches = new ArrayList<T>();
|
||||||
for ( T candidate : methods ) {
|
for ( T candidate : methods ) {
|
||||||
|
|
||||||
if ( !( candidate instanceof SourceMethod ) ) {
|
if ( !( candidate instanceof SourceMethod ) ) {
|
||||||
@ -65,28 +94,12 @@ public class QualifierSelector implements MethodSelector {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// retrieve annotations
|
// retrieve annotations
|
||||||
Set<TypeMirror> combinedAnnotations = new HashSet<TypeMirror>();
|
Set<TypeMirror> qualifierAnnotations = getQualifierAnnotations( candidate );
|
||||||
|
|
||||||
// first from the method itself
|
// now count if all qualifiers are matched
|
||||||
SourceMethod candidateSM = (SourceMethod) candidate;
|
|
||||||
List<? extends AnnotationMirror> methodAnnotations = candidateSM.getExecutable().getAnnotationMirrors();
|
|
||||||
for ( AnnotationMirror methodAnnotation : methodAnnotations ) {
|
|
||||||
addOnlyWhenQualifier( combinedAnnotations, methodAnnotation );
|
|
||||||
}
|
|
||||||
|
|
||||||
// then from the mapper (if declared)
|
|
||||||
Type mapper = candidate.getDeclaringMapper();
|
|
||||||
if ( mapper != null ) {
|
|
||||||
List<? extends AnnotationMirror> mapperAnnotations = mapper.getTypeElement().getAnnotationMirrors();
|
|
||||||
for ( AnnotationMirror mapperAnnotation : mapperAnnotations ) {
|
|
||||||
addOnlyWhenQualifier( combinedAnnotations, mapperAnnotation );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// now count if all qualifiers are machted
|
|
||||||
int matchingQualifierCounter = 0;
|
int matchingQualifierCounter = 0;
|
||||||
for ( TypeMirror qualifier : qualifiers) {
|
for ( TypeMirror qualifier : qualifiers ) {
|
||||||
for ( TypeMirror annotationType : combinedAnnotations ) {
|
for ( TypeMirror annotationType : qualifierAnnotations ) {
|
||||||
if ( typeUtils.isSameType( qualifier, annotationType ) ) {
|
if ( typeUtils.isSameType( qualifier, annotationType ) ) {
|
||||||
matchingQualifierCounter++;
|
matchingQualifierCounter++;
|
||||||
break;
|
break;
|
||||||
@ -106,6 +119,31 @@ public class QualifierSelector implements MethodSelector {
|
|||||||
return methods;
|
return methods;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private Set<TypeMirror> getQualifierAnnotations( Method candidate ) {
|
||||||
|
|
||||||
|
// retrieve annotations
|
||||||
|
Set<TypeMirror> qualiferAnnotations = new HashSet<TypeMirror>();
|
||||||
|
|
||||||
|
// first from the method itself
|
||||||
|
SourceMethod candidateSM = (SourceMethod) candidate;
|
||||||
|
List<? extends AnnotationMirror> methodAnnotations = candidateSM.getExecutable().getAnnotationMirrors();
|
||||||
|
for ( AnnotationMirror methodAnnotation : methodAnnotations ) {
|
||||||
|
addOnlyWhenQualifier( qualiferAnnotations, methodAnnotation );
|
||||||
|
}
|
||||||
|
|
||||||
|
// then from the mapper (if declared)
|
||||||
|
Type mapper = candidate.getDeclaringMapper();
|
||||||
|
if ( mapper != null ) {
|
||||||
|
List<? extends AnnotationMirror> mapperAnnotations = mapper.getTypeElement().getAnnotationMirrors();
|
||||||
|
for ( AnnotationMirror mapperAnnotation : mapperAnnotations ) {
|
||||||
|
addOnlyWhenQualifier( qualiferAnnotations, mapperAnnotation );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return qualiferAnnotations;
|
||||||
|
}
|
||||||
|
|
||||||
private void addOnlyWhenQualifier( Set<TypeMirror> annotationSet, AnnotationMirror candidate ) {
|
private void addOnlyWhenQualifier( Set<TypeMirror> annotationSet, AnnotationMirror candidate ) {
|
||||||
// only add the candidate annotation when the candidate itself has the annotation 'Qualifier'
|
// only add the candidate annotation when the candidate itself has the annotation 'Qualifier'
|
||||||
@ -113,5 +151,6 @@ public class QualifierSelector implements MethodSelector {
|
|||||||
annotationSet.add( candidate.getAnnotationType() );
|
annotationSet.add( candidate.getAnnotationType() );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -0,0 +1,46 @@
|
|||||||
|
/**
|
||||||
|
* 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.test.selection.qualifier;
|
||||||
|
|
||||||
|
import org.mapstruct.Mapper;
|
||||||
|
import org.mapstruct.Mapping;
|
||||||
|
import org.mapstruct.Mappings;
|
||||||
|
import org.mapstruct.ap.test.selection.qualifier.bean.GermanRelease;
|
||||||
|
import org.mapstruct.ap.test.selection.qualifier.bean.OriginalRelease;
|
||||||
|
import org.mapstruct.ap.test.selection.qualifier.handwritten.Facts;
|
||||||
|
import org.mapstruct.ap.test.selection.qualifier.handwritten.Reverse;
|
||||||
|
import org.mapstruct.factory.Mappers;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author Sjaak Derksen
|
||||||
|
*/
|
||||||
|
@Mapper( uses = { Facts.class, Reverse.class } )
|
||||||
|
public interface MapperWithoutQualifiedBy {
|
||||||
|
|
||||||
|
MapperWithoutQualifiedBy INSTANCE = Mappers.getMapper( MapperWithoutQualifiedBy.class );
|
||||||
|
|
||||||
|
@Mappings( {
|
||||||
|
@Mapping( target = "title", source = "title" ),
|
||||||
|
@Mapping( target = "keyWords", ignore = true ),
|
||||||
|
@Mapping( target = "facts", ignore = true )
|
||||||
|
} )
|
||||||
|
GermanRelease map( OriginalRelease movies );
|
||||||
|
|
||||||
|
}
|
@ -36,6 +36,7 @@ import org.mapstruct.ap.test.selection.qualifier.annotation.NonQualifierAnnotate
|
|||||||
import org.mapstruct.ap.test.selection.qualifier.annotation.TitleTranslator;
|
import org.mapstruct.ap.test.selection.qualifier.annotation.TitleTranslator;
|
||||||
import org.mapstruct.ap.test.selection.qualifier.handwritten.Facts;
|
import org.mapstruct.ap.test.selection.qualifier.handwritten.Facts;
|
||||||
import org.mapstruct.ap.test.selection.qualifier.handwritten.PlotWords;
|
import org.mapstruct.ap.test.selection.qualifier.handwritten.PlotWords;
|
||||||
|
import org.mapstruct.ap.test.selection.qualifier.handwritten.Reverse;
|
||||||
import org.mapstruct.ap.test.selection.qualifier.handwritten.SomeOtherMapper;
|
import org.mapstruct.ap.test.selection.qualifier.handwritten.SomeOtherMapper;
|
||||||
import org.mapstruct.ap.test.selection.qualifier.handwritten.YetAnotherMapper;
|
import org.mapstruct.ap.test.selection.qualifier.handwritten.YetAnotherMapper;
|
||||||
import org.mapstruct.ap.testutil.IssueKey;
|
import org.mapstruct.ap.testutil.IssueKey;
|
||||||
@ -116,4 +117,24 @@ public class QualifierTest {
|
|||||||
public void shouldNotProduceMatchingMethod() {
|
public void shouldNotProduceMatchingMethod() {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@WithClasses( {
|
||||||
|
MapperWithoutQualifiedBy.class,
|
||||||
|
Facts.class,
|
||||||
|
EnglishToGerman.class,
|
||||||
|
Reverse.class
|
||||||
|
} )
|
||||||
|
@IssueKey( "341" )
|
||||||
|
public void shouldNotUseQualifierAnnotatedMethod() {
|
||||||
|
|
||||||
|
|
||||||
|
OriginalRelease foreignMovies = new OriginalRelease();
|
||||||
|
foreignMovies.setTitle( "Sixth Sense, The" );
|
||||||
|
|
||||||
|
GermanRelease result = MapperWithoutQualifiedBy.INSTANCE.map( foreignMovies );
|
||||||
|
assertThat( result ).isNotNull();
|
||||||
|
assertThat( result.getTitle() ).isEqualTo( "ehT ,esneS htxiS");
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,32 @@
|
|||||||
|
/**
|
||||||
|
* 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.test.selection.qualifier.handwritten;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author Sjaak Derksen
|
||||||
|
*/
|
||||||
|
public class Reverse {
|
||||||
|
|
||||||
|
public String reverse( String in ) {
|
||||||
|
StringBuilder b = new StringBuilder(in);
|
||||||
|
return b.reverse().toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user