mirror of
https://github.com/mapstruct/mapstruct.git
synced 2025-07-12 00:00:08 +08:00
#3678 Prevent duplicate @BeforeMapping and @AfterMapping calls on classes that use the Builder pattern.
This commit is contained in:
parent
b452d7f2c8
commit
b74bde5c22
@ -406,9 +406,11 @@ public class BeanMappingMethod extends NormalTypeMappingMethod {
|
|||||||
existingVariableNames
|
existingVariableNames
|
||||||
) );
|
) );
|
||||||
|
|
||||||
// remove methods without parameters as they are already being invoked
|
// remove methods that are already being invoked
|
||||||
removeMappingReferencesWithoutSourceParameters( beforeMappingReferencesWithFinalizedReturnType );
|
removeMappingReferencesWithoutSourceParameters( beforeMappingReferencesWithFinalizedReturnType );
|
||||||
removeMappingReferencesWithoutSourceParameters( afterMappingReferencesWithFinalizedReturnType );
|
removeMappingReferencesWithoutSourceParameters( afterMappingReferencesWithFinalizedReturnType );
|
||||||
|
removeMappingReferencesWithSingleSourceParameter( beforeMappingReferencesWithFinalizedReturnType );
|
||||||
|
removeMappingReferencesWithSingleSourceParameter( afterMappingReferencesWithFinalizedReturnType );
|
||||||
}
|
}
|
||||||
|
|
||||||
Map<String, PresenceCheck> presenceChecksByParameter = new LinkedHashMap<>();
|
Map<String, PresenceCheck> presenceChecksByParameter = new LinkedHashMap<>();
|
||||||
@ -455,6 +457,17 @@ public class BeanMappingMethod extends NormalTypeMappingMethod {
|
|||||||
references.removeIf( r -> r.getSourceParameters().isEmpty() && r.getReturnType().isVoid() );
|
references.removeIf( r -> r.getSourceParameters().isEmpty() && r.getReturnType().isVoid() );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void removeMappingReferencesWithSingleSourceParameter(
|
||||||
|
List<LifecycleCallbackMethodReference> references) {
|
||||||
|
references.removeIf( Builder::isSingleSourceParameter );
|
||||||
|
}
|
||||||
|
|
||||||
|
private static boolean isSingleSourceParameter(LifecycleCallbackMethodReference reference) {
|
||||||
|
return reference.getParameterBindings().size() == 1
|
||||||
|
&& reference.getParameterBindings().stream().allMatch( ParameterBinding::isSourceParameter )
|
||||||
|
&& reference.getReturnType().isVoid();
|
||||||
|
}
|
||||||
|
|
||||||
private boolean doesNotAllowAbstractReturnTypeAndCanBeConstructed(Type returnTypeImpl) {
|
private boolean doesNotAllowAbstractReturnTypeAndCanBeConstructed(Type returnTypeImpl) {
|
||||||
return !isAbstractReturnTypeAllowed()
|
return !isAbstractReturnTypeAllowed()
|
||||||
&& canReturnTypeBeConstructed( returnTypeImpl );
|
&& canReturnTypeBeConstructed( returnTypeImpl );
|
||||||
|
@ -7,9 +7,11 @@ package org.mapstruct.ap.test.builder.lifecycle;
|
|||||||
|
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
|
|
||||||
|
import org.junit.jupiter.api.extension.RegisterExtension;
|
||||||
import org.mapstruct.ap.testutil.IssueKey;
|
import org.mapstruct.ap.testutil.IssueKey;
|
||||||
import org.mapstruct.ap.testutil.ProcessorTest;
|
import org.mapstruct.ap.testutil.ProcessorTest;
|
||||||
import org.mapstruct.ap.testutil.WithClasses;
|
import org.mapstruct.ap.testutil.WithClasses;
|
||||||
|
import org.mapstruct.ap.testutil.runner.GeneratedSource;
|
||||||
|
|
||||||
import static org.assertj.core.api.Assertions.assertThat;
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
|
|
||||||
@ -27,6 +29,9 @@ import static org.assertj.core.api.Assertions.assertThat;
|
|||||||
} )
|
} )
|
||||||
public class BuilderLifecycleCallbacksTest {
|
public class BuilderLifecycleCallbacksTest {
|
||||||
|
|
||||||
|
@RegisterExtension
|
||||||
|
final GeneratedSource source = new GeneratedSource().addComparisonToFixtureFor( OrderMapper.class );
|
||||||
|
|
||||||
@ProcessorTest
|
@ProcessorTest
|
||||||
public void lifecycleMethodsShouldBeInvoked() {
|
public void lifecycleMethodsShouldBeInvoked() {
|
||||||
OrderDto source = new OrderDto();
|
OrderDto source = new OrderDto();
|
||||||
@ -43,6 +48,7 @@ public class BuilderLifecycleCallbacksTest {
|
|||||||
assertThat( context.getInvokedMethods() )
|
assertThat( context.getInvokedMethods() )
|
||||||
.contains(
|
.contains(
|
||||||
"beforeWithoutParameters",
|
"beforeWithoutParameters",
|
||||||
|
"beforeWithSource",
|
||||||
"beforeWithTargetType",
|
"beforeWithTargetType",
|
||||||
"beforeWithBuilderTargetType",
|
"beforeWithBuilderTargetType",
|
||||||
"beforeWithBuilderTarget",
|
"beforeWithBuilderTarget",
|
||||||
@ -50,6 +56,7 @@ public class BuilderLifecycleCallbacksTest {
|
|||||||
"afterWithBuilderTargetType",
|
"afterWithBuilderTargetType",
|
||||||
"afterWithBuilderTarget",
|
"afterWithBuilderTarget",
|
||||||
"afterWithBuilderTargetReturningTarget",
|
"afterWithBuilderTargetReturningTarget",
|
||||||
|
"afterWithSource",
|
||||||
"afterWithTargetType",
|
"afterWithTargetType",
|
||||||
"afterWithTarget",
|
"afterWithTarget",
|
||||||
"afterWithTargetReturningTarget"
|
"afterWithTargetReturningTarget"
|
||||||
|
@ -25,6 +25,11 @@ public class MappingContext {
|
|||||||
invokedMethods.add( "beforeWithoutParameters" );
|
invokedMethods.add( "beforeWithoutParameters" );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@BeforeMapping
|
||||||
|
public void beforeWithSource(OrderDto source) {
|
||||||
|
invokedMethods.add( "beforeWithSource" );
|
||||||
|
}
|
||||||
|
|
||||||
@BeforeMapping
|
@BeforeMapping
|
||||||
public void beforeWithTargetType(OrderDto source, @TargetType Class<Order> orderClass) {
|
public void beforeWithTargetType(OrderDto source, @TargetType Class<Order> orderClass) {
|
||||||
invokedMethods.add( "beforeWithTargetType" );
|
invokedMethods.add( "beforeWithTargetType" );
|
||||||
@ -50,6 +55,11 @@ public class MappingContext {
|
|||||||
invokedMethods.add( "afterWithoutParameters" );
|
invokedMethods.add( "afterWithoutParameters" );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@AfterMapping
|
||||||
|
public void afterWithSource(OrderDto source) {
|
||||||
|
invokedMethods.add( "afterWithSource" );
|
||||||
|
}
|
||||||
|
|
||||||
@AfterMapping
|
@AfterMapping
|
||||||
public void afterWithTargetType(OrderDto source, @TargetType Class<Order> orderClass) {
|
public void afterWithTargetType(OrderDto source, @TargetType Class<Order> orderClass) {
|
||||||
invokedMethods.add( "afterWithTargetType" );
|
invokedMethods.add( "afterWithTargetType" );
|
||||||
|
@ -0,0 +1,91 @@
|
|||||||
|
/*
|
||||||
|
* 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.test.builder.lifecycle;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import javax.annotation.processing.Generated;
|
||||||
|
|
||||||
|
@Generated(
|
||||||
|
value = "org.mapstruct.ap.MappingProcessor",
|
||||||
|
date = "2024-08-21T23:18:51+0200",
|
||||||
|
comments = "version: , compiler: javac, environment: Java 21.0.1 (Oracle Corporation)"
|
||||||
|
)
|
||||||
|
public class OrderMapperImpl implements OrderMapper {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Order map(OrderDto source, MappingContext context) {
|
||||||
|
context.beforeWithoutParameters();
|
||||||
|
context.beforeWithSource( source );
|
||||||
|
context.beforeWithBuilderTargetType( source, Order.Builder.class );
|
||||||
|
|
||||||
|
context.beforeWithTargetType( source, Order.class );
|
||||||
|
|
||||||
|
if ( source == null ) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
Order.Builder order = Order.builder();
|
||||||
|
|
||||||
|
context.beforeWithBuilderTarget( source, order );
|
||||||
|
|
||||||
|
order.items( itemDtoListToItemList( source.getItems(), context ) );
|
||||||
|
|
||||||
|
context.afterWithoutParameters();
|
||||||
|
context.afterWithSource( source );
|
||||||
|
context.afterWithBuilderTargetType( source, Order.Builder.class );
|
||||||
|
context.afterWithBuilderTarget( source, order );
|
||||||
|
Order target = context.afterWithBuilderTargetReturningTarget( order );
|
||||||
|
if ( target != null ) {
|
||||||
|
return target;
|
||||||
|
}
|
||||||
|
|
||||||
|
Order orderResult = order.create();
|
||||||
|
|
||||||
|
context.afterWithTargetType( source, Order.class );
|
||||||
|
context.afterWithTarget( source, orderResult );
|
||||||
|
Order target1 = context.afterWithTargetReturningTarget( orderResult );
|
||||||
|
if ( target1 != null ) {
|
||||||
|
return target1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return orderResult;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Item map(ItemDto source, MappingContext context) {
|
||||||
|
context.beforeWithoutParameters();
|
||||||
|
|
||||||
|
if ( source == null ) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
Item.Builder item = Item.builder();
|
||||||
|
|
||||||
|
item.name( source.getName() );
|
||||||
|
|
||||||
|
context.afterWithoutParameters();
|
||||||
|
|
||||||
|
return item.create();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected List<Item> itemDtoListToItemList(List<ItemDto> list, MappingContext context) {
|
||||||
|
context.beforeWithoutParameters();
|
||||||
|
|
||||||
|
if ( list == null ) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
List<Item> list1 = new ArrayList<Item>( list.size() );
|
||||||
|
for ( ItemDto itemDto : list ) {
|
||||||
|
list1.add( map( itemDto, context ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
context.afterWithoutParameters();
|
||||||
|
|
||||||
|
return list1;
|
||||||
|
}
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user