Skip to content

Commit b6cb85b

Browse files
committed
Support CollectionMappingStrategy on @Mapping
Signed-off-by: Hyeonsoo Lee <znight1020@naver.com>
1 parent 9d7549d commit b6cb85b

6 files changed

Lines changed: 57 additions & 2 deletions

File tree

core/src/main/java/org/mapstruct/Mapping.java

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -490,6 +490,21 @@
490490
NullValuePropertyMappingStrategy nullValuePropertyMappingStrategy()
491491
default NullValuePropertyMappingStrategy.SET_TO_NULL;
492492

493+
/**
494+
* The strategy to be applied when mapping a target {@code Collection} property.
495+
*
496+
* Can be overridden by the one on {@link MapperConfig}, {@link Mapper} or {@link BeanMapping}.
497+
*
498+
* If no strategy is configured, the strategy given via {@link MapperConfig#collectionMappingStrategy()},
499+
* {@link BeanMapping#collectionMappingStrategy()} or {@link Mapper#collectionMappingStrategy()} will be applied.
500+
*
501+
* {@link CollectionMappingStrategy#ACCESSOR_ONLY} will be used by default.
502+
*
503+
* @since 1.7
504+
* @return The collection mapping strategy to be applied for the designated target property
505+
*/
506+
CollectionMappingStrategy collectionMappingStrategy() default CollectionMappingStrategy.ACCESSOR_ONLY;
507+
493508
/**
494509
* Allows detailed control over the mapping process.
495510
*

processor/src/main/java/org/mapstruct/ap/internal/model/CollectionAssignmentBuilder.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -137,7 +137,7 @@ public CollectionAssignmentBuilder nullValuePropertyMappingStrategy( NullValuePr
137137
public Assignment build() {
138138
Assignment result = assignment;
139139

140-
CollectionMappingStrategyGem cms = method.getOptions().getBeanMapping().getCollectionMappingStrategy();
140+
CollectionMappingStrategyGem cms = method.getOptions().getCollectionMappingStrategyFor( targetPropertyName );
141141
boolean targetImmutable = cms == CollectionMappingStrategyGem.TARGET_IMMUTABLE || targetReadAccessor == null;
142142

143143
if ( targetAccessorType == AccessorType.SETTER || targetAccessorType.isFieldAssignment() ) {

processor/src/main/java/org/mapstruct/ap/internal/model/source/MappingMethodOptions.java

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -380,6 +380,17 @@ private String getFirstTargetPropertyName(MappingOptions mapping) {
380380
return getPropertyEntries( mapping )[0];
381381
}
382382

383+
public CollectionMappingStrategyGem getCollectionMappingStrategyFor(String targetProperty) {
384+
if ( targetProperty != null && mappings != null ) {
385+
for ( MappingOptions m : mappings ) {
386+
if ( targetProperty.equals( m.getTargetName() ) && m.getCollectionMappingStrategy() != null ) {
387+
return CollectionMappingStrategyGem.valueOf( m.getCollectionMappingStrategy().name() );
388+
}
389+
}
390+
}
391+
return getBeanMapping().getCollectionMappingStrategy();
392+
}
393+
383394
/**
384395
* SubclassMappingOptions are not inherited to forged methods. They would result in an infinite loop if they were.
385396
*

processor/src/main/java/org/mapstruct/ap/internal/model/source/MappingOptions.java

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
import javax.lang.model.element.Element;
2020
import javax.lang.model.element.ExecutableElement;
2121

22+
import org.mapstruct.ap.internal.gem.CollectionMappingStrategyGem;
2223
import org.mapstruct.ap.internal.gem.MappingGem;
2324
import org.mapstruct.ap.internal.gem.MappingsGem;
2425
import org.mapstruct.ap.internal.gem.NullValueCheckStrategyGem;
@@ -472,6 +473,16 @@ public NullValuePropertyMappingStrategyGem getNullValuePropertyMappingStrategy()
472473
.orElse( next().getNullValuePropertyMappingStrategy() );
473474
}
474475

476+
@Override
477+
public CollectionMappingStrategyGem getCollectionMappingStrategy() {
478+
return Optional.ofNullable( mapping )
479+
.map( MappingGem::collectionMappingStrategy )
480+
.filter( GemValue::hasValue )
481+
.map( GemValue::getValue )
482+
.map( CollectionMappingStrategyGem::valueOf )
483+
.orElse( next().getCollectionMappingStrategy() );
484+
}
485+
475486
@Override
476487
public MappingControl getMappingControl(ElementUtils elementUtils) {
477488
return Optional.ofNullable( mapping ).map( MappingGem::mappingControl )

processor/src/test/java/org/mapstruct/ap/test/bugs/_3708/Issue3708TargetImmutableMapper.java

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,12 +16,18 @@
1616
import org.mapstruct.factory.Mappers;
1717

1818
/**
19-
* BeanMapping TARGET_IMMUTABLE
19+
* Mapping, BeanMapping TARGET_IMMUTABLE
2020
*/
2121
@Mapper
2222
public interface Issue3708TargetImmutableMapper {
2323
Issue3708TargetImmutableMapper INSTANCE = Mappers.getMapper( Issue3708TargetImmutableMapper.class );
2424

25+
@Mapping(target = "types",
26+
nullValuePropertyMappingStrategy = NullValuePropertyMappingStrategy.IGNORE,
27+
collectionMappingStrategy = CollectionMappingStrategy.TARGET_IMMUTABLE
28+
)
29+
void partialUpdateMapping(@MappingTarget Partner entity, PartnerDto dto);
30+
2531
@BeanMapping(
2632
nullValuePropertyMappingStrategy = NullValuePropertyMappingStrategy.IGNORE,
2733
collectionMappingStrategy = CollectionMappingStrategy.TARGET_IMMUTABLE

processor/src/test/java/org/mapstruct/ap/test/bugs/_3708/Issue3708Test.java

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,18 @@ void beanMappingTargetImmutableShouldReplaceWhenUpdatesImmutableTarget() {
5454
assertThat( entity.getTypes() ).containsExactlyInAnyOrder( "B", "C" );
5555
}
5656

57+
@ProcessorTest
58+
void mappingTargetImmutableShouldReplaceWhenUpdatesImmutableTarget() {
59+
Partner entity = new Partner();
60+
entity.setTypes( Set.of( "A" ) );
61+
PartnerDto dto = new PartnerDto();
62+
dto.setTypes( new LinkedHashSet<>( Set.of( "B", "C" ) ) );
63+
64+
Issue3708TargetImmutableMapper.INSTANCE.partialUpdateMapping( entity, dto );
65+
66+
assertThat( entity.getTypes() ).containsExactlyInAnyOrder( "B", "C" );
67+
}
68+
5769
@ProcessorTest
5870
void clearAndAddAllShouldNotGenerateWhenTargetImmutable() {
5971
generated.forMapper( Issue3708TargetImmutableMapper.class )

0 commit comments

Comments
 (0)