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.
|
||||
*
|
||||
* <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
|
||||
*/
|
||||
public class QualifierSelector implements MethodSelector {
|
||||
@ -52,66 +65,92 @@ public class QualifierSelector implements MethodSelector {
|
||||
Type parameterType, Type returnType,
|
||||
List<TypeMirror> qualifiers,
|
||||
String targetPropertyName) {
|
||||
List<T> matches = new ArrayList<T>();
|
||||
|
||||
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 ) {
|
||||
|
||||
for ( T candidate : methods ) {
|
||||
|
||||
if ( !( candidate instanceof SourceMethod ) ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// retrieve annotations
|
||||
Set<TypeMirror> combinedAnnotations = new HashSet<TypeMirror>();
|
||||
|
||||
// first from the method itself
|
||||
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;
|
||||
for ( TypeMirror qualifier : qualifiers) {
|
||||
for ( TypeMirror annotationType : combinedAnnotations ) {
|
||||
if ( typeUtils.isSameType( qualifier, annotationType ) ) {
|
||||
matchingQualifierCounter++;
|
||||
break;
|
||||
if ( candidate instanceof SourceMethod ) {
|
||||
Set<TypeMirror> qualifierAnnotations = getQualifierAnnotations( candidate );
|
||||
if ( qualifierAnnotations.isEmpty() ) {
|
||||
nonQualiferAnnotatedMethods.add( candidate );
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
nonQualiferAnnotatedMethods.add( candidate );
|
||||
}
|
||||
|
||||
if ( matchingQualifierCounter == qualifiers.size() ) {
|
||||
// all qualifiers are matched with a qualifying annotation, add candidate
|
||||
matches.add( candidate );
|
||||
}
|
||||
}
|
||||
if ( !matches.isEmpty() ) {
|
||||
return matches;
|
||||
return nonQualiferAnnotatedMethods;
|
||||
}
|
||||
else {
|
||||
return methods;
|
||||
|
||||
List<T> matches = new ArrayList<T>();
|
||||
for ( T candidate : methods ) {
|
||||
|
||||
if ( !( candidate instanceof SourceMethod ) ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// retrieve annotations
|
||||
Set<TypeMirror> qualifierAnnotations = getQualifierAnnotations( candidate );
|
||||
|
||||
// now count if all qualifiers are matched
|
||||
int matchingQualifierCounter = 0;
|
||||
for ( TypeMirror qualifier : qualifiers ) {
|
||||
for ( TypeMirror annotationType : qualifierAnnotations ) {
|
||||
if ( typeUtils.isSameType( qualifier, annotationType ) ) {
|
||||
matchingQualifierCounter++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ( matchingQualifierCounter == qualifiers.size() ) {
|
||||
// all qualifiers are matched with a qualifying annotation, add candidate
|
||||
matches.add( candidate );
|
||||
}
|
||||
}
|
||||
if ( !matches.isEmpty() ) {
|
||||
return matches;
|
||||
}
|
||||
else {
|
||||
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 ) {
|
||||
// only add the candidate annotation when the candidate itself has the annotation 'Qualifier'
|
||||
if ( QualifierPrism.getInstanceOn( candidate.getAnnotationType().asElement() ) != null ) {
|
||||
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.handwritten.Facts;
|
||||
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.YetAnotherMapper;
|
||||
import org.mapstruct.ap.testutil.IssueKey;
|
||||
@ -116,4 +117,24 @@ public class QualifierTest {
|
||||
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