mirror of
https://github.com/mapstruct/mapstruct.git
synced 2025-07-12 00:00:08 +08:00
#891 Implementation and unit test
This commit is contained in:
parent
ecd6411f93
commit
750af10900
@ -50,8 +50,5 @@ public class AssignmentFactory {
|
|||||||
return new MethodReference( method, contextParam );
|
return new MethodReference( method, contextParam );
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Direct createDirect(String sourceRef) {
|
|
||||||
return new Direct( sourceRef );
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -34,9 +34,12 @@ import org.mapstruct.ap.internal.model.common.Type;
|
|||||||
public class Direct extends ModelElement implements Assignment {
|
public class Direct extends ModelElement implements Assignment {
|
||||||
|
|
||||||
private final String sourceReference;
|
private final String sourceReference;
|
||||||
|
private final Type sourceType;
|
||||||
|
private String sourceLocalVarName;
|
||||||
|
|
||||||
public Direct( String sourceReference ) {
|
public Direct(String sourceReference, Type sourceType ) {
|
||||||
this.sourceReference = sourceReference;
|
this.sourceReference = sourceReference;
|
||||||
|
this.sourceType = sourceType;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -44,6 +47,21 @@ public class Direct extends ModelElement implements Assignment {
|
|||||||
return sourceReference;
|
return sourceReference;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Type getSourceType() {
|
||||||
|
return sourceType;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getSourceLocalVarName() {
|
||||||
|
return sourceLocalVarName;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setSourceLocalVarName(String sourceLocalVarName) {
|
||||||
|
this.sourceLocalVarName = sourceLocalVarName;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Set<Type> getImportTypes() {
|
public Set<Type> getImportTypes() {
|
||||||
return Collections.emptySet();
|
return Collections.emptySet();
|
||||||
|
@ -108,7 +108,7 @@ public class IterableMappingMethod extends MappingMethod {
|
|||||||
null, // there is no targetPropertyName
|
null, // there is no targetPropertyName
|
||||||
formattingParameters,
|
formattingParameters,
|
||||||
selectionParameters,
|
selectionParameters,
|
||||||
loopVariableName,
|
new Direct( loopVariableName, sourceElementType ),
|
||||||
false
|
false
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -111,7 +111,7 @@ public class MapMappingMethod extends MappingMethod {
|
|||||||
null, // there is no targetPropertyName
|
null, // there is no targetPropertyName
|
||||||
keyFormattingParameters,
|
keyFormattingParameters,
|
||||||
keySelectionParameters,
|
keySelectionParameters,
|
||||||
"entry.getKey()",
|
new Direct( "entry.getKey()", keySourceType ),
|
||||||
false
|
false
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -138,7 +138,7 @@ public class MapMappingMethod extends MappingMethod {
|
|||||||
null, // there is no targetPropertyName
|
null, // there is no targetPropertyName
|
||||||
valueFormattingParameters,
|
valueFormattingParameters,
|
||||||
valueSelectionParameters,
|
valueSelectionParameters,
|
||||||
"entry.getValue()",
|
new Direct( "entry.getValue()", valueSourceType ),
|
||||||
false
|
false
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -81,7 +81,7 @@ public class MappingBuilderContext {
|
|||||||
* @param targetPropertyName name of the target property
|
* @param targetPropertyName name of the target property
|
||||||
* @param formattingParameters used for formatting dates and numbers
|
* @param formattingParameters used for formatting dates and numbers
|
||||||
* @param selectionParameters parameters used in the selection process
|
* @param selectionParameters parameters used in the selection process
|
||||||
* @param sourceReference call to source type as string
|
* @param sourceReference source information
|
||||||
* @param preferUpdateMethods selection should prefer update methods when present.
|
* @param preferUpdateMethods selection should prefer update methods when present.
|
||||||
*
|
*
|
||||||
* @return an assignment to a method parameter, which can either be:
|
* @return an assignment to a method parameter, which can either be:
|
||||||
@ -95,7 +95,7 @@ public class MappingBuilderContext {
|
|||||||
@SuppressWarnings("checkstyle:parameternumber")
|
@SuppressWarnings("checkstyle:parameternumber")
|
||||||
Assignment getTargetAssignment(Method mappingMethod, String mappedElement, Type sourceType, Type targetType,
|
Assignment getTargetAssignment(Method mappingMethod, String mappedElement, Type sourceType, Type targetType,
|
||||||
String targetPropertyName, FormattingParameters formattingParameters,
|
String targetPropertyName, FormattingParameters formattingParameters,
|
||||||
SelectionParameters selectionParameters, String sourceReference,
|
SelectionParameters selectionParameters, Direct sourceReference,
|
||||||
boolean preferUpdateMethods);
|
boolean preferUpdateMethods);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -128,6 +128,21 @@ public class MethodReference extends MappingMethod implements Assignment {
|
|||||||
return assignment.getSourceReference();
|
return assignment.getSourceReference();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Type getSourceType() {
|
||||||
|
return assignment.getSourceType();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getSourceLocalVarName() {
|
||||||
|
return assignment.getSourceLocalVarName();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setSourceLocalVarName(String sourceLocalVarName) {
|
||||||
|
assignment.setSourceLocalVarName( sourceLocalVarName );
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return the type of the single source parameter that is not the {@code @TargetType} parameter
|
* @return the type of the single source parameter that is not the {@code @TargetType} parameter
|
||||||
*/
|
*/
|
||||||
|
@ -216,15 +216,15 @@ public class PropertyMapping extends ModelElement {
|
|||||||
// handle source
|
// handle source
|
||||||
String sourceElement = getSourceElement();
|
String sourceElement = getSourceElement();
|
||||||
Type sourceType = getSourceType();
|
Type sourceType = getSourceType();
|
||||||
String sourceRefStr;
|
Direct source;
|
||||||
if ( targetWriteAccessorType == TargetWriteAccessorType.ADDER && sourceType.isCollectionType() ) {
|
if ( targetWriteAccessorType == TargetWriteAccessorType.ADDER && sourceType.isCollectionType() ) {
|
||||||
// handle adder, if source is collection then use iterator element type as source type.
|
// handle adder, if source is collection then use iterator element type as source type.
|
||||||
// sourceRef becomes a local variable in the itereation.
|
// sourceRef becomes a local variable in the itereation.
|
||||||
sourceType = sourceType.getTypeParameters().get( 0 );
|
sourceType = sourceType.getTypeParameters().get( 0 );
|
||||||
sourceRefStr = Executables.getElementNameForAdder( targetWriteAccessor );
|
source = new Direct( Executables.getElementNameForAdder( targetWriteAccessor ), sourceType );
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
sourceRefStr = getSourceRef();
|
source = getSource();
|
||||||
}
|
}
|
||||||
|
|
||||||
// all the tricky cases will be excluded for the time being.
|
// all the tricky cases will be excluded for the time being.
|
||||||
@ -244,17 +244,17 @@ public class PropertyMapping extends ModelElement {
|
|||||||
targetPropertyName,
|
targetPropertyName,
|
||||||
formattingParameters,
|
formattingParameters,
|
||||||
selectionParameters,
|
selectionParameters,
|
||||||
sourceRefStr,
|
source,
|
||||||
preferUpdateMethods
|
preferUpdateMethods
|
||||||
);
|
);
|
||||||
|
|
||||||
// No mapping found. Try to forge a mapping
|
// No mapping found. Try to forge a mapping
|
||||||
if ( assignment == null ) {
|
if ( assignment == null ) {
|
||||||
if ( (sourceType.isCollectionType() || sourceType.isArrayType()) && targetType.isIterableType() ) {
|
if ( (sourceType.isCollectionType() || sourceType.isArrayType()) && targetType.isIterableType() ) {
|
||||||
assignment = forgeIterableMapping( sourceType, targetType, sourceRefStr, method.getExecutable() );
|
assignment = forgeIterableMapping( sourceType, targetType, source, method.getExecutable() );
|
||||||
}
|
}
|
||||||
else if ( sourceType.isMapType() && targetType.isMapType() ) {
|
else if ( sourceType.isMapType() && targetType.isMapType() ) {
|
||||||
assignment = forgeMapMapping( sourceType, targetType, sourceRefStr, method.getExecutable() );
|
assignment = forgeMapMapping( sourceType, targetType, source, method.getExecutable() );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -354,12 +354,6 @@ public class PropertyMapping extends ModelElement {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
// a nested source reference will take the bean mapping parameter itself, no null check is required
|
|
||||||
// since this is handled by the BeanMapping
|
|
||||||
if ( sourceReference.getPropertyEntries().size() > 1 ) {
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
// add a null / presence checked when required
|
// add a null / presence checked when required
|
||||||
if ( sourceType.isPrimitive() ) {
|
if ( sourceType.isPrimitive() ) {
|
||||||
if ( getSourcePresenceCheckerRef() != null ) {
|
if ( getSourcePresenceCheckerRef() != null ) {
|
||||||
@ -376,6 +370,7 @@ public class PropertyMapping extends ModelElement {
|
|||||||
}
|
}
|
||||||
else if ( ALWAYS.equals( method.getMapperConfiguration().getNullValueCheckStrategy() ) ) {
|
else if ( ALWAYS.equals( method.getMapperConfiguration().getNullValueCheckStrategy() ) ) {
|
||||||
result = new NullCheckWrapper( result, getSourcePresenceCheckerRef() );
|
result = new NullCheckWrapper( result, getSourcePresenceCheckerRef() );
|
||||||
|
useLocalVarWhenNested( result );
|
||||||
}
|
}
|
||||||
else if ( result.getType() == TYPE_CONVERTED
|
else if ( result.getType() == TYPE_CONVERTED
|
||||||
|| result.getType() == TYPE_CONVERTED_MAPPED
|
|| result.getType() == TYPE_CONVERTED_MAPPED
|
||||||
@ -384,12 +379,20 @@ public class PropertyMapping extends ModelElement {
|
|||||||
// for primitive types null check is not possible at all, but a conversion needs
|
// for primitive types null check is not possible at all, but a conversion needs
|
||||||
// a null check.
|
// a null check.
|
||||||
result = new NullCheckWrapper( result, getSourcePresenceCheckerRef() );
|
result = new NullCheckWrapper( result, getSourcePresenceCheckerRef() );
|
||||||
|
useLocalVarWhenNested( result );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void useLocalVarWhenNested(Assignment rightHandSide) {
|
||||||
|
if ( sourceReference.getPropertyEntries().size() > 1 ) {
|
||||||
|
String sourceTypeName = rightHandSide.getSourceType().getName();
|
||||||
|
String safeName = Strings.getSaveVariableName( sourceTypeName, existingVariableNames );
|
||||||
|
rightHandSide.setSourceLocalVarName( safeName );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private Assignment assignToPlainViaAdder(Type sourceType, Assignment rightHandSide) {
|
private Assignment assignToPlainViaAdder(Type sourceType, Assignment rightHandSide) {
|
||||||
|
|
||||||
@ -399,7 +402,7 @@ public class PropertyMapping extends ModelElement {
|
|||||||
result = new AdderWrapper(
|
result = new AdderWrapper(
|
||||||
result,
|
result,
|
||||||
method.getThrownTypes(),
|
method.getThrownTypes(),
|
||||||
getSourceRef(),
|
getSource().getSourceReference(),
|
||||||
sourceType
|
sourceType
|
||||||
);
|
);
|
||||||
result = new NullCheckWrapper( result, getSourcePresenceCheckerRef() );
|
result = new NullCheckWrapper( result, getSourcePresenceCheckerRef() );
|
||||||
@ -524,18 +527,19 @@ public class PropertyMapping extends ModelElement {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private String getSourceRef() {
|
private Direct getSource() {
|
||||||
Parameter sourceParam = sourceReference.getParameter();
|
Parameter sourceParam = sourceReference.getParameter();
|
||||||
List<PropertyEntry> propertyEntries = sourceReference.getPropertyEntries();
|
List<PropertyEntry> propertyEntries = sourceReference.getPropertyEntries();
|
||||||
|
|
||||||
// parameter reference
|
// parameter reference
|
||||||
if ( propertyEntries.isEmpty() ) {
|
if ( propertyEntries.isEmpty() ) {
|
||||||
return sourceParam.getName();
|
return new Direct( sourceParam.getName(), getSourceType() );
|
||||||
}
|
}
|
||||||
// simple property
|
// simple property
|
||||||
else if ( propertyEntries.size() == 1 ) {
|
else if ( propertyEntries.size() == 1 ) {
|
||||||
PropertyEntry propertyEntry = propertyEntries.get( 0 );
|
PropertyEntry propertyEntry = propertyEntries.get( 0 );
|
||||||
return sourceParam.getName() + "." + propertyEntry.getReadAccessor().getSimpleName() + "()";
|
return new Direct( sourceParam.getName()
|
||||||
|
+ "." + propertyEntry.getReadAccessor().getSimpleName() + "()", propertyEntry.getType() );
|
||||||
}
|
}
|
||||||
// nested property given as dot path
|
// nested property given as dot path
|
||||||
else {
|
else {
|
||||||
@ -567,8 +571,8 @@ public class PropertyMapping extends ModelElement {
|
|||||||
else {
|
else {
|
||||||
forgedName = ctx.getExistingMappingMethod( nestedPropertyMapping ).getName();
|
forgedName = ctx.getExistingMappingMethod( nestedPropertyMapping ).getName();
|
||||||
}
|
}
|
||||||
|
return new Direct( forgedName + "( " + sourceParam.getName() + " )", getSourceType() );
|
||||||
|
|
||||||
return forgedName + "( " + sourceParam.getName() + " )";
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -606,7 +610,7 @@ public class PropertyMapping extends ModelElement {
|
|||||||
return sourcePresenceChecker;
|
return sourcePresenceChecker;
|
||||||
}
|
}
|
||||||
|
|
||||||
private Assignment forgeIterableMapping(Type sourceType, Type targetType, String sourceReference,
|
private Assignment forgeIterableMapping(Type sourceType, Type targetType, Direct source,
|
||||||
ExecutableElement element) {
|
ExecutableElement element) {
|
||||||
|
|
||||||
Assignment assignment = null;
|
Assignment assignment = null;
|
||||||
@ -635,13 +639,13 @@ public class PropertyMapping extends ModelElement {
|
|||||||
}
|
}
|
||||||
|
|
||||||
assignment = AssignmentFactory.createMethodReference( methodRef, null, targetType );
|
assignment = AssignmentFactory.createMethodReference( methodRef, null, targetType );
|
||||||
assignment.setAssignment( AssignmentFactory.createDirect( sourceReference ) );
|
assignment.setAssignment( source );
|
||||||
}
|
}
|
||||||
|
|
||||||
return assignment;
|
return assignment;
|
||||||
}
|
}
|
||||||
|
|
||||||
private Assignment forgeMapMapping(Type sourceType, Type targetType, String sourceReference,
|
private Assignment forgeMapMapping(Type sourceType, Type targetType, Direct source,
|
||||||
ExecutableElement element) {
|
ExecutableElement element) {
|
||||||
|
|
||||||
Assignment assignment = null;
|
Assignment assignment = null;
|
||||||
@ -668,7 +672,7 @@ public class PropertyMapping extends ModelElement {
|
|||||||
methodRef = new ForgedMethod( existingName, methodRef );
|
methodRef = new ForgedMethod( existingName, methodRef );
|
||||||
}
|
}
|
||||||
assignment = AssignmentFactory.createMethodReference( methodRef, null, targetType );
|
assignment = AssignmentFactory.createMethodReference( methodRef, null, targetType );
|
||||||
assignment.setAssignment( AssignmentFactory.createDirect( sourceReference ) );
|
assignment.setAssignment( source );
|
||||||
}
|
}
|
||||||
|
|
||||||
return assignment;
|
return assignment;
|
||||||
@ -726,7 +730,7 @@ public class PropertyMapping extends ModelElement {
|
|||||||
targetPropertyName,
|
targetPropertyName,
|
||||||
formattingParameters,
|
formattingParameters,
|
||||||
selectionParameters,
|
selectionParameters,
|
||||||
constantExpression,
|
new Direct( constantExpression, sourceType ),
|
||||||
method.getMappingTargetParameter() != null
|
method.getMappingTargetParameter() != null
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -793,7 +797,7 @@ public class PropertyMapping extends ModelElement {
|
|||||||
// String String quotation marks.
|
// String String quotation marks.
|
||||||
String enumExpression = constantExpression.substring( 1, constantExpression.length() - 1 );
|
String enumExpression = constantExpression.substring( 1, constantExpression.length() - 1 );
|
||||||
if ( targetType.getEnumConstants().contains( enumExpression ) ) {
|
if ( targetType.getEnumConstants().contains( enumExpression ) ) {
|
||||||
assignment = AssignmentFactory.createDirect( enumExpression );
|
assignment = new Direct( enumExpression, targetType );
|
||||||
assignment = new EnumConstantWrapper( assignment, targetType );
|
assignment = new EnumConstantWrapper( assignment, targetType );
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
@ -819,7 +823,7 @@ public class PropertyMapping extends ModelElement {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public PropertyMapping build() {
|
public PropertyMapping build() {
|
||||||
Assignment assignment = AssignmentFactory.createDirect( javaExpression );
|
Assignment assignment = new Direct( javaExpression, null );
|
||||||
|
|
||||||
if ( Executables.isSetterMethod( targetWriteAccessor ) ) {
|
if ( Executables.isSetterMethod( targetWriteAccessor ) ) {
|
||||||
// setter, so wrap in setter
|
// setter, so wrap in setter
|
||||||
|
@ -86,6 +86,21 @@ public class TypeConversion extends ModelElement implements Assignment {
|
|||||||
return assignment.getSourceReference();
|
return assignment.getSourceReference();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Type getSourceType() {
|
||||||
|
return assignment.getSourceType();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getSourceLocalVarName() {
|
||||||
|
return assignment.getSourceLocalVarName();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setSourceLocalVarName(String sourceLocalVarName) {
|
||||||
|
assignment.setSourceLocalVarName( sourceLocalVarName );
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setAssignment( Assignment assignment ) {
|
public void setAssignment( Assignment assignment ) {
|
||||||
this.assignment = assignment;
|
this.assignment = assignment;
|
||||||
|
@ -71,12 +71,32 @@ public interface Assignment {
|
|||||||
void setAssignment(Assignment assignment);
|
void setAssignment(Assignment assignment);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* the source reference being a source-getter, a constant, etc.
|
* the source reference being a source-getter, a constant, nested method call, etc.
|
||||||
*
|
*
|
||||||
* @return source reference
|
* @return source reference
|
||||||
*/
|
*/
|
||||||
String getSourceReference();
|
String getSourceReference();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* the source type.
|
||||||
|
*
|
||||||
|
* @return source type (can be null)
|
||||||
|
*/
|
||||||
|
Type getSourceType();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* a local variable name for supporting a null check and avoiding executing a nested method forged method twice
|
||||||
|
*
|
||||||
|
* @return local variable name (can be null)
|
||||||
|
*/
|
||||||
|
String getSourceLocalVarName();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Use sourceLocalVarName iso sourceReference
|
||||||
|
* @param sourceLocalVarName source local variable name
|
||||||
|
*/
|
||||||
|
void setSourceLocalVarName(String sourceLocalVarName);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns whether the type of assignment
|
* Returns whether the type of assignment
|
||||||
*
|
*
|
||||||
|
@ -61,6 +61,21 @@ public abstract class AssignmentWrapper extends ModelElement implements Assignme
|
|||||||
return decoratedAssignment.getSourceReference();
|
return decoratedAssignment.getSourceReference();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Type getSourceType() {
|
||||||
|
return decoratedAssignment.getSourceType();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getSourceLocalVarName() {
|
||||||
|
return decoratedAssignment.getSourceLocalVarName();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setSourceLocalVarName(String sourceLocalVarName) {
|
||||||
|
decoratedAssignment.setSourceLocalVarName( sourceLocalVarName );
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public AssignmentType getType() {
|
public AssignmentType getType() {
|
||||||
return decoratedAssignment.getType();
|
return decoratedAssignment.getType();
|
||||||
|
@ -36,6 +36,7 @@ import javax.lang.model.util.Types;
|
|||||||
import org.mapstruct.ap.internal.conversion.ConversionProvider;
|
import org.mapstruct.ap.internal.conversion.ConversionProvider;
|
||||||
import org.mapstruct.ap.internal.conversion.Conversions;
|
import org.mapstruct.ap.internal.conversion.Conversions;
|
||||||
import org.mapstruct.ap.internal.model.AssignmentFactory;
|
import org.mapstruct.ap.internal.model.AssignmentFactory;
|
||||||
|
import org.mapstruct.ap.internal.model.Direct;
|
||||||
import org.mapstruct.ap.internal.model.MapperReference;
|
import org.mapstruct.ap.internal.model.MapperReference;
|
||||||
import org.mapstruct.ap.internal.model.MappingBuilderContext.MappingResolver;
|
import org.mapstruct.ap.internal.model.MappingBuilderContext.MappingResolver;
|
||||||
import org.mapstruct.ap.internal.model.MethodReference;
|
import org.mapstruct.ap.internal.model.MethodReference;
|
||||||
@ -108,7 +109,7 @@ public class MappingResolverImpl implements MappingResolver {
|
|||||||
@SuppressWarnings("checkstyle:parameternumber")
|
@SuppressWarnings("checkstyle:parameternumber")
|
||||||
public Assignment getTargetAssignment(Method mappingMethod, String mappedElement, Type sourceType,
|
public Assignment getTargetAssignment(Method mappingMethod, String mappedElement, Type sourceType,
|
||||||
Type targetType, String targetPropertyName, FormattingParameters formattingParameters,
|
Type targetType, String targetPropertyName, FormattingParameters formattingParameters,
|
||||||
SelectionParameters selectionParameters, String sourceReference, boolean preferUpdateMapping) {
|
SelectionParameters selectionParameters, Direct sourceReference, boolean preferUpdateMapping) {
|
||||||
|
|
||||||
SelectionCriteria criteria =
|
SelectionCriteria criteria =
|
||||||
new SelectionCriteria( selectionParameters, targetPropertyName, preferUpdateMapping );
|
new SelectionCriteria( selectionParameters, targetPropertyName, preferUpdateMapping );
|
||||||
@ -171,7 +172,7 @@ public class MappingResolverImpl implements MappingResolver {
|
|||||||
private final String dateFormat;
|
private final String dateFormat;
|
||||||
private final String numberFormat;
|
private final String numberFormat;
|
||||||
private final SelectionCriteria selectionCriteria;
|
private final SelectionCriteria selectionCriteria;
|
||||||
private final String sourceReference;
|
private final Direct sourceReference;
|
||||||
private final boolean savedPreferUpdateMapping;
|
private final boolean savedPreferUpdateMapping;
|
||||||
|
|
||||||
// resolving via 2 steps creates the possibillity of wrong matches, first builtin method matches,
|
// resolving via 2 steps creates the possibillity of wrong matches, first builtin method matches,
|
||||||
@ -180,7 +181,7 @@ public class MappingResolverImpl implements MappingResolver {
|
|||||||
private final Set<VirtualMappingMethod> virtualMethodCandidates;
|
private final Set<VirtualMappingMethod> virtualMethodCandidates;
|
||||||
|
|
||||||
private ResolvingAttempt(List<SourceMethod> sourceModel, Method mappingMethod, String mappedElement,
|
private ResolvingAttempt(List<SourceMethod> sourceModel, Method mappingMethod, String mappedElement,
|
||||||
String dateFormat, String numberFormat, String sourceReference, SelectionCriteria criteria) {
|
String dateFormat, String numberFormat, Direct sourceReference, SelectionCriteria criteria) {
|
||||||
|
|
||||||
this.mappingMethod = mappingMethod;
|
this.mappingMethod = mappingMethod;
|
||||||
this.mappedElement = mappedElement;
|
this.mappedElement = mappedElement;
|
||||||
@ -209,28 +210,28 @@ public class MappingResolverImpl implements MappingResolver {
|
|||||||
// first simple mapping method
|
// first simple mapping method
|
||||||
Assignment referencedMethod = resolveViaMethod( sourceType, targetType, false );
|
Assignment referencedMethod = resolveViaMethod( sourceType, targetType, false );
|
||||||
if ( referencedMethod != null ) {
|
if ( referencedMethod != null ) {
|
||||||
referencedMethod.setAssignment( AssignmentFactory.createDirect( sourceReference ) );
|
referencedMethod.setAssignment( sourceReference );
|
||||||
return referencedMethod;
|
return referencedMethod;
|
||||||
}
|
}
|
||||||
|
|
||||||
// then direct assignable
|
// then direct assignable
|
||||||
if ( sourceType.isAssignableTo( targetType ) ||
|
if ( sourceType.isAssignableTo( targetType ) ||
|
||||||
isAssignableThroughCollectionCopyConstructor( sourceType, targetType ) ) {
|
isAssignableThroughCollectionCopyConstructor( sourceType, targetType ) ) {
|
||||||
Assignment simpleAssignment = AssignmentFactory.createDirect( sourceReference );
|
Assignment simpleAssignment = sourceReference;
|
||||||
return simpleAssignment;
|
return simpleAssignment;
|
||||||
}
|
}
|
||||||
|
|
||||||
// then type conversion
|
// then type conversion
|
||||||
Assignment conversion = resolveViaConversion( sourceType, targetType );
|
Assignment conversion = resolveViaConversion( sourceType, targetType );
|
||||||
if ( conversion != null ) {
|
if ( conversion != null ) {
|
||||||
conversion.setAssignment( AssignmentFactory.createDirect( sourceReference ) );
|
conversion.setAssignment( sourceReference );
|
||||||
return conversion;
|
return conversion;
|
||||||
}
|
}
|
||||||
|
|
||||||
// check for a built-in method
|
// check for a built-in method
|
||||||
Assignment builtInMethod = resolveViaBuiltInMethod( sourceType, targetType );
|
Assignment builtInMethod = resolveViaBuiltInMethod( sourceType, targetType );
|
||||||
if ( builtInMethod != null ) {
|
if ( builtInMethod != null ) {
|
||||||
builtInMethod.setAssignment( AssignmentFactory.createDirect( sourceReference ) );
|
builtInMethod.setAssignment( sourceReference );
|
||||||
usedVirtualMappings.addAll( virtualMethodCandidates );
|
usedVirtualMappings.addAll( virtualMethodCandidates );
|
||||||
return builtInMethod;
|
return builtInMethod;
|
||||||
}
|
}
|
||||||
@ -309,7 +310,7 @@ public class MappingResolverImpl implements MappingResolver {
|
|||||||
sourceType,
|
sourceType,
|
||||||
targetType, dateFormat, numberFormat);
|
targetType, dateFormat, numberFormat);
|
||||||
Assignment methodReference = AssignmentFactory.createMethodReference( matchingBuiltInMethod, ctx );
|
Assignment methodReference = AssignmentFactory.createMethodReference( matchingBuiltInMethod, ctx );
|
||||||
methodReference.setAssignment( AssignmentFactory.createDirect( sourceReference ) );
|
methodReference.setAssignment( sourceReference );
|
||||||
return methodReference;
|
return methodReference;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -350,7 +351,7 @@ public class MappingResolverImpl implements MappingResolver {
|
|||||||
selectionCriteria.setPreferUpdateMapping( savedPreferUpdateMapping );
|
selectionCriteria.setPreferUpdateMapping( savedPreferUpdateMapping );
|
||||||
if ( methodRefX != null ) {
|
if ( methodRefX != null ) {
|
||||||
methodRefY.setAssignment( methodRefX );
|
methodRefY.setAssignment( methodRefX );
|
||||||
methodRefX.setAssignment( AssignmentFactory.createDirect( sourceReference ) );
|
methodRefX.setAssignment( sourceReference );
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
@ -387,7 +388,7 @@ public class MappingResolverImpl implements MappingResolver {
|
|||||||
resolveViaConversion( sourceType, methodYCandidate.getSourceParameters().get( 0 ).getType() );
|
resolveViaConversion( sourceType, methodYCandidate.getSourceParameters().get( 0 ).getType() );
|
||||||
if ( conversionXRef != null ) {
|
if ( conversionXRef != null ) {
|
||||||
methodRefY.setAssignment( conversionXRef );
|
methodRefY.setAssignment( conversionXRef );
|
||||||
conversionXRef.setAssignment( AssignmentFactory.createDirect( sourceReference ) );
|
conversionXRef.setAssignment( sourceReference );
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
@ -430,7 +431,7 @@ public class MappingResolverImpl implements MappingResolver {
|
|||||||
conversionYRef = resolveViaConversion( methodXCandidate.getReturnType(), targetType );
|
conversionYRef = resolveViaConversion( methodXCandidate.getReturnType(), targetType );
|
||||||
if ( conversionYRef != null ) {
|
if ( conversionYRef != null ) {
|
||||||
conversionYRef.setAssignment( methodRefX );
|
conversionYRef.setAssignment( methodRefX );
|
||||||
methodRefX.setAssignment( AssignmentFactory.createDirect( sourceReference ) );
|
methodRefX.setAssignment( sourceReference );
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
@ -18,4 +18,4 @@
|
|||||||
limitations under the License.
|
limitations under the License.
|
||||||
|
|
||||||
-->
|
-->
|
||||||
${sourceReference}
|
<#if sourceLocalVarName??>${sourceLocalVarName}<#else>${sourceReference}</#if>
|
@ -18,22 +18,27 @@
|
|||||||
limitations under the License.
|
limitations under the License.
|
||||||
|
|
||||||
-->
|
-->
|
||||||
|
<#if sourceLocalVarName??>
|
||||||
|
<@includeModel object=sourceType/> ${sourceLocalVarName} = ${sourceReference};
|
||||||
|
if ( ${sourceLocalVarName} != null ) {
|
||||||
|
<@_assignment object=assignment defaultValue=ext.defaultValueAssignment/>
|
||||||
|
}
|
||||||
|
<#else>
|
||||||
if ( <#if sourcePresenceChecker?? >${sourcePresenceChecker}<#else>${sourceReference} != null</#if> ) {
|
if ( <#if sourcePresenceChecker?? >${sourcePresenceChecker}<#else>${sourceReference} != null</#if> ) {
|
||||||
<@includeModel object=assignment
|
<@_assignment object=assignment defaultValue=ext.defaultValueAssignment/>
|
||||||
|
}
|
||||||
|
</#if>
|
||||||
|
<#if ext.defaultValueAssignment?? >
|
||||||
|
else {
|
||||||
|
<@_assignment object=ext.defaultValueAssignment/>
|
||||||
|
}
|
||||||
|
</#if>
|
||||||
|
<#macro _assignment object defaultValue="">
|
||||||
|
<@includeModel object=object
|
||||||
targetBeanName=ext.targetBeanName
|
targetBeanName=ext.targetBeanName
|
||||||
existingInstanceMapping=ext.existingInstanceMapping
|
existingInstanceMapping=ext.existingInstanceMapping
|
||||||
targetReadAccessorName=ext.targetReadAccessorName
|
targetReadAccessorName=ext.targetReadAccessorName
|
||||||
targetWriteAccessorName=ext.targetWriteAccessorName
|
targetWriteAccessorName=ext.targetWriteAccessorName
|
||||||
targetType=ext.targetType
|
targetType=ext.targetType
|
||||||
defaultValue=ext.defaultValueAssignment/>
|
defaultValue=defaultValue/>
|
||||||
}
|
</#macro>
|
||||||
<#if ext.defaultValueAssignment?? >
|
|
||||||
else {
|
|
||||||
<@includeModel object=ext.defaultValueAssignment
|
|
||||||
targetBeanName=ext.targetBeanName
|
|
||||||
existingInstanceMapping=ext.existingInstanceMapping
|
|
||||||
targetReadAccessorName=ext.targetReadAccessorName
|
|
||||||
targetWriteAccessorName=ext.targetWriteAccessorName
|
|
||||||
targetType=ext.targetType/>
|
|
||||||
}
|
|
||||||
</#if>
|
|
||||||
|
@ -0,0 +1,36 @@
|
|||||||
|
/**
|
||||||
|
* Copyright 2012-2016 Gunnar Morling (http://www.gunnarmorling.de/)
|
||||||
|
* and/or other contributors as indicated by the @authors tag. See the
|
||||||
|
* copyright.txt file in the distribution for a full listing of all
|
||||||
|
* contributors.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package org.mapstruct.ap.test.bugs._891;
|
||||||
|
|
||||||
|
import org.mapstruct.Mapper;
|
||||||
|
import org.mapstruct.Mapping;
|
||||||
|
import org.mapstruct.factory.Mappers;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author Sjaak Derksen
|
||||||
|
*/
|
||||||
|
@Mapper
|
||||||
|
public interface BuggyMapper {
|
||||||
|
|
||||||
|
BuggyMapper INSTANCE = Mappers.getMapper( BuggyMapper.class );
|
||||||
|
|
||||||
|
@Mapping(source = "nested.propInt", target = "propLong")
|
||||||
|
Dest convert(Src src);
|
||||||
|
}
|
@ -0,0 +1,30 @@
|
|||||||
|
/**
|
||||||
|
* Copyright 2012-2016 Gunnar Morling (http://www.gunnarmorling.de/)
|
||||||
|
* and/or other contributors as indicated by the @authors tag. See the
|
||||||
|
* copyright.txt file in the distribution for a full listing of all
|
||||||
|
* contributors.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package org.mapstruct.ap.test.bugs._891;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author Sjaak Derksen
|
||||||
|
*/
|
||||||
|
public class Dest {
|
||||||
|
|
||||||
|
public void setPropLong(Long l) {
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,38 @@
|
|||||||
|
/**
|
||||||
|
* Copyright 2012-2016 Gunnar Morling (http://www.gunnarmorling.de/)
|
||||||
|
* and/or other contributors as indicated by the @authors tag. See the
|
||||||
|
* copyright.txt file in the distribution for a full listing of all
|
||||||
|
* contributors.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package org.mapstruct.ap.test.bugs._891;
|
||||||
|
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.junit.runner.RunWith;
|
||||||
|
import org.mapstruct.ap.testutil.WithClasses;
|
||||||
|
import org.mapstruct.ap.testutil.runner.AnnotationProcessorTestRunner;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Sjaak Derksen
|
||||||
|
*/
|
||||||
|
@RunWith(AnnotationProcessorTestRunner.class)
|
||||||
|
@WithClasses({BuggyMapper.class, Dest.class, Src.class, SrcNested.class})
|
||||||
|
public class Issue891Test {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void shouldNotThrowNPE() {
|
||||||
|
|
||||||
|
BuggyMapper.INSTANCE.convert( new Src() );
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,31 @@
|
|||||||
|
/**
|
||||||
|
* Copyright 2012-2016 Gunnar Morling (http://www.gunnarmorling.de/)
|
||||||
|
* and/or other contributors as indicated by the @authors tag. See the
|
||||||
|
* copyright.txt file in the distribution for a full listing of all
|
||||||
|
* contributors.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package org.mapstruct.ap.test.bugs._891;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author Sjaak Derksen
|
||||||
|
*/
|
||||||
|
public class Src {
|
||||||
|
|
||||||
|
public SrcNested getNested() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,31 @@
|
|||||||
|
/**
|
||||||
|
* Copyright 2012-2016 Gunnar Morling (http://www.gunnarmorling.de/)
|
||||||
|
* and/or other contributors as indicated by the @authors tag. See the
|
||||||
|
* copyright.txt file in the distribution for a full listing of all
|
||||||
|
* contributors.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package org.mapstruct.ap.test.bugs._891;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author Sjaak Derksen
|
||||||
|
*/
|
||||||
|
public class SrcNested {
|
||||||
|
|
||||||
|
public Integer getPropInt() {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user