mirror of
https://github.com/mapstruct/mapstruct.git
synced 2025-07-12 00:00:08 +08:00
parent
9c33199a66
commit
d50e41cdbb
@ -89,25 +89,15 @@ public abstract class ContainerMappingMethodBuilder<B extends ContainerMappingMe
|
|||||||
false
|
false
|
||||||
);
|
);
|
||||||
|
|
||||||
Assignment assignment = ctx.getMappingResolver().getTargetAssignment(
|
Assignment assignment = ctx.getMappingResolver().getTargetAssignment( method,
|
||||||
method,
|
|
||||||
targetElementType,
|
targetElementType,
|
||||||
formattingParameters,
|
formattingParameters,
|
||||||
criteria,
|
criteria,
|
||||||
sourceRHS,
|
sourceRHS,
|
||||||
null
|
null,
|
||||||
|
() -> forge( sourceRHS, sourceElementType, targetElementType )
|
||||||
);
|
);
|
||||||
|
|
||||||
if ( assignment == null && !criteria.hasQualfiers() ) {
|
|
||||||
assignment = forgeMapping( sourceRHS, sourceElementType, targetElementType );
|
|
||||||
if ( assignment != null ) {
|
|
||||||
ctx.getMessager().note( 2, Message.ITERABLEMAPPING_CREATE_ELEMENT_NOTE, assignment );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
ctx.getMessager().note( 2, Message.ITERABLEMAPPING_SELECT_ELEMENT_NOTE, assignment );
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( assignment == null ) {
|
if ( assignment == null ) {
|
||||||
if ( method instanceof ForgedMethod ) {
|
if ( method instanceof ForgedMethod ) {
|
||||||
// leave messaging to calling property mapping
|
// leave messaging to calling property mapping
|
||||||
@ -124,6 +114,7 @@ public abstract class ContainerMappingMethodBuilder<B extends ContainerMappingMe
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
ctx.getMessager().note( 2, Message.ITERABLEMAPPING_SELECT_ELEMENT_NOTE, assignment );
|
||||||
if ( method instanceof ForgedMethod ) {
|
if ( method instanceof ForgedMethod ) {
|
||||||
ForgedMethod forgedMethod = (ForgedMethod) method;
|
ForgedMethod forgedMethod = (ForgedMethod) method;
|
||||||
forgedMethod.addThrownTypes( assignment.getThrownTypes() );
|
forgedMethod.addThrownTypes( assignment.getThrownTypes() );
|
||||||
@ -171,6 +162,14 @@ public abstract class ContainerMappingMethodBuilder<B extends ContainerMappingMe
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private Assignment forge(SourceRHS sourceRHS, Type sourceType, Type targetType) {
|
||||||
|
Assignment assignment = super.forgeMapping( sourceRHS, sourceType, targetType );
|
||||||
|
if ( assignment != null ) {
|
||||||
|
ctx.getMessager().note( 2, Message.ITERABLEMAPPING_CREATE_ELEMENT_NOTE, assignment );
|
||||||
|
}
|
||||||
|
return assignment;
|
||||||
|
}
|
||||||
|
|
||||||
protected abstract M instantiateMappingMethod(Method method, Collection<String> existingVariables,
|
protected abstract M instantiateMappingMethod(Method method, Collection<String> existingVariables,
|
||||||
Assignment assignment, MethodReference factoryMethod,
|
Assignment assignment, MethodReference factoryMethod,
|
||||||
boolean mapNullToDefault, String loopVariableName,
|
boolean mapNullToDefault, String loopVariableName,
|
||||||
|
@ -97,19 +97,10 @@ public class MapMappingMethod extends NormalTypeMappingMethod {
|
|||||||
keyFormattingParameters,
|
keyFormattingParameters,
|
||||||
keyCriteria,
|
keyCriteria,
|
||||||
keySourceRHS,
|
keySourceRHS,
|
||||||
null
|
null,
|
||||||
|
() -> forge( keySourceRHS, keySourceType, keyTargetType, Message.MAPMAPPING_CREATE_KEY_NOTE )
|
||||||
);
|
);
|
||||||
|
|
||||||
if ( keyAssignment == null && !keyCriteria.hasQualfiers( ) ) {
|
|
||||||
keyAssignment = forgeMapping( keySourceRHS, keySourceType, keyTargetType );
|
|
||||||
if ( keyAssignment != null ) {
|
|
||||||
ctx.getMessager().note( 2, Message.MAPMAPPING_CREATE_KEY_NOTE, keyAssignment );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
ctx.getMessager().note( 2, Message.MAPMAPPING_SELECT_KEY_NOTE, keyAssignment );
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( keyAssignment == null ) {
|
if ( keyAssignment == null ) {
|
||||||
if ( method instanceof ForgedMethod ) {
|
if ( method instanceof ForgedMethod ) {
|
||||||
// leave messaging to calling property mapping
|
// leave messaging to calling property mapping
|
||||||
@ -129,6 +120,9 @@ public class MapMappingMethod extends NormalTypeMappingMethod {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else {
|
||||||
|
ctx.getMessager().note( 2, Message.MAPMAPPING_SELECT_KEY_NOTE, keyAssignment );
|
||||||
|
}
|
||||||
|
|
||||||
// find mapping method or conversion for value
|
// find mapping method or conversion for value
|
||||||
Type valueSourceType = sourceTypeParams.get( 1 ).getTypeBound();
|
Type valueSourceType = sourceTypeParams.get( 1 ).getTypeBound();
|
||||||
@ -146,7 +140,8 @@ public class MapMappingMethod extends NormalTypeMappingMethod {
|
|||||||
valueFormattingParameters,
|
valueFormattingParameters,
|
||||||
valueCriteria,
|
valueCriteria,
|
||||||
valueSourceRHS,
|
valueSourceRHS,
|
||||||
null
|
null,
|
||||||
|
() -> forge( valueSourceRHS, valueSourceType, valueTargetType, Message.MAPMAPPING_CREATE_VALUE_NOTE )
|
||||||
);
|
);
|
||||||
|
|
||||||
if ( method instanceof ForgedMethod ) {
|
if ( method instanceof ForgedMethod ) {
|
||||||
@ -159,16 +154,6 @@ public class MapMappingMethod extends NormalTypeMappingMethod {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( valueAssignment == null && !valueCriteria.hasQualfiers( ) ) {
|
|
||||||
valueAssignment = forgeMapping( valueSourceRHS, valueSourceType, valueTargetType );
|
|
||||||
if ( valueAssignment != null ) {
|
|
||||||
ctx.getMessager().note( 2, Message.MAPMAPPING_CREATE_VALUE_NOTE, valueAssignment );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
ctx.getMessager().note( 2, Message.MAPMAPPING_SELECT_VALUE_NOTE, valueAssignment );
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( valueAssignment == null ) {
|
if ( valueAssignment == null ) {
|
||||||
if ( method instanceof ForgedMethod ) {
|
if ( method instanceof ForgedMethod ) {
|
||||||
// leave messaging to calling property mapping
|
// leave messaging to calling property mapping
|
||||||
@ -188,6 +173,9 @@ public class MapMappingMethod extends NormalTypeMappingMethod {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else {
|
||||||
|
ctx.getMessager().note( 2, Message.MAPMAPPING_SELECT_VALUE_NOTE, valueAssignment );
|
||||||
|
}
|
||||||
|
|
||||||
// mapNullToDefault
|
// mapNullToDefault
|
||||||
boolean mapNullToDefault = false;
|
boolean mapNullToDefault = false;
|
||||||
@ -222,6 +210,14 @@ public class MapMappingMethod extends NormalTypeMappingMethod {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Assignment forge(SourceRHS sourceRHS, Type sourceType, Type targetType, Message message ) {
|
||||||
|
Assignment assignment = forgeMapping( sourceRHS, sourceType, targetType );
|
||||||
|
if ( assignment != null ) {
|
||||||
|
ctx.getMessager().note( 2, message, assignment );
|
||||||
|
}
|
||||||
|
return assignment;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected boolean shouldUsePropertyNamesInHistory() {
|
protected boolean shouldUsePropertyNamesInHistory() {
|
||||||
return true;
|
return true;
|
||||||
|
@ -11,6 +11,7 @@ import java.util.HashSet;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
import java.util.function.Supplier;
|
||||||
|
|
||||||
import javax.lang.model.element.AnnotationMirror;
|
import javax.lang.model.element.AnnotationMirror;
|
||||||
import javax.lang.model.element.TypeElement;
|
import javax.lang.model.element.TypeElement;
|
||||||
@ -93,7 +94,8 @@ public class MappingBuilderContext {
|
|||||||
Assignment getTargetAssignment(Method mappingMethod, Type targetType,
|
Assignment getTargetAssignment(Method mappingMethod, Type targetType,
|
||||||
FormattingParameters formattingParameters,
|
FormattingParameters formattingParameters,
|
||||||
SelectionCriteria criteria, SourceRHS sourceRHS,
|
SelectionCriteria criteria, SourceRHS sourceRHS,
|
||||||
AnnotationMirror positionHint);
|
AnnotationMirror positionHint,
|
||||||
|
Supplier<Assignment> forger);
|
||||||
|
|
||||||
Set<SupportingMappingMethod> getUsedSupportedMappings();
|
Set<SupportingMappingMethod> getUsedSupportedMappings();
|
||||||
}
|
}
|
||||||
|
@ -280,36 +280,17 @@ public class PropertyMapping extends ModelElement {
|
|||||||
formattingParameters,
|
formattingParameters,
|
||||||
criteria,
|
criteria,
|
||||||
rightHandSide,
|
rightHandSide,
|
||||||
positionHint
|
positionHint,
|
||||||
|
() -> forge( )
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
else {
|
||||||
|
assignment = forge();
|
||||||
|
}
|
||||||
|
|
||||||
Type sourceType = rightHandSide.getSourceType();
|
Type sourceType = rightHandSide.getSourceType();
|
||||||
// No mapping found. Try to forge a mapping
|
|
||||||
if ( assignment == null && !criteria.hasQualfiers() ) {
|
|
||||||
if ( (sourceType.isCollectionType() || sourceType.isArrayType()) && targetType.isIterableType() ) {
|
|
||||||
assignment = forgeIterableMapping( sourceType, targetType, rightHandSide, method.getExecutable() );
|
|
||||||
}
|
|
||||||
else if ( sourceType.isMapType() && targetType.isMapType() ) {
|
|
||||||
assignment = forgeMapMapping( sourceType, targetType, rightHandSide, method.getExecutable() );
|
|
||||||
}
|
|
||||||
else if ( ( sourceType.isIterableType() && targetType.isStreamType() ) ||
|
|
||||||
( sourceType.isStreamType() && targetType.isStreamType() ) ||
|
|
||||||
( sourceType.isStreamType() && targetType.isIterableType() ) ) {
|
|
||||||
assignment = forgeStreamMapping( sourceType, targetType, rightHandSide, method.getExecutable() );
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
assignment = forgeMapping( rightHandSide );
|
|
||||||
}
|
|
||||||
if ( assignment != null ) {
|
|
||||||
ctx.getMessager().note( 2, Message.PROPERTYMAPPING_CREATE_NOTE, assignment );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
ctx.getMessager().note( 2, Message.PROPERTYMAPPING_SELECT_NOTE, assignment );
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( assignment != null ) {
|
if ( assignment != null ) {
|
||||||
|
ctx.getMessager().note( 2, Message.PROPERTYMAPPING_SELECT_NOTE, assignment );
|
||||||
if ( targetType.isCollectionOrMapType() ) {
|
if ( targetType.isCollectionOrMapType() ) {
|
||||||
assignment = assignToCollection( targetType, targetWriteAccessorType, assignment );
|
assignment = assignToCollection( targetType, targetWriteAccessorType, assignment );
|
||||||
}
|
}
|
||||||
@ -336,6 +317,29 @@ public class PropertyMapping extends ModelElement {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private Assignment forge( ) {
|
||||||
|
Assignment assignment;
|
||||||
|
Type sourceType = rightHandSide.getSourceType();
|
||||||
|
if ( (sourceType.isCollectionType() || sourceType.isArrayType()) && targetType.isIterableType() ) {
|
||||||
|
assignment = forgeIterableMapping( sourceType, targetType, rightHandSide, method.getExecutable() );
|
||||||
|
}
|
||||||
|
else if ( sourceType.isMapType() && targetType.isMapType() ) {
|
||||||
|
assignment = forgeMapMapping( sourceType, targetType, rightHandSide, method.getExecutable() );
|
||||||
|
}
|
||||||
|
else if ( ( sourceType.isIterableType() && targetType.isStreamType() )
|
||||||
|
|| ( sourceType.isStreamType() && targetType.isStreamType() )
|
||||||
|
|| ( sourceType.isStreamType() && targetType.isIterableType() ) ) {
|
||||||
|
assignment = forgeStreamMapping( sourceType, targetType, rightHandSide, method.getExecutable() );
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
assignment = forgeMapping( rightHandSide );
|
||||||
|
}
|
||||||
|
if ( assignment != null ) {
|
||||||
|
ctx.getMessager().note( 2, Message.PROPERTYMAPPING_CREATE_NOTE, assignment );
|
||||||
|
}
|
||||||
|
return assignment;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Report that a mapping could not be created.
|
* Report that a mapping could not be created.
|
||||||
*/
|
*/
|
||||||
@ -844,7 +848,8 @@ public class PropertyMapping extends ModelElement {
|
|||||||
formattingParameters,
|
formattingParameters,
|
||||||
criteria,
|
criteria,
|
||||||
new SourceRHS( constantExpression, sourceType, existingVariableNames, sourceErrorMessagePart ),
|
new SourceRHS( constantExpression, sourceType, existingVariableNames, sourceErrorMessagePart ),
|
||||||
positionHint
|
positionHint,
|
||||||
|
() -> null
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
@ -9,6 +9,7 @@ import java.util.ArrayList;
|
|||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
import java.util.function.Supplier;
|
||||||
import javax.lang.model.element.AnnotationMirror;
|
import javax.lang.model.element.AnnotationMirror;
|
||||||
import javax.lang.model.element.ExecutableElement;
|
import javax.lang.model.element.ExecutableElement;
|
||||||
import javax.lang.model.element.TypeElement;
|
import javax.lang.model.element.TypeElement;
|
||||||
@ -97,7 +98,8 @@ public class MappingResolverImpl implements MappingResolver {
|
|||||||
public Assignment getTargetAssignment(Method mappingMethod, Type targetType,
|
public Assignment getTargetAssignment(Method mappingMethod, Type targetType,
|
||||||
FormattingParameters formattingParameters,
|
FormattingParameters formattingParameters,
|
||||||
SelectionCriteria criteria, SourceRHS sourceRHS,
|
SelectionCriteria criteria, SourceRHS sourceRHS,
|
||||||
AnnotationMirror positionHint) {
|
AnnotationMirror positionHint,
|
||||||
|
Supplier<Assignment> forger) {
|
||||||
|
|
||||||
ResolvingAttempt attempt = new ResolvingAttempt(
|
ResolvingAttempt attempt = new ResolvingAttempt(
|
||||||
sourceModel,
|
sourceModel,
|
||||||
@ -105,7 +107,8 @@ public class MappingResolverImpl implements MappingResolver {
|
|||||||
formattingParameters,
|
formattingParameters,
|
||||||
sourceRHS,
|
sourceRHS,
|
||||||
criteria,
|
criteria,
|
||||||
positionHint
|
positionHint,
|
||||||
|
forger
|
||||||
);
|
);
|
||||||
|
|
||||||
return attempt.getTargetAssignment( sourceRHS.getSourceTypeForMatching(), targetType );
|
return attempt.getTargetAssignment( sourceRHS.getSourceTypeForMatching(), targetType );
|
||||||
@ -136,6 +139,7 @@ public class MappingResolverImpl implements MappingResolver {
|
|||||||
private final boolean savedPreferUpdateMapping;
|
private final boolean savedPreferUpdateMapping;
|
||||||
private final FormattingParameters formattingParameters;
|
private final FormattingParameters formattingParameters;
|
||||||
private final AnnotationMirror positionHint;
|
private final AnnotationMirror positionHint;
|
||||||
|
private final Supplier<Assignment> forger;
|
||||||
|
|
||||||
// resolving via 2 steps creates the possibility of wrong matches, first builtin method matches,
|
// resolving via 2 steps creates the possibility of wrong matches, first builtin method matches,
|
||||||
// second doesn't. In that case, the first builtin method should not lead to a supported method
|
// second doesn't. In that case, the first builtin method should not lead to a supported method
|
||||||
@ -145,7 +149,8 @@ public class MappingResolverImpl implements MappingResolver {
|
|||||||
private ResolvingAttempt(List<Method> sourceModel, Method mappingMethod,
|
private ResolvingAttempt(List<Method> sourceModel, Method mappingMethod,
|
||||||
FormattingParameters formattingParameters, SourceRHS sourceRHS,
|
FormattingParameters formattingParameters, SourceRHS sourceRHS,
|
||||||
SelectionCriteria criteria,
|
SelectionCriteria criteria,
|
||||||
AnnotationMirror positionHint) {
|
AnnotationMirror positionHint,
|
||||||
|
Supplier<Assignment> forger) {
|
||||||
|
|
||||||
this.mappingMethod = mappingMethod;
|
this.mappingMethod = mappingMethod;
|
||||||
this.methods = filterPossibleCandidateMethods( sourceModel );
|
this.methods = filterPossibleCandidateMethods( sourceModel );
|
||||||
@ -156,6 +161,7 @@ public class MappingResolverImpl implements MappingResolver {
|
|||||||
this.selectionCriteria = criteria;
|
this.selectionCriteria = criteria;
|
||||||
this.savedPreferUpdateMapping = criteria.isPreferUpdateMapping();
|
this.savedPreferUpdateMapping = criteria.isPreferUpdateMapping();
|
||||||
this.positionHint = positionHint;
|
this.positionHint = positionHint;
|
||||||
|
this.forger = forger;
|
||||||
}
|
}
|
||||||
|
|
||||||
private <T extends Method> List<T> filterPossibleCandidateMethods(List<T> candidateMethods) {
|
private <T extends Method> List<T> filterPossibleCandidateMethods(List<T> candidateMethods) {
|
||||||
@ -243,6 +249,19 @@ public class MappingResolverImpl implements MappingResolver {
|
|||||||
return conversion.getAssignment();
|
return conversion.getAssignment();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ( hasQualfiers() ) {
|
||||||
|
messager.printMessage(
|
||||||
|
mappingMethod.getExecutable(),
|
||||||
|
positionHint,
|
||||||
|
Message.GENERAL_NO_QUALIFYING_METHOD,
|
||||||
|
Strings.join( selectionCriteria.getQualifiers(), ", " ),
|
||||||
|
Strings.join( selectionCriteria.getQualifiedByNames(), ", " )
|
||||||
|
);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return forger.get();
|
||||||
|
}
|
||||||
|
|
||||||
// if nothing works, alas, the result is null
|
// if nothing works, alas, the result is null
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
@ -113,6 +113,7 @@ public enum Message {
|
|||||||
GENERAL_JODA_NOT_ON_CLASSPATH( "Cannot validate Joda dateformat, no Joda on classpath. Consider adding Joda to the annotation processorpath.", Diagnostic.Kind.WARNING ),
|
GENERAL_JODA_NOT_ON_CLASSPATH( "Cannot validate Joda dateformat, no Joda on classpath. Consider adding Joda to the annotation processorpath.", Diagnostic.Kind.WARNING ),
|
||||||
GENERAL_NOT_ALL_FORGED_CREATED( "Internal Error in creation of Forged Methods, it was expected all Forged Methods to finished with creation, but %s did not" ),
|
GENERAL_NOT_ALL_FORGED_CREATED( "Internal Error in creation of Forged Methods, it was expected all Forged Methods to finished with creation, but %s did not" ),
|
||||||
GENERAL_NO_SUITABLE_CONSTRUCTOR( "%s does not have an accessible parameterless constructor." ),
|
GENERAL_NO_SUITABLE_CONSTRUCTOR( "%s does not have an accessible parameterless constructor." ),
|
||||||
|
GENERAL_NO_QUALIFYING_METHOD( "No qualifying method found for qualifiers: %s and / or qualifying names: %s" ),
|
||||||
|
|
||||||
BUILDER_MORE_THAN_ONE_BUILDER_CREATION_METHOD( "More than one builder creation method for \"%s\". Found methods: \"%s\". Builder will not be used. Consider implementing a custom BuilderProvider SPI.", Diagnostic.Kind.WARNING ),
|
BUILDER_MORE_THAN_ONE_BUILDER_CREATION_METHOD( "More than one builder creation method for \"%s\". Found methods: \"%s\". Builder will not be used. Consider implementing a custom BuilderProvider SPI.", Diagnostic.Kind.WARNING ),
|
||||||
BUILDER_NO_BUILD_METHOD_FOUND("No build method \"%s\" found in \"%s\" for \"%s\". Found methods: \"%s\".", Diagnostic.Kind.ERROR ),
|
BUILDER_NO_BUILD_METHOD_FOUND("No build method \"%s\" found in \"%s\" for \"%s\". Found methods: \"%s\".", Diagnostic.Kind.ERROR ),
|
||||||
|
@ -98,7 +98,16 @@ public class QualifierTest {
|
|||||||
@ExpectedCompilationOutcome(
|
@ExpectedCompilationOutcome(
|
||||||
value = CompilationResult.FAILED,
|
value = CompilationResult.FAILED,
|
||||||
diagnostics = {
|
diagnostics = {
|
||||||
@Diagnostic(type = ErroneousMapper.class,
|
@Diagnostic(
|
||||||
|
type = ErroneousMapper.class,
|
||||||
|
kind = Kind.ERROR,
|
||||||
|
line = 28,
|
||||||
|
messageRegExp =
|
||||||
|
"No qualifying method found for qualifiers: "
|
||||||
|
+ "org.mapstruct.ap.test.selection.qualifier.annotation.NonQualifierAnnotated and "
|
||||||
|
+ "/ or qualifying names: .*"),
|
||||||
|
@Diagnostic(
|
||||||
|
type = ErroneousMapper.class,
|
||||||
kind = Kind.ERROR,
|
kind = Kind.ERROR,
|
||||||
line = 28,
|
line = 28,
|
||||||
messageRegExp =
|
messageRegExp =
|
||||||
|
Loading…
x
Reference in New Issue
Block a user