mirror of
https://github.com/mapstruct/mapstruct.git
synced 2025-07-12 00:00:08 +08:00
#432 Selection of factory method based on Qualifier
This commit is contained in:
parent
bd89a054e8
commit
6ba04920ef
@ -18,6 +18,7 @@
|
||||
*/
|
||||
package org.mapstruct;
|
||||
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
@ -38,4 +39,15 @@ public @interface BeanMapping {
|
||||
* @return the resultType to select
|
||||
*/
|
||||
Class<?> resultType() default void.class;
|
||||
|
||||
/**
|
||||
* A qualifier can be specified to aid the selection process of a suitable factory method. This is useful in
|
||||
* case multiple factory method (hand written of internal) qualify and result in an 'Ambiguous factory methods'
|
||||
* error.
|
||||
*
|
||||
* A qualifier is a custom annotation and can be placed on either a hand written mapper class or a method.
|
||||
*
|
||||
* @return the qualifiers
|
||||
*/
|
||||
Class<? extends Annotation>[] qualifiedBy() default { };
|
||||
}
|
||||
|
@ -0,0 +1,76 @@
|
||||
/**
|
||||
* Copyright 2012-2015 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.model.source;
|
||||
|
||||
import java.util.List;
|
||||
import javax.annotation.processing.Messager;
|
||||
import javax.lang.model.element.ExecutableElement;
|
||||
import javax.lang.model.type.TypeKind;
|
||||
import javax.lang.model.type.TypeMirror;
|
||||
import javax.tools.Diagnostic;
|
||||
import org.mapstruct.ap.prism.BeanMappingPrism;
|
||||
|
||||
|
||||
/**
|
||||
* Represents an bean mapping as configured via {@code @BeanMapping}.
|
||||
*
|
||||
* @author Sjaak Derksen
|
||||
*/
|
||||
public class BeanMapping {
|
||||
|
||||
private final List<TypeMirror> qualifiers;
|
||||
private final TypeMirror resultType;
|
||||
|
||||
public static BeanMapping fromPrism( BeanMappingPrism beanMapping, ExecutableElement method, Messager messager ) {
|
||||
if ( beanMapping == null ) {
|
||||
return null;
|
||||
}
|
||||
|
||||
boolean resultTypeIsDefined = !TypeKind.VOID.equals( beanMapping.resultType().getKind() );
|
||||
if ( !resultTypeIsDefined && beanMapping.qualifiedBy().isEmpty() ) {
|
||||
messager.printMessage(
|
||||
Diagnostic.Kind.ERROR,
|
||||
"'resultType' and 'qualifiedBy' are are are undefined in @BeanMapping, "
|
||||
+ "define at least one of them.",
|
||||
method
|
||||
);
|
||||
}
|
||||
|
||||
return new BeanMapping(
|
||||
beanMapping.qualifiedBy(),
|
||||
resultTypeIsDefined ? beanMapping.resultType() : null
|
||||
);
|
||||
}
|
||||
|
||||
private BeanMapping(
|
||||
List<TypeMirror> qualifiers,
|
||||
TypeMirror mirror) {
|
||||
this.qualifiers = qualifiers;
|
||||
this.resultType = mirror;
|
||||
}
|
||||
|
||||
public List<TypeMirror> getQualifiers() {
|
||||
return qualifiers;
|
||||
}
|
||||
|
||||
public TypeMirror getResultType() {
|
||||
return resultType;
|
||||
}
|
||||
|
||||
}
|
@ -41,6 +41,7 @@ import org.mapstruct.ap.model.common.ConversionContext;
|
||||
import org.mapstruct.ap.model.common.DefaultConversionContext;
|
||||
import org.mapstruct.ap.model.common.Type;
|
||||
import org.mapstruct.ap.model.common.TypeFactory;
|
||||
import org.mapstruct.ap.model.source.BeanMapping;
|
||||
import org.mapstruct.ap.model.source.Method;
|
||||
import org.mapstruct.ap.model.source.SourceMethod;
|
||||
import org.mapstruct.ap.model.source.builtin.BuiltInMappingMethods;
|
||||
@ -147,12 +148,15 @@ public class MappingResolverImpl implements MappingResolver {
|
||||
@Override
|
||||
public MethodReference getFactoryMethod( Method mappingMethod, Type targetType ) {
|
||||
|
||||
TypeMirror qualifyingResultTypeMirror = null;
|
||||
TypeMirror resultType = null;
|
||||
List<TypeMirror> qualifiers = null;
|
||||
BeanMappingPrism beanMappingPrism = BeanMappingPrism.getInstanceOn( mappingMethod.getExecutable() );
|
||||
if ( beanMappingPrism != null ) {
|
||||
qualifyingResultTypeMirror = beanMappingPrism.resultType();
|
||||
BeanMapping beanMapping = BeanMapping.fromPrism( beanMappingPrism, mappingMethod.getExecutable(), messager );
|
||||
if ( beanMapping != null ) {
|
||||
resultType = beanMapping.getResultType();
|
||||
qualifiers = beanMapping.getQualifiers();
|
||||
}
|
||||
SelectionCriteria criteria = new SelectionCriteria(null, null, qualifyingResultTypeMirror );
|
||||
SelectionCriteria criteria = new SelectionCriteria(qualifiers, null, resultType );
|
||||
|
||||
ResolvingAttempt attempt = new ResolvingAttempt(
|
||||
sourceModel,
|
||||
|
@ -0,0 +1,39 @@
|
||||
/**
|
||||
* Copyright 2012-2015 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.BeanMapping;
|
||||
import org.mapstruct.Mapper;
|
||||
import org.mapstruct.ap.test.selection.qualifier.bean.AbstractEntry;
|
||||
import org.mapstruct.ap.test.selection.qualifier.bean.OriginalRelease;
|
||||
import org.mapstruct.factory.Mappers;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Sjaak Derksen
|
||||
*/
|
||||
@Mapper
|
||||
public interface ErroneousMovieFactoryMapper {
|
||||
|
||||
ErroneousMovieFactoryMapper INSTANCE = Mappers.getMapper( ErroneousMovieFactoryMapper.class );
|
||||
|
||||
@BeanMapping
|
||||
AbstractEntry toGerman( OriginalRelease movies );
|
||||
|
||||
}
|
@ -0,0 +1,41 @@
|
||||
/**
|
||||
* Copyright 2012-2015 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.BeanMapping;
|
||||
import org.mapstruct.Mapper;
|
||||
import org.mapstruct.ap.test.selection.qualifier.annotation.CreateGermanRelease;
|
||||
import org.mapstruct.ap.test.selection.qualifier.bean.AbstractEntry;
|
||||
import org.mapstruct.ap.test.selection.qualifier.bean.OriginalRelease;
|
||||
import org.mapstruct.ap.test.selection.qualifier.bean.ReleaseFactory;
|
||||
import org.mapstruct.factory.Mappers;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Sjaak Derksen
|
||||
*/
|
||||
@Mapper( uses = ReleaseFactory.class )
|
||||
public interface MovieFactoryMapper {
|
||||
|
||||
MovieFactoryMapper INSTANCE = Mappers.getMapper( MovieFactoryMapper.class );
|
||||
|
||||
@BeanMapping(qualifiedBy = CreateGermanRelease.class)
|
||||
AbstractEntry toGerman( OriginalRelease movies );
|
||||
|
||||
}
|
@ -31,9 +31,11 @@ import static org.fest.assertions.Assertions.assertThat;
|
||||
import static org.fest.assertions.MapAssert.entry;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mapstruct.ap.test.selection.qualifier.annotation.CreateGermanRelease;
|
||||
import org.mapstruct.ap.test.selection.qualifier.annotation.EnglishToGerman;
|
||||
import org.mapstruct.ap.test.selection.qualifier.annotation.NonQualifierAnnotated;
|
||||
import org.mapstruct.ap.test.selection.qualifier.annotation.TitleTranslator;
|
||||
import org.mapstruct.ap.test.selection.qualifier.bean.ReleaseFactory;
|
||||
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;
|
||||
@ -137,4 +139,57 @@ public class QualifierTest {
|
||||
assertThat( result.getTitle() ).isEqualTo( "ehT ,esneS htxiS");
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
@WithClasses( {
|
||||
MovieFactoryMapper.class,
|
||||
ReleaseFactory.class,
|
||||
CreateGermanRelease.class
|
||||
})
|
||||
@IssueKey( "342")
|
||||
public void testFactorySelectionWithQualifier() {
|
||||
|
||||
OriginalRelease foreignMovies = new OriginalRelease();
|
||||
foreignMovies.setTitle( "Sixth Sense, The" );
|
||||
foreignMovies.setKeyWords( Arrays.asList( "evergreen", "magnificent" ) );
|
||||
Map<String, List<String>> facts = new HashMap<String, List<String>>();
|
||||
facts.put( "director", Arrays.asList( "M. Night Shyamalan" ) );
|
||||
facts.put( "cast", Arrays.asList( "Bruce Willis", "Haley Joel Osment", "Toni Collette" ) );
|
||||
facts.put( "plot keywords", Arrays.asList( "boy", "child psychologist", "I see dead people" ) );
|
||||
foreignMovies.setFacts( facts );
|
||||
|
||||
AbstractEntry abstractEntry = MovieFactoryMapper.INSTANCE.toGerman( foreignMovies );
|
||||
assertThat( abstractEntry ).isNotNull();
|
||||
assertThat( abstractEntry ).isInstanceOf( GermanRelease.class );
|
||||
assertThat( abstractEntry.getTitle() ).isEqualTo( "Sixth Sense, The" );
|
||||
assertThat( abstractEntry.getKeyWords() ).isNotNull();
|
||||
assertThat( abstractEntry.getKeyWords().size() ).isEqualTo( 2 );
|
||||
assertThat( abstractEntry.getKeyWords() ).containsSequence( "evergreen", "magnificent" );
|
||||
|
||||
assertThat( abstractEntry.getFacts() ).isNotNull();
|
||||
assertThat( abstractEntry.getFacts() ).hasSize( 3 );
|
||||
assertThat( abstractEntry.getFacts() ).includes(
|
||||
entry( "director", Arrays.asList( "M. Night Shyamalan" ) ),
|
||||
entry( "cast", Arrays.asList( "Bruce Willis", "Haley Joel Osment", "Toni Collette" ) ),
|
||||
entry( "plot keywords", Arrays.asList( "boy", "child psychologist", "I see dead people" ) )
|
||||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
@IssueKey( "342")
|
||||
@WithClasses( {
|
||||
ErroneousMovieFactoryMapper.class
|
||||
} )
|
||||
@ExpectedCompilationOutcome(
|
||||
value = CompilationResult.FAILED,
|
||||
diagnostics = {
|
||||
@Diagnostic( type = ErroneousMovieFactoryMapper.class,
|
||||
kind = Kind.ERROR,
|
||||
line = 37,
|
||||
messageRegExp = "'resultType' and 'qualifiedBy' are are are undefined in @BeanMapping, "
|
||||
+ "define at least one of them." )
|
||||
}
|
||||
)
|
||||
public void testEmptyBeanMapping() {
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,35 @@
|
||||
/**
|
||||
* Copyright 2012-2015 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.annotation;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
import org.mapstruct.Qualifier;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Sjaak Derksen
|
||||
*/
|
||||
@Qualifier
|
||||
@Target(ElementType.METHOD)
|
||||
@Retention(RetentionPolicy.SOURCE)
|
||||
public @interface CreateGermanRelease {
|
||||
}
|
@ -0,0 +1,37 @@
|
||||
/**
|
||||
* Copyright 2012-2015 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.bean;
|
||||
|
||||
import org.mapstruct.ap.test.selection.qualifier.annotation.CreateGermanRelease;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Sjaak Derksen
|
||||
*/
|
||||
public class ReleaseFactory {
|
||||
|
||||
public OriginalRelease createOriginalRelease() {
|
||||
return new OriginalRelease();
|
||||
}
|
||||
|
||||
@CreateGermanRelease
|
||||
public GermanRelease createGermanRelease() {
|
||||
return new GermanRelease();
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user