org.mapstruct.ap.internal.model.CollectionAssignmentBuilder Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of mapstruct-processor Show documentation
Show all versions of mapstruct-processor Show documentation
An annotation processor for generating type-safe bean mappers
/*
* Copyright MapStruct Authors.
*
* Licensed under the Apache License version 2.0, available at http://www.apache.org/licenses/LICENSE-2.0
*/
package org.mapstruct.ap.internal.model;
import org.mapstruct.ap.internal.model.assignment.ExistingInstanceSetterWrapperForCollectionsAndMaps;
import org.mapstruct.ap.internal.model.assignment.GetterWrapperForCollectionsAndMaps;
import org.mapstruct.ap.internal.model.assignment.SetterWrapperForCollectionsAndMaps;
import org.mapstruct.ap.internal.model.assignment.SetterWrapperForCollectionsAndMapsWithNullCheck;
import org.mapstruct.ap.internal.model.assignment.UpdateWrapper;
import org.mapstruct.ap.internal.model.common.Assignment;
import org.mapstruct.ap.internal.model.common.SourceRHS;
import org.mapstruct.ap.internal.model.common.Type;
import org.mapstruct.ap.internal.model.source.Method;
import org.mapstruct.ap.internal.model.source.SelectionParameters;
import org.mapstruct.ap.internal.gem.CollectionMappingStrategyGem;
import org.mapstruct.ap.internal.gem.NullValueCheckStrategyGem;
import org.mapstruct.ap.internal.gem.NullValuePropertyMappingStrategyGem;
import org.mapstruct.ap.internal.util.Message;
import org.mapstruct.ap.internal.util.accessor.Accessor;
import org.mapstruct.ap.internal.util.accessor.AccessorType;
import static org.mapstruct.ap.internal.gem.NullValuePropertyMappingStrategyGem.SET_TO_DEFAULT;
import static org.mapstruct.ap.internal.gem.NullValuePropertyMappingStrategyGem.SET_TO_NULL;
/**
* A builder that is used for creating an assignment to a collection.
*
* The created assignments to the following null checks:
*
* - source-null-check - For this the {@link SetterWrapperForCollectionsAndMapsWithNullCheck} is used when a
* direct assignment is done or the {@link org.mapstruct.NullValueCheckStrategy} is
* {@link org.mapstruct.NullValueCheckStrategy#ALWAYS}. It is also done in
* {@link ExistingInstanceSetterWrapperForCollectionsAndMaps} which extends
* {@link SetterWrapperForCollectionsAndMapsWithNullCheck}
* - target-null-check - Done in the {@link ExistingInstanceSetterWrapperForCollectionsAndMaps}
* - local-var-null-check - Done in {@link ExistingInstanceSetterWrapperForCollectionsAndMaps}, and
* {@link SetterWrapperForCollectionsAndMapsWithNullCheck}
*
*
* A local-var-null-check is needed in the following cases:
*
*
* - Presence check with direct assignment - We need a null check before setting, because we use the copy
* constructor
* - Presence check for existing instance mapping - We need the null check because we call addAll / putAll.
* - No Presence check and direct assignment - We use the copy constructor
* - No Presence check and {@link org.mapstruct.NullValueCheckStrategy#ALWAYS} - the user requested one
*
*
* @author Filip Hrisafov
*/
public class CollectionAssignmentBuilder {
private MappingBuilderContext ctx;
private Method method;
private Accessor targetReadAccessor;
private Type targetType;
private String targetPropertyName;
private AccessorType targetAccessorType;
private Assignment assignment;
private SourceRHS sourceRHS;
private NullValueCheckStrategyGem nvcs;
private NullValuePropertyMappingStrategyGem nvpms;
public CollectionAssignmentBuilder mappingBuilderContext(MappingBuilderContext ctx) {
this.ctx = ctx;
return this;
}
public CollectionAssignmentBuilder method(Method method) {
this.method = method;
return this;
}
public CollectionAssignmentBuilder targetReadAccessor(Accessor targetReadAccessor) {
this.targetReadAccessor = targetReadAccessor;
return this;
}
public CollectionAssignmentBuilder targetType(Type targetType) {
this.targetType = targetType;
return this;
}
public CollectionAssignmentBuilder targetPropertyName(String targetPropertyName) {
this.targetPropertyName = targetPropertyName;
return this;
}
public CollectionAssignmentBuilder targetAccessorType(AccessorType targetAccessorType) {
this.targetAccessorType = targetAccessorType;
return this;
}
/**
* @param assignment the assignment that needs to be invoked
*
* @return this builder for chaining
*/
public CollectionAssignmentBuilder assignment(Assignment assignment) {
this.assignment = assignment;
return this;
}
/**
* @param sourceRHS the source right hand side for getting the property for mapping
*
* @return this builder for chaining
*/
public CollectionAssignmentBuilder rightHandSide(SourceRHS sourceRHS) {
this.sourceRHS = sourceRHS;
return this;
}
public CollectionAssignmentBuilder nullValueCheckStrategy( NullValueCheckStrategyGem nvcs ) {
this.nvcs = nvcs;
return this;
}
public CollectionAssignmentBuilder nullValuePropertyMappingStrategy( NullValuePropertyMappingStrategyGem nvpms ) {
this.nvpms = nvpms;
return this;
}
public Assignment build() {
Assignment result = assignment;
CollectionMappingStrategyGem cms = method.getOptions().getMapper().getCollectionMappingStrategy();
boolean targetImmutable = cms == CollectionMappingStrategyGem.TARGET_IMMUTABLE || targetReadAccessor == null;
if ( targetAccessorType == AccessorType.SETTER || targetAccessorType.isFieldAssignment() ) {
if ( result.isCallingUpdateMethod() && !targetImmutable ) {
// call to an update method
if ( targetReadAccessor == null ) {
ctx.getMessager().printMessage(
method.getExecutable(),
Message.PROPERTYMAPPING_NO_READ_ACCESSOR_FOR_TARGET_TYPE,
targetPropertyName
);
}
Assignment factoryMethod = ObjectFactoryMethodResolver
.getFactoryMethod( method, targetType, SelectionParameters.forSourceRHS( sourceRHS ), ctx );
result = new UpdateWrapper(
result,
method.getThrownTypes(),
factoryMethod,
targetAccessorType.isFieldAssignment(),
targetType,
true,
nvpms == SET_TO_NULL && !targetType.isPrimitive(),
nvpms == SET_TO_DEFAULT
);
}
else if ( method.isUpdateMethod() && !targetImmutable ) {
result = new ExistingInstanceSetterWrapperForCollectionsAndMaps(
result,
method.getThrownTypes(),
targetType,
nvcs,
nvpms,
ctx.getTypeFactory(),
targetAccessorType.isFieldAssignment()
);
}
else if ( result.getType() == Assignment.AssignmentType.DIRECT ||
nvcs == NullValueCheckStrategyGem.ALWAYS ) {
result = new SetterWrapperForCollectionsAndMapsWithNullCheck(
result,
method.getThrownTypes(),
targetType,
ctx.getTypeFactory(),
targetAccessorType.isFieldAssignment()
);
}
else {
//TODO init default value
// target accessor is setter, so wrap the setter in setter map/ collection handling
result = new SetterWrapperForCollectionsAndMaps(
result,
method.getThrownTypes(),
targetType,
targetAccessorType.isFieldAssignment()
);
}
}
else {
if ( targetImmutable ) {
ctx.getMessager().printMessage(
method.getExecutable(),
Message.PROPERTYMAPPING_NO_WRITE_ACCESSOR_FOR_TARGET_TYPE,
targetPropertyName
);
}
// target accessor is getter, so wrap the setter in getter map/ collection handling
result = new GetterWrapperForCollectionsAndMaps(
result,
method.getThrownTypes(),
targetType,
targetAccessorType.isFieldAssignment()
);
}
return result;
}
}