Skip to content

Commit

Permalink
mapstruct#1742 & mapstruct#1661 refactoring and making builder optional
Browse files Browse the repository at this point in the history
Applying changes done in 3371058
  • Loading branch information
filiphr committed Sep 27, 2019
1 parent 5656ae6 commit 9e487a2
Show file tree
Hide file tree
Showing 45 changed files with 874 additions and 482 deletions.
8 changes: 8 additions & 0 deletions core/src/main/java/org/mapstruct/Builder.java
Original file line number Diff line number Diff line change
Expand Up @@ -29,4 +29,12 @@
* @return the method that needs to tbe invoked on the builder
*/
String buildMethod() default "build";

/**
* Toggling builders on / off. Builders are sometimes used solely for unit testing (fluent testdata)
* MapStruct will need to use the regular getters /setters in that case.
*
* @return when true, no builder patterns will be applied
*/
boolean disableBuilder() default false;
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@

import javax.lang.model.element.AnnotationMirror;
import org.mapstruct.ap.internal.model.common.Assignment;
import org.mapstruct.ap.internal.model.common.BuilderType;
import org.mapstruct.ap.internal.model.common.ParameterBinding;
import org.mapstruct.ap.internal.model.common.SourceRHS;
import org.mapstruct.ap.internal.model.common.Type;
Expand Down Expand Up @@ -73,7 +74,7 @@ private boolean isDisableSubMappingMethodsGeneration() {
*
* @return See above
*/
Assignment createForgedAssignment(SourceRHS sourceRHS, ForgedMethod forgedMethod) {
Assignment createForgedAssignment(SourceRHS sourceRHS, BuilderType builderType, ForgedMethod forgedMethod) {

if ( ctx.getForgedMethodsUnderCreation().containsKey( forgedMethod ) ) {
return createAssignment( sourceRHS, ctx.getForgedMethodsUnderCreation().get( forgedMethod ) );
Expand All @@ -93,6 +94,7 @@ Assignment createForgedAssignment(SourceRHS sourceRHS, ForgedMethod forgedMethod
else {
forgedMappingMethod = new BeanMappingMethod.Builder()
.forgedMethod( forgedMethod )
.returnTypeBuilder( builderType )
.mappingContext( ctx )
.build();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
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.BeanMapping;
import org.mapstruct.ap.internal.model.source.ForgedMethod;
import org.mapstruct.ap.internal.model.source.ForgedMethodHistory;
import org.mapstruct.ap.internal.util.Strings;
Expand Down Expand Up @@ -63,7 +64,11 @@ Assignment forgeMapping(SourceRHS sourceRHS, Type sourceType, Type targetType) {
true
);

return createForgedAssignment( sourceRHS, forgedMethod );
return createForgedAssignment(
sourceRHS,
ctx.getTypeFactory().builderTypeFor( targetType, BeanMapping.builderPrismFor( method ) ),
forgedMethod
);
}

private String getName(Type sourceType, Type targetType) {
Expand Down

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@
import org.mapstruct.ap.internal.model.source.BeanMapping;
import org.mapstruct.ap.internal.model.source.Method;
import org.mapstruct.ap.internal.prism.BuilderPrism;
import org.mapstruct.ap.internal.util.MapperConfiguration;
import org.mapstruct.ap.internal.util.Message;
import org.mapstruct.ap.internal.util.Strings;

Expand All @@ -36,7 +35,7 @@ public static MethodReference getBuilderFinisherMethod(Method method, BuilderTyp
return null;
}

BuilderPrism builderMapping = builderMappingPrism( method, ctx );
BuilderPrism builderMapping = BeanMapping.builderPrismFor( method );
if ( builderMapping == null && buildMethods.size() == 1 ) {
return MethodReference.forMethodCall( first( buildMethods ).getSimpleName().toString() );
}
Expand Down Expand Up @@ -77,12 +76,4 @@ public static MethodReference getBuilderFinisherMethod(Method method, BuilderTyp

return null;
}

private static BuilderPrism builderMappingPrism(Method method, MappingBuilderContext ctx) {
BeanMapping beanMapping = method.getMappingOptions().getBeanMapping();
if ( beanMapping != null && beanMapping.getBuilder() != null ) {
return beanMapping.getBuilder();
}
return MapperConfiguration.getInstanceOn( ctx.getMapperTypeElement() ).getBuilderPrism();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
import org.mapstruct.ap.internal.prism.NullValuePropertyMappingStrategyPrism;
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.prism.NullValuePropertyMappingStrategyPrism.SET_TO_DEFAULT;
import static org.mapstruct.ap.internal.prism.NullValuePropertyMappingStrategyPrism.SET_TO_NULL;
Expand Down Expand Up @@ -57,7 +58,7 @@ public class CollectionAssignmentBuilder {
private Accessor targetReadAccessor;
private Type targetType;
private String targetPropertyName;
private PropertyMapping.TargetWriteAccessorType targetAccessorType;
private AccessorType targetAccessorType;
private Assignment assignment;
private SourceRHS sourceRHS;
private NullValueCheckStrategyPrism nvcs;
Expand Down Expand Up @@ -88,7 +89,7 @@ public CollectionAssignmentBuilder targetPropertyName(String targetPropertyName)
return this;
}

public CollectionAssignmentBuilder targetAccessorType(PropertyMapping.TargetWriteAccessorType targetAccessorType) {
public CollectionAssignmentBuilder targetAccessorType(AccessorType targetAccessorType) {
this.targetAccessorType = targetAccessorType;
return this;
}
Expand Down Expand Up @@ -129,8 +130,7 @@ public Assignment build() {
CollectionMappingStrategyPrism cms = method.getMapperConfiguration().getCollectionMappingStrategy();
boolean targetImmutable = cms == CollectionMappingStrategyPrism.TARGET_IMMUTABLE || targetReadAccessor == null;

if ( targetAccessorType == PropertyMapping.TargetWriteAccessorType.SETTER ||
targetAccessorType == PropertyMapping.TargetWriteAccessorType.FIELD ) {
if ( targetAccessorType == AccessorType.SETTER || targetAccessorType == AccessorType.FIELD ) {

if ( result.isCallingUpdateMethod() && !targetImmutable ) {

Expand All @@ -149,7 +149,7 @@ public Assignment build() {
result,
method.getThrownTypes(),
factoryMethod,
PropertyMapping.TargetWriteAccessorType.isFieldAssignment( targetAccessorType ),
targetAccessorType == AccessorType.FIELD,
targetType,
true,
nvpms == SET_TO_NULL && !targetType.isPrimitive(),
Expand All @@ -165,7 +165,7 @@ else if ( method.isUpdateMethod() && !targetImmutable ) {
nvcs,
nvpms,
ctx.getTypeFactory(),
PropertyMapping.TargetWriteAccessorType.isFieldAssignment( targetAccessorType )
targetAccessorType == AccessorType.FIELD
);
}
else if ( result.getType() == Assignment.AssignmentType.DIRECT ||
Expand All @@ -176,7 +176,7 @@ else if ( result.getType() == Assignment.AssignmentType.DIRECT ||
method.getThrownTypes(),
targetType,
ctx.getTypeFactory(),
PropertyMapping.TargetWriteAccessorType.isFieldAssignment( targetAccessorType )
targetAccessorType == AccessorType.FIELD
);
}
else {
Expand All @@ -185,7 +185,7 @@ else if ( result.getType() == Assignment.AssignmentType.DIRECT ||
result,
method.getThrownTypes(),
targetType,
PropertyMapping.TargetWriteAccessorType.isFieldAssignment( targetAccessorType )
targetAccessorType == AccessorType.FIELD
);
}
}
Expand All @@ -203,7 +203,7 @@ else if ( result.getType() == Assignment.AssignmentType.DIRECT ||
result,
method.getThrownTypes(),
targetType,
PropertyMapping.TargetWriteAccessorType.isFieldAssignment( targetAccessorType )
targetAccessorType == AccessorType.FIELD
);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,7 @@ public final M build() {

MethodReference factoryMethod = null;
if ( !method.isUpdateMethod() ) {
factoryMethod = ObjectFactoryMethodResolver.getFactoryMethod( method, method.getResultType(), null, ctx );
factoryMethod = ObjectFactoryMethodResolver.getFactoryMethod( method, null, ctx );
}

Set<String> existingVariables = new HashSet<>( method.getParameterNames() );
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@
import java.util.Collections;
import java.util.List;
import java.util.Set;

import javax.lang.model.element.ExecutableElement;

import org.mapstruct.ap.internal.model.common.Accessibility;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,16 +32,19 @@ private LifecycleMethodResolver() {

/**
* @param method the method to obtain the beforeMapping methods for
* @param alternativeTarget alternative to {@link Method#getResultType()} e.g. when target is abstract
* @param selectionParameters method selectionParameters
* @param ctx the builder context
* @param existingVariableNames the existing variable names in the mapping method
* @return all applicable {@code @BeforeMapping} methods for the given method
*/
public static List<LifecycleCallbackMethodReference> beforeMappingMethods(Method method,
Type alternativeTarget,
SelectionParameters selectionParameters,
MappingBuilderContext ctx,
Set<String> existingVariableNames) {
return collectLifecycleCallbackMethods( method,
alternativeTarget,
selectionParameters,
filterBeforeMappingMethods( getAllAvailableMethods( method, ctx.getSourceModel() ) ),
ctx,
Expand All @@ -50,16 +53,57 @@ public static List<LifecycleCallbackMethodReference> beforeMappingMethods(Method

/**
* @param method the method to obtain the afterMapping methods for
* @param alternativeTarget alternative to {@link Method#getResultType()} e.g. when target is abstract
* @param selectionParameters method selectionParameters
* @param ctx the builder context
* @param existingVariableNames list of already used variable names
* @return all applicable {@code @AfterMapping} methods for the given method
*/
public static List<LifecycleCallbackMethodReference> afterMappingMethods(Method method,
Type alternativeTarget,
SelectionParameters selectionParameters,
MappingBuilderContext ctx,
Set<String> existingVariableNames) {
return collectLifecycleCallbackMethods( method,
alternativeTarget,
selectionParameters,
filterAfterMappingMethods( getAllAvailableMethods( method, ctx.getSourceModel() ) ),
ctx,
existingVariableNames );
}

/**
* @param method the method to obtain the beforeMapping methods for
* @param selectionParameters method selectionParameters
* @param ctx the builder context
* @param existingVariableNames the existing variable names in the mapping method
* @return all applicable {@code @BeforeMapping} methods for the given method
*/
public static List<LifecycleCallbackMethodReference> beforeMappingMethods(Method method,
SelectionParameters selectionParameters,
MappingBuilderContext ctx,
Set<String> existingVariableNames) {
return collectLifecycleCallbackMethods( method,
method.getResultType(),
selectionParameters,
filterAfterMappingMethods( getAllAvailableMethods( method, ctx.getSourceModel() ) ),
ctx,
existingVariableNames );
}

/**
* @param method the method to obtain the afterMapping methods for
* @param selectionParameters method selectionParameters
* @param ctx the builder context
* @param existingVariableNames list of already used variable names
* @return all applicable {@code @AfterMapping} methods for the given method
*/
public static List<LifecycleCallbackMethodReference> afterMappingMethods(Method method,
SelectionParameters selectionParameters,
MappingBuilderContext ctx,
Set<String> existingVariableNames) {
return collectLifecycleCallbackMethods( method,
method.getResultType(),
selectionParameters,
filterAfterMappingMethods( getAllAvailableMethods( method, ctx.getSourceModel() ) ),
ctx,
Expand Down Expand Up @@ -87,18 +131,12 @@ private static List<SourceMethod> getAllAvailableMethods(Method method, List<Sou
}

private static List<LifecycleCallbackMethodReference> collectLifecycleCallbackMethods(
Method method, SelectionParameters selectionParameters, List<SourceMethod> callbackMethods,
Method method, Type targetType, SelectionParameters selectionParameters, List<SourceMethod> callbackMethods,
MappingBuilderContext ctx, Set<String> existingVariableNames) {

MethodSelectors selectors =
new MethodSelectors( ctx.getTypeUtils(), ctx.getElementUtils(), ctx.getTypeFactory(), ctx.getMessager() );

Type targetType = method.getResultType();

if ( !method.isUpdateMethod() ) {
targetType = targetType.getEffectiveType();
}

List<SelectedMethod<SourceMethod>> matchingMethods = selectors.getMatchingMethods(
method,
callbackMethods,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -181,7 +181,7 @@ public MapMappingMethod build() {
MethodReference factoryMethod = null;
if ( !method.isUpdateMethod() ) {
factoryMethod = ObjectFactoryMethodResolver
.getFactoryMethod( method, method.getResultType(), null, ctx );
.getFactoryMethod( method, null, ctx );
}


Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -155,7 +155,7 @@ public void setAssignment( Assignment assignment ) {

@Override
public String getSourceReference() {
return assignment.getSourceReference();
return assignment != null ? assignment.getSourceReference() : null;
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,17 +38,35 @@ private ObjectFactoryMethodResolver() {
* returns a no arg factory method
*
* @param method target mapping method
* @param targetType return type to match
* @param selectionParameters parameters used in the selection process
* @param ctx
*
* @return a method reference to the factory method, or null if no suitable, or ambiguous method found
*
*/
public static MethodReference getFactoryMethod( Method method,
Type targetType,
SelectionParameters selectionParameters,
MappingBuilderContext ctx) {
return getFactoryMethod( method, method.getResultType(), selectionParameters, ctx );
}



/**
* returns a no arg factory method
*
* @param method target mapping method
* @param alternativeTarget alternative to {@link Method#getResultType()} e.g. when target is abstract
* @param selectionParameters parameters used in the selection process
* @param ctx
*
* @return a method reference to the factory method, or null if no suitable, or ambiguous method found
*
*/
public static MethodReference getFactoryMethod( Method method,
Type alternativeTarget,
SelectionParameters selectionParameters,
MappingBuilderContext ctx) {

MethodSelectors selectors =
new MethodSelectors( ctx.getTypeUtils(), ctx.getElementUtils(), ctx.getTypeFactory(), ctx.getMessager() );
Expand All @@ -58,18 +76,18 @@ public static MethodReference getFactoryMethod( Method method,
method,
getAllAvailableMethods( method, ctx.getSourceModel() ),
java.util.Collections.<Type> emptyList(),
targetType.getEffectiveType(),
alternativeTarget,
SelectionCriteria.forFactoryMethods( selectionParameters ) );

if (matchingFactoryMethods.isEmpty()) {
return findBuilderFactoryMethod( targetType );
return null;
}

if ( matchingFactoryMethods.size() > 1 ) {
ctx.getMessager().printMessage(
method.getExecutable(),
Message.GENERAL_AMBIGIOUS_FACTORY_METHOD,
targetType.getEffectiveType(),
alternativeTarget,
Strings.join( matchingFactoryMethods, ", " ) );

return null;
Expand Down Expand Up @@ -98,8 +116,7 @@ java.util.Collections.<Type> emptyList(),
}
}

private static MethodReference findBuilderFactoryMethod(Type targetType) {
BuilderType builder = targetType.getBuilderType();
public static MethodReference getBuilderFactoryMethod(Method method, BuilderType builder) {
if ( builder == null ) {
return null;
}
Expand All @@ -110,7 +127,7 @@ private static MethodReference findBuilderFactoryMethod(Type targetType) {
return null;
}

if ( !builder.getBuildingType().isAssignableTo( targetType ) ) {
if ( !builder.getBuildingType().isAssignableTo( method.getReturnType() ) ) {
//TODO print error message
return null;
}
Expand Down
Loading

0 comments on commit 9e487a2

Please sign in to comment.