mirror of
https://github.com/mapstruct/mapstruct.git
synced 2025-07-12 00:00:08 +08:00
#981 Refactoring, move SourceRHS init to start of property build.
This commit is contained in:
parent
0ec9729801
commit
81a4cb360d
@ -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
|
||||
);
|
||||
|
||||
|
@ -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
|
||||
);
|
||||
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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();
|
||||
|
@ -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 ) ) {
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -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();
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
*
|
||||
|
@ -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();
|
||||
|
@ -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 );
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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(), "." )
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -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, ", " )
|
||||
);
|
||||
|
@ -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>;
|
||||
}
|
||||
}
|
||||
|
@ -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>
|
||||
|
@ -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>
|
@ -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
|
||||
|
@ -28,8 +28,8 @@
|
||||
present.
|
||||
-->
|
||||
<#macro handleNullCheck>
|
||||
<#if sourcePresenceChecker??>
|
||||
if ( ${sourcePresenceChecker} ) {
|
||||
<#if sourcePresenceCheckerReference??>
|
||||
if ( ${sourcePresenceCheckerReference} ) {
|
||||
<@includeModel object=localVarType/> ${localVarName} = <@lib.handleAssignment/>;
|
||||
<#nested>
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user