#981 Refactoring, move SourceRHS init to start of property build.

This commit is contained in:
sjaakd 2016-12-03 15:20:26 +01:00
parent 0ec9729801
commit 81a4cb360d
22 changed files with 187 additions and 178 deletions

View File

@ -105,12 +105,11 @@ public class IterableMappingMethod extends MappingMethod {
Assignment assignment = ctx.getMappingResolver().getTargetAssignment(
method,
"collection element",
targetElementType,
null, // there is no targetPropertyName
formattingParameters,
selectionParameters,
new SourceRHS( loopVariableName, sourceElementType, new HashSet<String>() ),
new SourceRHS( loopVariableName, sourceElementType, new HashSet<String>(), "collection element" ),
false
);

View File

@ -108,12 +108,11 @@ public class MapMappingMethod extends MappingMethod {
Assignment keyAssignment = ctx.getMappingResolver().getTargetAssignment(
method,
"map key",
keyTargetType,
null, // there is no targetPropertyName
keyFormattingParameters,
keySelectionParameters,
new SourceRHS( "entry.getKey()", keySourceType, new HashSet<String>() ),
new SourceRHS( "entry.getKey()", keySourceType, new HashSet<String>(), "map key" ),
false
);
@ -134,12 +133,11 @@ public class MapMappingMethod extends MappingMethod {
Assignment valueAssignment = ctx.getMappingResolver().getTargetAssignment(
method,
"map value",
valueTargetType,
null, // there is no targetPropertyName
valueFormattingParameters,
valueSelectionParameters,
new SourceRHS( "entry.getValue()", valueSourceType, new HashSet<String>() ),
new SourceRHS( "entry.getValue()", valueSourceType, new HashSet<String>(), "map value" ),
false
);

View File

@ -75,7 +75,6 @@ public class MappingBuilderContext {
* returns a parameter assignment
*
* @param mappingMethod target mapping method
* @param mappedElement used for error messages
* @param targetType return type to match
* @param targetPropertyName name of the target property
* @param formattingParameters used for formatting dates and numbers
@ -91,9 +90,8 @@ public class MappingBuilderContext {
* <li>null, no assignment found</li>
* </ol>
*/
@SuppressWarnings("checkstyle:parameternumber")
Assignment getTargetAssignment(Method mappingMethod, String mappedElement, Type targetType,
String targetPropertyName, FormattingParameters formattingParameters,
Assignment getTargetAssignment(Method mappingMethod, Type targetType, String targetPropertyName,
FormattingParameters formattingParameters,
SelectionParameters selectionParameters, SourceRHS sourceRHS,
boolean preferUpdateMethods);

View File

@ -127,6 +127,11 @@ public class MethodReference extends MappingMethod implements Assignment {
return assignment.getSourceReference();
}
@Override
public String getSourcePresenceCheckerReference() {
return assignment.getSourcePresenceCheckerReference();
}
@Override
public Type getSourceType() {
return assignment.getSourceType();

View File

@ -203,6 +203,7 @@ public class PropertyMapping extends ModelElement {
// initial properties
private String defaultValue;
private SourceReference sourceReference;
private SourceRHS rightHandSide;
private FormattingParameters formattingParameters;
private SelectionParameters selectionParameters;
@ -228,14 +229,10 @@ public class PropertyMapping extends ModelElement {
public PropertyMapping build() {
// handle source
String sourceElement = getSourceElement();
Type sourceType = getSourceType();
SourceRHS sourceRHS = getSourceRHS();
if ( targetWriteAccessorType == TargetWriteAccessorType.ADDER && sourceType.isCollectionType() ) {
// handle adder, if source is collection then use iterator element type as source type.
sourceType = sourceType.getTypeParameters().get( 0 );
sourceRHS = new SourceRHS( sourceRHS.getSourceReference(), sourceType, existingVariableNames );
}
this.rightHandSide = getSourceRHS( sourceReference );
rightHandSide.setUseElementAsSourceTypeForMatching(
targetWriteAccessorType == TargetWriteAccessorType.ADDER );
Type sourceType = rightHandSide.getSourceType();
// all the tricky cases will be excluded for the time being.
boolean preferUpdateMethods;
@ -248,22 +245,21 @@ public class PropertyMapping extends ModelElement {
Assignment assignment = ctx.getMappingResolver().getTargetAssignment(
method,
sourceElement,
targetType,
targetPropertyName,
formattingParameters,
selectionParameters,
sourceRHS,
rightHandSide,
preferUpdateMethods
);
// No mapping found. Try to forge a mapping
if ( assignment == null ) {
if ( (sourceType.isCollectionType() || sourceType.isArrayType()) && targetType.isIterableType() ) {
assignment = forgeIterableMapping( sourceType, targetType, sourceRHS, method.getExecutable() );
assignment = forgeIterableMapping( sourceType, targetType, rightHandSide, method.getExecutable() );
}
else if ( sourceType.isMapType() && targetType.isMapType() ) {
assignment = forgeMapMapping( sourceType, targetType, sourceRHS, method.getExecutable() );
assignment = forgeMapMapping( sourceType, targetType, rightHandSide, method.getExecutable() );
}
}
@ -282,30 +278,30 @@ public class PropertyMapping extends ModelElement {
ctx.getMessager().printMessage(
method.getExecutable(),
Message.PROPERTYMAPPING_MAPPING_NOT_FOUND,
sourceElement,
rightHandSide.getSourceErrorMessagePart(),
targetType,
targetPropertyName,
targetType,
getSourceType() /* original source type */
rightHandSide.getSourceType() /* original source type */
);
}
return new PropertyMapping(
targetPropertyName,
sourceReference.getParameter().getName(),
rightHandSide.getSourceParameterName(),
targetWriteAccessor.getSimpleName().toString(),
ValueProvider.of( targetReadAccessor ),
targetType,
localTargetVarName,
assignment,
dependsOn,
getDefaultValueAssignment()
getDefaultValueAssignment( assignment )
);
}
private Assignment getDefaultValueAssignment() {
private Assignment getDefaultValueAssignment( Assignment rhs ) {
if ( defaultValue != null
&& ( !getSourceType().isPrimitive() || getSourcePresenceCheckerRef() != null) ) {
&& ( !rhs.getSourceType().isPrimitive() || rhs.getSourcePresenceCheckerReference() != null) ) {
// cannot check on null source if source is primitive unless it has a presenche checker
PropertyMapping build = new ConstantMappingBuilder()
.constantExpression( '"' + defaultValue + '"' )
@ -340,23 +336,23 @@ public class PropertyMapping extends ModelElement {
}
private Assignment assignToPlainViaSetter(Type sourceType, Type targetType, Assignment rightHandSide) {
private Assignment assignToPlainViaSetter(Type sourceType, Type targetType, Assignment rhs) {
Assignment result;
if ( rightHandSide.isUpdateMethod() ) {
if ( rhs.isUpdateMethod() ) {
if ( targetReadAccessor == null ) {
ctx.getMessager().printMessage( method.getExecutable(),
Message.PROPERTYMAPPING_NO_READ_ACCESSOR_FOR_TARGET_TYPE,
targetPropertyName );
}
Assignment factoryMethod = ctx.getMappingResolver().getFactoryMethod( method, targetType, null );
result = new UpdateWrapper( rightHandSide, method.getThrownTypes(), factoryMethod,
result = new UpdateWrapper( rhs, method.getThrownTypes(), factoryMethod,
targetType, isFieldAssignment()
);
}
else {
result = new SetterWrapper( rightHandSide, method.getThrownTypes(), isFieldAssignment() );
result = new SetterWrapper( rhs, method.getThrownTypes(), isFieldAssignment() );
}
// if the sourceReference is the bean mapping method parameter itself, no null check is required
@ -367,20 +363,20 @@ public class PropertyMapping extends ModelElement {
// add a null / presence checked when required
if ( sourceType.isPrimitive() ) {
if ( getSourcePresenceCheckerRef() != null ) {
result = new NullCheckWrapper( result, getSourcePresenceCheckerRef() );
if ( rhs.getSourcePresenceCheckerReference() != null ) {
result = new NullCheckWrapper( result );
}
}
else {
if ( result.isUpdateMethod() ) {
result = new UpdateNullCheckWrapper( result, getSourcePresenceCheckerRef(), isFieldAssignment() );
result = new UpdateNullCheckWrapper( result, isFieldAssignment() );
}
else if ( getSourcePresenceCheckerRef() != null ) {
result = new NullCheckWrapper( result, getSourcePresenceCheckerRef() );
else if ( rhs.getSourcePresenceCheckerReference() != null ) {
result = new NullCheckWrapper( result );
}
else if ( ALWAYS.equals( method.getMapperConfiguration().getNullValueCheckStrategy() ) ) {
result = new NullCheckWrapper( result, getSourcePresenceCheckerRef() );
result = new NullCheckWrapper( result );
useLocalVarWhenNested( result );
}
else if ( result.getType() == TYPE_CONVERTED
@ -389,7 +385,7 @@ public class PropertyMapping extends ModelElement {
|| (result.getType() == DIRECT && targetType.isPrimitive() ) ) {
// for primitive types null check is not possible at all, but a conversion needs
// a null check.
result = new NullCheckWrapper( result, getSourcePresenceCheckerRef() );
result = new NullCheckWrapper( result );
useLocalVarWhenNested( result );
}
}
@ -410,13 +406,13 @@ public class PropertyMapping extends ModelElement {
Assignment result = rightHandSide;
if ( getSourceType().isCollectionType() ) {
if ( result.getSourceType().isCollectionType() ) {
result = new AdderWrapper( result, method.getThrownTypes(), isFieldAssignment() );
}
else {
// Possibly adding null to a target collection. So should be surrounded by an null check.
result = new SetterWrapper( result, method.getThrownTypes(), isFieldAssignment() );
result = new NullCheckWrapper( result, getSourcePresenceCheckerRef() );
result = new NullCheckWrapper( result );
}
return result;
}
@ -450,7 +446,6 @@ public class PropertyMapping extends ModelElement {
result = new SetterWrapperForCollectionsAndMaps(
result,
method.getThrownTypes(),
getSourcePresenceCheckerRef(),
existingVariableNames,
targetType,
ALWAYS == method.getMapperConfiguration().getNullValueCheckStrategy(),
@ -463,7 +458,6 @@ public class PropertyMapping extends ModelElement {
// target accessor is getter, so wrap the setter in getter map/ collection handling
result = new GetterWrapperForCollectionsAndMaps( result,
method.getThrownTypes(),
getSourcePresenceCheckerRef(),
existingVariableNames,
targetType,
isFieldAssignment()
@ -484,19 +478,34 @@ public class PropertyMapping extends ModelElement {
existingVariableNames,
isFieldAssignment()
);
return new NullCheckWrapper( assignment, getSourcePresenceCheckerRef() );
return new NullCheckWrapper( assignment );
}
private Type getSourceType() {
private SourceRHS getSourceRHS( SourceReference sourceReference ) {
Parameter sourceParam = sourceReference.getParameter();
List<PropertyEntry> propertyEntries = sourceReference.getPropertyEntries();
// parameter reference
if ( propertyEntries.isEmpty() ) {
return sourceParam.getType();
return new SourceRHS( sourceParam.getName(),
sourceParam.getType(),
existingVariableNames,
sourceReference.toString()
);
}
// simple property
else if ( propertyEntries.size() == 1 ) {
return last( propertyEntries ).getType();
PropertyEntry propertyEntry = propertyEntries.get( 0 );
String sourceRef = sourceParam.getName() + "." + ValueProvider.of( propertyEntry.getReadAccessor() );
return new SourceRHS( sourceParam.getName(),
sourceRef,
getSourcePresenceCheckerRef( sourceReference ),
propertyEntry.getType(),
existingVariableNames,
sourceReference.toString()
);
}
// nested property given as dot path
else {
Type sourceType = last( propertyEntries ).getType();
if ( sourceType.isPrimitive() && !targetType.isPrimitive() ) {
@ -505,39 +514,18 @@ public class PropertyMapping extends ModelElement {
// type. The source type becomes the wrapped type in that case.
sourceType = ctx.getTypeFactory().getWrappedType( sourceType );
}
return sourceType;
}
}
private SourceRHS getSourceRHS() {
Parameter sourceParam = sourceReference.getParameter();
List<PropertyEntry> propertyEntries = sourceReference.getPropertyEntries();
// parameter reference
if ( propertyEntries.isEmpty() ) {
return new SourceRHS( sourceParam.getName(), getSourceType(), existingVariableNames );
}
// simple property
else if ( propertyEntries.size() == 1 ) {
PropertyEntry propertyEntry = propertyEntries.get( 0 );
String sourceRef = sourceParam.getName() + "." + ValueProvider.of( propertyEntry.getReadAccessor() );
return new SourceRHS( sourceRef, propertyEntry.getType(), existingVariableNames );
}
// nested property given as dot path
else {
// copy mapper configuration from the source method, its the same mapper
MapperConfiguration config = method.getMapperConfiguration();
// forge a method from the parameter type to the last entry type.
String forgedName = Strings.joinAndCamelize( sourceReference.getElementNames() );
forgedName = Strings.getSaveVariableName( forgedName, ctx.getNamesOfMappingsToGenerate() );
ForgedMethod methodRef = new ForgedMethod(
forgedName,
sourceReference.getParameter().getType(),
getSourceType(),
config,
method.getExecutable()
ForgedMethod methodRef = new ForgedMethod( forgedName,
sourceReference.getParameter().getType(),
sourceType,
config,
method.getExecutable()
);
NestedPropertyMappingMethod.Builder builder = new NestedPropertyMappingMethod.Builder();
NestedPropertyMappingMethod nestedPropertyMapping = builder
@ -553,36 +541,24 @@ public class PropertyMapping extends ModelElement {
forgedName = ctx.getExistingMappingMethod( nestedPropertyMapping ).getName();
}
String sourceRef = forgedName + "( " + sourceParam.getName() + " )";
return new SourceRHS( sourceRef, getSourceType(), existingVariableNames );
}
}
private String getSourceElement() {
Parameter sourceParam = sourceReference.getParameter();
List<PropertyEntry> propertyEntries = sourceReference.getPropertyEntries();
if ( propertyEntries.isEmpty() ) {
return String.format( "parameter \"%s %s\"", sourceParam.getType(), sourceParam.getName() );
}
else if ( propertyEntries.size() == 1 ) {
PropertyEntry propertyEntry = propertyEntries.get( 0 );
return String.format( "property \"%s %s\"", propertyEntry.getType(), propertyEntry.getName() );
}
else {
PropertyEntry lastPropertyEntry = propertyEntries.get( propertyEntries.size() - 1 );
return String.format(
"property \"%s %s\"",
lastPropertyEntry.getType(),
Strings.join( sourceReference.getElementNames(), "." )
SourceRHS sourceRhs = new SourceRHS( sourceParam.getName(),
sourceRef,
getSourcePresenceCheckerRef( sourceReference ),
sourceType,
existingVariableNames,
sourceReference.toString()
);
return sourceRhs;
}
}
private String getSourcePresenceCheckerRef() {
private String getSourcePresenceCheckerRef( SourceReference sourceReference ) {
String sourcePresenceChecker = null;
if ( !sourceReference.getPropertyEntries().isEmpty() ) {
Parameter sourceParam = sourceReference.getParameter();
// TODO is first correct here?? shouldn't it be last since the remainer is checked
// in the forged method?
PropertyEntry propertyEntry = first( sourceReference.getPropertyEntries() );
if ( propertyEntry.getPresenceChecker() != null ) {
sourcePresenceChecker = sourceParam.getName()
@ -699,19 +675,18 @@ public class PropertyMapping extends ModelElement {
public PropertyMapping build() {
// source
String mappedElement = "constant '" + constantExpression + "'";
String sourceErrorMessagePart = "constant '" + constantExpression + "'";
Type sourceType = ctx.getTypeFactory().getType( String.class );
Assignment assignment = null;
if ( !targetType.isEnumType() ) {
assignment = ctx.getMappingResolver().getTargetAssignment(
method,
mappedElement,
targetType,
targetPropertyName,
formattingParameters,
selectionParameters,
new SourceRHS( constantExpression, sourceType, existingVariableNames ),
new SourceRHS( constantExpression, sourceType, existingVariableNames, sourceErrorMessagePart ),
method.getMappingTargetParameter() != null
);
}
@ -780,7 +755,8 @@ public class PropertyMapping extends ModelElement {
// String String quotation marks.
String enumExpression = constantExpression.substring( 1, constantExpression.length() - 1 );
if ( targetType.getEnumConstants().contains( enumExpression ) ) {
assignment = new SourceRHS( enumExpression, targetType, existingVariableNames );
String sourceErrorMessagePart = "constant '" + constantExpression + "'";
assignment = new SourceRHS( enumExpression, targetType, existingVariableNames, sourceErrorMessagePart );
assignment = new EnumConstantWrapper( assignment, targetType );
}
else {
@ -806,7 +782,7 @@ public class PropertyMapping extends ModelElement {
}
public PropertyMapping build() {
Assignment assignment = new SourceRHS( javaExpression, null, existingVariableNames );
Assignment assignment = new SourceRHS( javaExpression, null, existingVariableNames, "" );
if ( Executables.isSetterMethod( targetWriteAccessor ) ||
Executables.isFieldAccessor( targetWriteAccessor ) ) {

View File

@ -30,6 +30,8 @@ import org.mapstruct.ap.internal.util.Strings;
/**
* SourceRHS Assignment. Right Hand Side (RHS), source part of the assignment.
*
* This class contains all information on the source side of an assignment needed for common use in the mapping.
*
* @author Sjaak Derksen
*/
public class SourceRHS extends ModelElement implements Assignment {
@ -38,11 +40,24 @@ public class SourceRHS extends ModelElement implements Assignment {
private final Type sourceType;
private String sourceLocalVarName;
private final Set<String> existingVariableNames;
private final String sourceErrorMessagePart;
private final String sourcePresenceCheckerReference;
private boolean useElementAsSourceTypeForMatching = false;
private final String sourceParameterName;
public SourceRHS(String sourceReference, Type sourceType, Set<String> existingVariableNames ) {
public SourceRHS(String sourceReference, Type sourceType, Set<String> existingVariableNames,
String sourceErrorMessagePart ) {
this( null, sourceReference, null, sourceType, existingVariableNames, sourceErrorMessagePart );
}
public SourceRHS(String sourceParameterName, String sourceReference, String sourcePresenceCheckerReference,
Type sourceType, Set<String> existingVariableNames, String sourceErrorMessagePart ) {
this.sourceReference = sourceReference;
this.sourceType = sourceType;
this.existingVariableNames = existingVariableNames;
this.sourceErrorMessagePart = sourceErrorMessagePart;
this.sourcePresenceCheckerReference = sourcePresenceCheckerReference;
this.sourceParameterName = sourceParameterName;
}
@Override
@ -50,6 +65,11 @@ public class SourceRHS extends ModelElement implements Assignment {
return sourceReference;
}
@Override
public String getSourcePresenceCheckerReference() {
return sourcePresenceCheckerReference;
}
@Override
public Type getSourceType() {
return sourceType;
@ -99,4 +119,32 @@ public class SourceRHS extends ModelElement implements Assignment {
public String toString() {
return sourceReference;
}
public String getSourceErrorMessagePart() {
return sourceErrorMessagePart;
}
/**
* The source type that is to be used when resolving the mapping from source to target.
*
* @return the source type to be used in the matching process.
*/
public Type getSourceTypeForMatching() {
return useElementAsSourceTypeForMatching && sourceType.isCollectionType() ?
sourceType.getTypeParameters().get( 0 ) : sourceType;
}
/**
* For collection type, use element as source type to find a suitable mapping method.
*
* @param useElementAsSourceTypeForMatching
*/
public void setUseElementAsSourceTypeForMatching(boolean useElementAsSourceTypeForMatching) {
this.useElementAsSourceTypeForMatching = useElementAsSourceTypeForMatching;
}
public String getSourceParameterName() {
return sourceParameterName;
}
}

View File

@ -86,6 +86,11 @@ public class TypeConversion extends ModelElement implements Assignment {
return assignment.getSourceReference();
}
@Override
public String getSourcePresenceCheckerReference() {
return assignment.getSourcePresenceCheckerReference();
}
@Override
public Type getSourceType() {
return assignment.getSourceType();

View File

@ -38,8 +38,8 @@ public class AdderWrapper extends AssignmentWrapper {
public AdderWrapper( Assignment decoratedAssignment, List<Type> thrownTypesToExclude, boolean fieldAssignment ) {
super( decoratedAssignment, fieldAssignment );
this.thrownTypesToExclude = thrownTypesToExclude;
this.sourceIteratorName =
decoratedAssignment.createLocalVarName( decoratedAssignment.getSourceType().getName() );
String desiredName = decoratedAssignment.getSourceType().getTypeParameters().get( 0 ).getName();
this.sourceIteratorName = decoratedAssignment.createLocalVarName( desiredName );
decoratedAssignment.setSourceLocalVarName( sourceIteratorName );
}
@ -61,7 +61,7 @@ public class AdderWrapper extends AssignmentWrapper {
public Set<Type> getImportTypes() {
Set<Type> imported = new HashSet<Type>();
imported.addAll( super.getImportTypes() );
imported.add( getSourceType() );
imported.add( getSourceType().getTypeParameters().get( 0 ) );
return imported;
}

View File

@ -77,6 +77,13 @@ public interface Assignment {
*/
String getSourceReference();
/**
* the source presence checker reference
*
* @return source reference
*/
String getSourcePresenceCheckerReference();
/**
* the source type used in the matching process
*

View File

@ -63,6 +63,11 @@ public abstract class AssignmentWrapper extends ModelElement implements Assignme
return decoratedAssignment.getSourceReference();
}
@Override
public String getSourcePresenceCheckerReference() {
return decoratedAssignment.getSourcePresenceCheckerReference();
}
@Override
public Type getSourceType() {
return decoratedAssignment.getSourceType();

View File

@ -39,17 +39,14 @@ import org.mapstruct.ap.internal.model.common.Type;
public class GetterWrapperForCollectionsAndMaps extends WrapperForCollectionsAndMaps {
/**
* constructor for property mapping
*
* @param decoratedAssignment
* @param thrownTypesToExclude
* @param sourcePresenceChecker
* @param existingVariableNames
* @param targetType
* @param fieldAssignment
*/
public GetterWrapperForCollectionsAndMaps(Assignment decoratedAssignment,
List<Type> thrownTypesToExclude,
String sourcePresenceChecker,
Set<String> existingVariableNames,
Type targetType,
boolean fieldAssignment) {
@ -57,28 +54,10 @@ public class GetterWrapperForCollectionsAndMaps extends WrapperForCollectionsAnd
super(
decoratedAssignment,
thrownTypesToExclude,
sourcePresenceChecker,
existingVariableNames,
targetType,
fieldAssignment
);
}
/**
* constructor for e.g. constants and expressions
*
* @param decoratedAssignment
* @param thrownTypesToExclude
* @param existingVariableNames
* @param targetType
*/
public GetterWrapperForCollectionsAndMaps(Assignment decoratedAssignment,
List<Type> thrownTypesToExclude,
Set<String> existingVariableNames,
Type targetType,
boolean fieldAssignment) {
super( decoratedAssignment, thrownTypesToExclude, null, existingVariableNames, targetType, fieldAssignment );
}
}

View File

@ -25,14 +25,8 @@ package org.mapstruct.ap.internal.model.assignment;
*/
public class NullCheckWrapper extends AssignmentWrapper {
private final String sourcePresenceChecker;
public NullCheckWrapper( Assignment decoratedAssignment, String sourcePresenceChecker ) {
public NullCheckWrapper( Assignment decoratedAssignment ) {
super( decoratedAssignment, false );
this.sourcePresenceChecker = sourcePresenceChecker;
}
public String getSourcePresenceChecker() {
return sourcePresenceChecker;
}
}

View File

@ -47,7 +47,6 @@ public class SetterWrapperForCollectionsAndMaps extends WrapperForCollectionsAnd
public SetterWrapperForCollectionsAndMaps(Assignment decoratedAssignment,
List<Type> thrownTypesToExclude,
String sourcePresenceChecker,
Set<String> existingVariableNames,
Type targetType,
boolean allwaysIncludeNullCheck,
@ -57,7 +56,6 @@ public class SetterWrapperForCollectionsAndMaps extends WrapperForCollectionsAnd
super(
decoratedAssignment,
thrownTypesToExclude,
sourcePresenceChecker,
existingVariableNames,
targetType,
fieldAssignment
@ -97,8 +95,4 @@ public class SetterWrapperForCollectionsAndMaps extends WrapperForCollectionsAnd
return "java.util.EnumSet".equals( targetType.getFullyQualifiedName() );
}
public boolean isFieldAssignment() {
return fieldAssignment;
}
}

View File

@ -26,16 +26,8 @@ package org.mapstruct.ap.internal.model.assignment;
*/
public class UpdateNullCheckWrapper extends AssignmentWrapper {
private final String sourcePresenceChecker;
public UpdateNullCheckWrapper(Assignment decoratedAssignment, String sourcePresenceChecker,
boolean fieldAssignment) {
public UpdateNullCheckWrapper(Assignment decoratedAssignment, boolean fieldAssignment) {
super( decoratedAssignment, fieldAssignment );
this.sourcePresenceChecker = sourcePresenceChecker;
}
public String getSourcePresenceChecker() {
return sourcePresenceChecker;
}
}

View File

@ -35,13 +35,11 @@ import org.mapstruct.ap.internal.util.Strings;
public class WrapperForCollectionsAndMaps extends AssignmentWrapper {
private final List<Type> thrownTypesToExclude;
private final String sourcePresenceChecker;
private final String localVarName;
private final Type localVarType;
public WrapperForCollectionsAndMaps(Assignment decoratedAssignment,
List<Type> thrownTypesToExclude,
String sourcePresenceChecker,
Set<String> existingVariableNames,
Type targetType,
boolean fieldAssignment) {
@ -49,7 +47,6 @@ public class WrapperForCollectionsAndMaps extends AssignmentWrapper {
super( decoratedAssignment, fieldAssignment );
this.thrownTypesToExclude = thrownTypesToExclude;
this.sourcePresenceChecker = sourcePresenceChecker;
if ( getType() == AssignmentType.DIRECT && getSourceType() != null ) {
this.localVarType = getSourceType();
}
@ -83,10 +80,6 @@ public class WrapperForCollectionsAndMaps extends AssignmentWrapper {
return imported;
}
public String getSourcePresenceChecker() {
return sourcePresenceChecker;
}
public String getLocalVarName() {
return localVarName;
}

View File

@ -296,4 +296,25 @@ public class SourceReference {
return new SourceReference( replacement, propertyEntries, isValid );
}
@Override
public String toString() {
if ( propertyEntries.isEmpty() ) {
return String.format( "parameter \"%s %s\"", getParameter().getType(), getParameter().getName() );
}
else if ( propertyEntries.size() == 1 ) {
PropertyEntry propertyEntry = propertyEntries.get( 0 );
return String.format( "property \"%s %s\"", propertyEntry.getType(), propertyEntry.getName() );
}
else {
PropertyEntry lastPropertyEntry = propertyEntries.get( propertyEntries.size() - 1 );
return String.format(
"property \"%s %s\"",
lastPropertyEntry.getType(),
Strings.join( getElementNames(), "." )
);
}
}
}

View File

@ -104,10 +104,9 @@ public class MappingResolverImpl implements MappingResolver {
}
@Override
@SuppressWarnings("checkstyle:parameternumber")
public Assignment getTargetAssignment(Method mappingMethod, String mappedElement,
Type targetType, String targetPropertyName, FormattingParameters formattingParameters,
SelectionParameters selectionParameters, SourceRHS sourceRHS, boolean preferUpdateMapping) {
public Assignment getTargetAssignment(Method mappingMethod, Type targetType, String targetPropertyName,
FormattingParameters formattingParameters, SelectionParameters selectionParameters, SourceRHS sourceRHS,
boolean preferUpdateMapping) {
SelectionCriteria criteria =
new SelectionCriteria( selectionParameters, targetPropertyName, preferUpdateMapping, false );
@ -122,14 +121,13 @@ public class MappingResolverImpl implements MappingResolver {
ResolvingAttempt attempt = new ResolvingAttempt(
sourceModel,
mappingMethod,
mappedElement,
dateFormat,
numberFormat,
sourceRHS,
criteria
);
return attempt.getTargetAssignment( sourceRHS.getSourceType(), targetType );
return attempt.getTargetAssignment( sourceRHS.getSourceTypeForMatching(), targetType );
}
@Override
@ -143,7 +141,7 @@ public class MappingResolverImpl implements MappingResolver {
SelectionCriteria criteria = new SelectionCriteria( selectionParameters, null, false, true );
ResolvingAttempt attempt = new ResolvingAttempt( sourceModel, mappingMethod, null, null, null, null, criteria );
ResolvingAttempt attempt = new ResolvingAttempt( sourceModel, mappingMethod, null, null, null, criteria );
List<SourceMethod> matchingSourceMethods = attempt.getMatches( sourceModel, null, targetType );
@ -199,7 +197,6 @@ public class MappingResolverImpl implements MappingResolver {
private class ResolvingAttempt {
private final Method mappingMethod;
private final String mappedElement;
private final List<SourceMethod> methods;
private final String dateFormat;
private final String numberFormat;
@ -212,12 +209,10 @@ public class MappingResolverImpl implements MappingResolver {
// so this set must be cleared.
private final Set<VirtualMappingMethod> virtualMethodCandidates;
private ResolvingAttempt(List<SourceMethod> sourceModel, Method mappingMethod, String mappedElement,
String dateFormat, String numberFormat, SourceRHS sourceRHS, SelectionCriteria criteria) {
private ResolvingAttempt(List<SourceMethod> sourceModel, Method mappingMethod, String dateFormat,
String numberFormat, SourceRHS sourceRHS, SelectionCriteria criteria) {
this.mappingMethod = mappingMethod;
this.mappedElement = mappedElement;
this.methods = filterPossibleCandidateMethods( sourceModel );
this.dateFormat = dateFormat;
this.numberFormat = numberFormat;
@ -520,10 +515,10 @@ public class MappingResolverImpl implements MappingResolver {
// into the target type
if ( candidates.size() > 1 ) {
if ( mappedElement != null ) {
if ( sourceRHS.getSourceErrorMessagePart() != null ) {
messager.printMessage( mappingMethod.getExecutable(),
Message.GENERAL_AMBIGIOUS_MAPPING_METHOD,
mappedElement,
sourceRHS.getSourceErrorMessagePart(),
returnType,
Strings.join( candidates, ", " )
);

View File

@ -21,7 +21,7 @@
<#import "../macro/CommonMacros.ftl" as lib>
<@lib.handleExceptions>
if ( ${sourceReference} != null ) {
for ( <@includeModel object=sourceType/> ${sourceIteratorName} : ${sourceReference} ) {
for ( <@includeModel object=sourceType.typeParameters[0]/> ${sourceIteratorName} : ${sourceReference} ) {
${ext.targetBeanName}.${ext.targetWriteAccessorName}<@lib.handleWrite><@lib.handleAssignment/></@lib.handleWrite>;
}
}

View File

@ -25,7 +25,7 @@ if ( ${sourceLocalVarName} != null ) {
<@_assignment object=assignment defaultValue=ext.defaultValueAssignment/>
}
<#else>
if ( <#if sourcePresenceChecker?? >${sourcePresenceChecker}<#else>${sourceReference} != null</#if> ) {
if ( <#if sourcePresenceCheckerReference?? >${sourcePresenceCheckerReference}<#else>${sourceReference} != null</#if> ) {
<@_assignment object=assignment defaultValue=ext.defaultValueAssignment/>
}
</#if>

View File

@ -26,7 +26,7 @@
${ext.targetBeanName}.${ext.targetReadAccessorName}.clear();
${ext.targetBeanName}.${ext.targetReadAccessorName}.<#if ext.targetType.collectionType>addAll<#else>putAll</#if>( ${localVarName} );
</@lib.handleNullCheck>
<#if !ext.defaultValueAssignment?? && !sourcePresenceChecker?? && !allwaysIncludeNullCheck>else {<#-- the opposite (defaultValueAssignment) case is handeld inside lib.handleNullCheck -->
<#if !ext.defaultValueAssignment?? && !sourcePresenceCheckerReference?? && !allwaysIncludeNullCheck>else {<#-- the opposite (defaultValueAssignment) case is handeld inside lib.handleNullCheck -->
${ext.targetBeanName}.${ext.targetWriteAccessorName}<@lib.handleWrite>null</@lib.handleWrite>;
}
</#if>
@ -55,4 +55,4 @@
<#else>
new <#if ext.targetType.implementationType??><@includeModel object=ext.targetType.implementationType/><#else><@includeModel object=ext.targetType/></#if>( ${localVarName} )
</#if>
</@compress></#macro>
</@compress></#macro>

View File

@ -19,7 +19,7 @@
-->
<#import '../macro/CommonMacros.ftl' as lib>
if ( <#if sourcePresenceChecker?? >${sourcePresenceChecker}<#else>${sourceReference} != null</#if> ) {
if ( <#if sourcePresenceCheckerReference?? >${sourcePresenceCheckerReference}<#else>${sourceReference} != null</#if> ) {
<@includeModel object=assignment
targetBeanName=ext.targetBeanName
existingInstanceMapping=ext.existingInstanceMapping

View File

@ -28,8 +28,8 @@
present.
-->
<#macro handleNullCheck>
<#if sourcePresenceChecker??>
if ( ${sourcePresenceChecker} ) {
<#if sourcePresenceCheckerReference??>
if ( ${sourcePresenceCheckerReference} ) {
<@includeModel object=localVarType/> ${localVarName} = <@lib.handleAssignment/>;
<#nested>
}