Skip to content

Commit

Permalink
#1131 Use SourceRHS source type for update methods factories
Browse files Browse the repository at this point in the history
If a SourceRHS is present then the source type of the SourceRHS and the MappingContext parameters are considered for the factory method selection, i.e. the other source parameters are ignored
  • Loading branch information
filiphr committed Jul 11, 2017
1 parent 3ebd09e commit 3004ea2
Show file tree
Hide file tree
Showing 45 changed files with 590 additions and 61 deletions.
2 changes: 1 addition & 1 deletion core-common/src/main/java/org/mapstruct/ObjectFactory.java
Expand Up @@ -30,7 +30,7 @@
* return type that is assignable to the required object type is present, then the factory method is used instead.
* <p>
* Factory methods can be defined without parameters, with an {@code @}{@link TargetType} parameter, a {@code @}
* {@link Context} parameter, or with a mapping methods source parameter. If any of those parameters are defined, then
* {@link Context} parameter, or with the mapping source parameter. If any of those parameters are defined, then
* the mapping method that is supposed to use the factory method needs to be declared with an assignable result type,
* assignable context parameter, and/or assignable source types.
* <p>
Expand Down
72 changes: 70 additions & 2 deletions documentation/src/main/asciidoc/mapstruct-reference-guide.asciidoc
Expand Up @@ -1579,7 +1579,7 @@ The mapping of enum to enum via the `@Mapping` annotation is *DEPRECATED*. It wi
[[object-factories]]
== Object factories

By default, the generated code for mapping one bean type into another will call the default constructor to instantiate the target type.
By default, the generated code for mapping one bean type into another or updating a bean will call the default constructor to instantiate the target type.

Alternatively you can plug in custom object factories which will be invoked to obtain instances of the target type. One use case for this is JAXB which creates `ObjectFactory` classes for obtaining new instances of schema types.

Expand Down Expand Up @@ -1613,7 +1613,7 @@ public class EntityFactory {
@Mapper(uses= { DtoFactory.class, EntityFactory.class } )
public interface CarMapper {
OrderMapper INSTANCE = Mappers.getMapper( CarMapper.class );
CarMapper INSTANCE = Mappers.getMapper( CarMapper.class );
CarDto carToCarDto(Car car);
Expand Down Expand Up @@ -1659,6 +1659,74 @@ public class CarMapperImpl implements CarMapper {
----
====

.Custom object factories with update methods
====
[source, java, linenums]
[subs="verbatim,attributes"]
----
@Mapper(uses = { DtoFactory.class, EntityFactory.class, CarMapper.class } )
public interface OwnerMapper {
OwnerMapper INSTANCE = Mappers.getMapper( OwnerMapper.class );
void updateOwnerDto(Owner owner, @MappingTarget OwnerDto ownerDto);
void updateOwner(OwnerDto ownerDto, @MappingTarget Owner owner);
}
----
[source, java, linenums]
[subs="verbatim,attributes"]
----
//GENERATED CODE
public class OwnerMapperImpl implements OwnerMapper {
private final DtoFactory dtoFactory = new DtoFactory();
private final EntityFactory entityFactory = new EntityFactory();
private final OwnerMapper ownerMapper = Mappers.getMapper( OwnerMapper.class );
@Override
public void updateOwnerDto(Owner owner, @MappingTarget OwnerDto ownerDto) {
if ( owner == null ) {
return;
}
if ( owner.getCar() != null ) {
if ( ownerDto.getCar() == null ) {
ownerDto.setCar( dtoFactory.createCarDto() );
}
// update car within ownerDto
}
else {
ownerDto.setCar( null );
}
// updating other properties
}
@Override
public void updateOwner(OwnerDto ownerDto, @MappingTarget Owner owner) {
if ( ownerDto == null ) {
return;
}
if ( ownerDto.getCar() != null ) {
if ( owner.getCar() == null ) {
owner.setCar( entityFactory.createEntity( Car.class ) );
}
// update car within owner
}
else {
owner.setCar( null );
}
// updating other properties
}
}
----
====

In addition, annotating a factory method with `@ObjectFactory` lets you gain access to the mapping sources.
Source objects can be added as parameters in the same way as for mapping method. The `@ObjectFactory`
annotation is necessary to let MapStruct know that the given method is only a factory method.
Expand Down
Expand Up @@ -20,7 +20,7 @@

import java.util.List;
import org.mapstruct.ap.internal.model.TypeConversion;
import org.mapstruct.ap.internal.model.assignment.Assignment;
import org.mapstruct.ap.internal.model.common.Assignment;
import org.mapstruct.ap.internal.model.common.ConversionContext;
import org.mapstruct.ap.internal.model.HelperMethod;

Expand Down
Expand Up @@ -27,10 +27,10 @@
import java.util.Date;
import java.util.List;

import org.mapstruct.ap.internal.model.assignment.Assignment;
import org.mapstruct.ap.internal.model.common.ConversionContext;
import org.mapstruct.ap.internal.model.HelperMethod;
import org.mapstruct.ap.internal.model.TypeConversion;
import org.mapstruct.ap.internal.model.common.Assignment;
import org.mapstruct.ap.internal.model.common.ConversionContext;
import org.mapstruct.ap.internal.model.common.Type;

/**
Expand Down
Expand Up @@ -20,7 +20,7 @@

import java.util.Collections;
import java.util.List;
import org.mapstruct.ap.internal.model.assignment.Assignment;
import org.mapstruct.ap.internal.model.common.Assignment;
import org.mapstruct.ap.internal.model.common.ConversionContext;
import org.mapstruct.ap.internal.model.HelperMethod;

Expand Down
Expand Up @@ -23,7 +23,7 @@
import java.util.Set;

import org.mapstruct.ap.internal.model.TypeConversion;
import org.mapstruct.ap.internal.model.assignment.Assignment;
import org.mapstruct.ap.internal.model.common.Assignment;
import org.mapstruct.ap.internal.model.common.ConversionContext;
import org.mapstruct.ap.internal.model.HelperMethod;
import org.mapstruct.ap.internal.model.common.Type;
Expand Down
Expand Up @@ -18,8 +18,9 @@
*/
package org.mapstruct.ap.internal.model;

import org.mapstruct.ap.internal.model.assignment.Assignment;
import org.mapstruct.ap.internal.model.common.Assignment;
import org.mapstruct.ap.internal.model.common.ParameterBinding;
import org.mapstruct.ap.internal.model.common.SourceRHS;
import org.mapstruct.ap.internal.model.common.Type;
import org.mapstruct.ap.internal.model.source.ForgedMethod;
import org.mapstruct.ap.internal.model.source.MappingMethodUtils;
Expand Down
Expand Up @@ -19,7 +19,8 @@

package org.mapstruct.ap.internal.model;

import org.mapstruct.ap.internal.model.assignment.Assignment;
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.ForgedMethod;
import org.mapstruct.ap.internal.model.source.ForgedMethodHistory;
Expand Down
Expand Up @@ -18,14 +18,16 @@
*/
package org.mapstruct.ap.internal.model;

import org.mapstruct.ap.internal.model.assignment.Assignment;
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.prism.CollectionMappingStrategyPrism;
import org.mapstruct.ap.internal.prism.NullValueCheckStrategyPrism;
import org.mapstruct.ap.internal.util.Message;
Expand Down Expand Up @@ -65,7 +67,8 @@ public class CollectionAssignmentBuilder {
private Type targetType;
private String targetPropertyName;
private PropertyMapping.TargetWriteAccessorType targetAccessorType;
private Assignment rhs;
private Assignment assignment;
private SourceRHS sourceRHS;

public CollectionAssignmentBuilder mappingBuilderContext(MappingBuilderContext ctx) {
this.ctx = ctx;
Expand Down Expand Up @@ -97,13 +100,28 @@ public CollectionAssignmentBuilder targetAccessorType(PropertyMapping.TargetWrit
return this;
}

public CollectionAssignmentBuilder rightHandSide(Assignment rhs) {
this.rhs = rhs;
/**
* @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 Assignment build() {
Assignment result = rhs;
Assignment result = assignment;

CollectionMappingStrategyPrism cms = method.getMapperConfiguration().getCollectionMappingStrategy();
boolean targetImmutable = cms == CollectionMappingStrategyPrism.TARGET_IMMUTABLE;
Expand All @@ -121,7 +139,8 @@ public Assignment build() {
targetPropertyName
);
}
Assignment factoryMethod = ctx.getMappingResolver().getFactoryMethod( method, targetType, null );
Assignment factoryMethod = ctx.getMappingResolver()
.getFactoryMethod( method, targetType, SelectionParameters.forSourceRHS( sourceRHS ) );
result = new UpdateWrapper(
result,
method.getThrownTypes(),
Expand Down
Expand Up @@ -22,7 +22,7 @@
import java.util.List;
import java.util.Set;

import org.mapstruct.ap.internal.model.assignment.Assignment;
import org.mapstruct.ap.internal.model.common.Assignment;
import org.mapstruct.ap.internal.model.common.Parameter;
import org.mapstruct.ap.internal.model.common.Type;
import org.mapstruct.ap.internal.model.source.Method;
Expand Down
Expand Up @@ -25,10 +25,11 @@
import java.util.List;
import java.util.Set;

import org.mapstruct.ap.internal.model.assignment.Assignment;
import org.mapstruct.ap.internal.model.common.Assignment;
import org.mapstruct.ap.internal.model.common.FormattingParameters;
import org.mapstruct.ap.internal.model.common.SourceRHS;
import org.mapstruct.ap.internal.model.common.Type;
import org.mapstruct.ap.internal.model.source.ForgedMethod;
import org.mapstruct.ap.internal.model.common.FormattingParameters;
import org.mapstruct.ap.internal.model.source.Method;
import org.mapstruct.ap.internal.model.source.SelectionParameters;
import org.mapstruct.ap.internal.prism.NullValueMappingStrategyPrism;
Expand Down
Expand Up @@ -23,9 +23,9 @@
import java.util.Collection;
import java.util.List;

import org.mapstruct.ap.internal.model.assignment.Assignment;
import org.mapstruct.ap.internal.model.assignment.LocalVarWrapper;
import org.mapstruct.ap.internal.model.assignment.SetterWrapper;
import org.mapstruct.ap.internal.model.common.Assignment;
import org.mapstruct.ap.internal.model.common.Type;
import org.mapstruct.ap.internal.model.source.Method;
import org.mapstruct.ap.internal.model.source.SelectionParameters;
Expand Down
Expand Up @@ -24,12 +24,13 @@
import java.util.Map;
import java.util.Set;

import org.mapstruct.ap.internal.model.assignment.Assignment;
import org.mapstruct.ap.internal.model.assignment.LocalVarWrapper;
import org.mapstruct.ap.internal.model.common.Assignment;
import org.mapstruct.ap.internal.model.common.FormattingParameters;
import org.mapstruct.ap.internal.model.common.Parameter;
import org.mapstruct.ap.internal.model.common.SourceRHS;
import org.mapstruct.ap.internal.model.common.Type;
import org.mapstruct.ap.internal.model.source.ForgedMethod;
import org.mapstruct.ap.internal.model.common.FormattingParameters;
import org.mapstruct.ap.internal.model.source.Method;
import org.mapstruct.ap.internal.model.source.SelectionParameters;
import org.mapstruct.ap.internal.prism.NullValueMappingStrategyPrism;
Expand Down
Expand Up @@ -28,8 +28,9 @@
import javax.lang.model.util.Elements;
import javax.lang.model.util.Types;

import org.mapstruct.ap.internal.model.assignment.Assignment;
import org.mapstruct.ap.internal.model.common.Assignment;
import org.mapstruct.ap.internal.model.common.FormattingParameters;
import org.mapstruct.ap.internal.model.common.SourceRHS;
import org.mapstruct.ap.internal.model.common.Type;
import org.mapstruct.ap.internal.model.common.TypeFactory;
import org.mapstruct.ap.internal.model.source.ForgedMethod;
Expand Down
Expand Up @@ -24,7 +24,7 @@
import java.util.List;
import java.util.Set;

import org.mapstruct.ap.internal.model.assignment.Assignment;
import org.mapstruct.ap.internal.model.common.Assignment;
import org.mapstruct.ap.internal.model.common.ConversionContext;
import org.mapstruct.ap.internal.model.common.Parameter;
import org.mapstruct.ap.internal.model.common.ParameterBinding;
Expand Down
Expand Up @@ -18,7 +18,7 @@
*/
package org.mapstruct.ap.internal.model;

import static org.mapstruct.ap.internal.model.assignment.Assignment.AssignmentType.DIRECT;
import static org.mapstruct.ap.internal.model.common.Assignment.AssignmentType.DIRECT;
import static org.mapstruct.ap.internal.prism.NullValueCheckStrategyPrism.ALWAYS;
import static org.mapstruct.ap.internal.util.Collections.first;
import static org.mapstruct.ap.internal.util.Collections.last;
Expand All @@ -34,14 +34,15 @@

import org.mapstruct.ap.internal.model.assignment.AdderWrapper;
import org.mapstruct.ap.internal.model.assignment.ArrayCopyWrapper;
import org.mapstruct.ap.internal.model.assignment.Assignment;
import org.mapstruct.ap.internal.model.assignment.EnumConstantWrapper;
import org.mapstruct.ap.internal.model.assignment.GetterWrapperForCollectionsAndMaps;
import org.mapstruct.ap.internal.model.assignment.SetterWrapper;
import org.mapstruct.ap.internal.model.assignment.UpdateWrapper;
import org.mapstruct.ap.internal.model.common.Assignment;
import org.mapstruct.ap.internal.model.common.FormattingParameters;
import org.mapstruct.ap.internal.model.common.ModelElement;
import org.mapstruct.ap.internal.model.common.Parameter;
import org.mapstruct.ap.internal.model.common.SourceRHS;
import org.mapstruct.ap.internal.model.common.Type;
import org.mapstruct.ap.internal.model.source.ForgedMethod;
import org.mapstruct.ap.internal.model.source.ForgedMethodHistory;
Expand Down Expand Up @@ -393,7 +394,8 @@ private Assignment assignToPlainViaSetter(Type targetType, Assignment rhs) {
targetPropertyName
);
}
Assignment factory = ctx.getMappingResolver().getFactoryMethod( method, targetType, null );
Assignment factory = ctx.getMappingResolver()
.getFactoryMethod( method, targetType, SelectionParameters.forSourceRHS( rightHandSide ) );
return new UpdateWrapper( rhs, method.getThrownTypes(), factory, isFieldAssignment(), targetType,
!rhs.isSourceReferenceParameter() );
}
Expand Down Expand Up @@ -426,7 +428,8 @@ private Assignment assignToCollection(Type targetType, TargetWriteAccessorType t
.targetType( targetType )
.targetPropertyName( targetPropertyName )
.targetAccessorType( targetAccessorType )
.rightHandSide( rhs )
.rightHandSide( rightHandSide )
.assignment( rhs )
.build();
}

Expand Down
Expand Up @@ -26,8 +26,8 @@
import java.util.stream.Stream;
import java.util.stream.StreamSupport;

import org.mapstruct.ap.internal.model.assignment.Assignment;
import org.mapstruct.ap.internal.model.assignment.Java8FunctionWrapper;
import org.mapstruct.ap.internal.model.common.Assignment;
import org.mapstruct.ap.internal.model.common.Type;
import org.mapstruct.ap.internal.model.source.Method;
import org.mapstruct.ap.internal.model.source.SelectionParameters;
Expand Down
Expand Up @@ -22,7 +22,7 @@
import java.util.List;
import java.util.Set;

import org.mapstruct.ap.internal.model.assignment.Assignment;
import org.mapstruct.ap.internal.model.common.Assignment;
import org.mapstruct.ap.internal.model.common.ModelElement;
import org.mapstruct.ap.internal.model.common.Type;

Expand Down
Expand Up @@ -23,6 +23,7 @@
import java.util.List;
import java.util.Set;

import org.mapstruct.ap.internal.model.common.Assignment;
import org.mapstruct.ap.internal.model.common.Type;
import org.mapstruct.ap.internal.util.Nouns;

Expand Down
Expand Up @@ -21,6 +21,7 @@
import java.util.HashSet;
import java.util.Set;

import org.mapstruct.ap.internal.model.common.Assignment;
import org.mapstruct.ap.internal.model.common.Type;

/**
Expand Down
Expand Up @@ -21,6 +21,7 @@
import java.util.List;
import java.util.Set;

import org.mapstruct.ap.internal.model.common.Assignment;
import org.mapstruct.ap.internal.model.common.ModelElement;
import org.mapstruct.ap.internal.model.common.Type;

Expand Down

0 comments on commit 3004ea2

Please sign in to comment.