Skip to content

Commit e32fc8c

Browse files
hpoettkerfiliphr
authored andcommitted
mapstruct#2351 NullValueMappingStrategy for Maps and Iterables
With two new parameters for Mapper and MapperConfig, it is now possible to override the nullValueMappingStrategy specifically for MapMapping and IterableMapping.
1 parent 80d26a1 commit e32fc8c

18 files changed

+453
-32
lines changed

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

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -203,6 +203,32 @@
203203
*/
204204
NullValueMappingStrategy nullValueMappingStrategy() default NullValueMappingStrategy.RETURN_NULL;
205205

206+
/**
207+
* The strategy to be applied when {@code null} is passed as source argument value to an {@link IterableMapping} of
208+
* this mapper. If unset, the strategy set with {@link #nullValueMappingStrategy()} will be applied. If neither
209+
* strategy is configured, the strategy given via {@link MapperConfig#nullValueIterableMappingStrategy()} will be
210+
* applied, using {@link NullValueMappingStrategy#RETURN_NULL} by default.
211+
*
212+
* @since 1.5
213+
*
214+
* @return The strategy to be applied when {@code null} is passed as source value to an {@link IterableMapping} of
215+
* this mapper.
216+
*/
217+
NullValueMappingStrategy nullValueIterableMappingStrategy() default NullValueMappingStrategy.RETURN_NULL;
218+
219+
/**
220+
* The strategy to be applied when {@code null} is passed as source argument value to a {@link MapMapping} of this
221+
* mapper. If unset, the strategy set with {@link #nullValueMappingStrategy()} will be applied. If neither strategy
222+
* is configured, the strategy given via {@link MapperConfig#nullValueMapMappingStrategy()} will be applied, using
223+
* {@link NullValueMappingStrategy#RETURN_NULL} by default.
224+
*
225+
* @since 1.5
226+
*
227+
* @return The strategy to be applied when {@code null} is passed as source value to a {@link MapMapping} of this
228+
* mapper.
229+
*/
230+
NullValueMappingStrategy nullValueMapMappingStrategy() default NullValueMappingStrategy.RETURN_NULL;
231+
206232
/**
207233
* The strategy to be applied when a source bean property is {@code null} or not present. If no strategy is
208234
* configured, the strategy given via {@link MapperConfig#nullValuePropertyMappingStrategy()} will be applied,

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

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -177,6 +177,28 @@
177177
*/
178178
NullValueMappingStrategy nullValueMappingStrategy() default NullValueMappingStrategy.RETURN_NULL;
179179

180+
/**
181+
* The strategy to be applied when {@code null} is passed as source argument value to an {@link IterableMapping}.
182+
* If no strategy is configured, the strategy given via {@link #nullValueMappingStrategy()} will be applied, using
183+
* {@link NullValueMappingStrategy#RETURN_NULL} by default.
184+
*
185+
* @since 1.5
186+
*
187+
* @return The strategy to be applied when {@code null} is passed as source value to an {@link IterableMapping}.
188+
*/
189+
NullValueMappingStrategy nullValueIterableMappingStrategy() default NullValueMappingStrategy.RETURN_NULL;
190+
191+
/**
192+
* The strategy to be applied when {@code null} is passed as source argument value to a {@link MapMapping}.
193+
* If no strategy is configured, the strategy given via {@link #nullValueMappingStrategy()} will be applied, using
194+
* {@link NullValueMappingStrategy#RETURN_NULL} by default.
195+
*
196+
* @since 1.5
197+
*
198+
* @return The strategy to be applied when {@code null} is passed as source value to a {@link MapMapping}.
199+
*/
200+
NullValueMappingStrategy nullValueMapMappingStrategy() default NullValueMappingStrategy.RETURN_NULL;
201+
180202
/**
181203
* The strategy to be applied when a source bean property is {@code null} or not present. If no strategy is
182204
* configured, {@link NullValuePropertyMappingStrategy#SET_TO_NULL} will be used by default.

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

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,14 @@ public SubclassExhaustiveStrategyGem getSubclassExhaustiveStrategy() {
124124
return SubclassExhaustiveStrategyGem.valueOf( mapper.subclassExhaustiveStrategy().getDefaultValue() );
125125
}
126126

127+
public NullValueMappingStrategyGem getNullValueIterableMappingStrategy() {
128+
return NullValueMappingStrategyGem.valueOf( mapper.nullValueIterableMappingStrategy().getDefaultValue() );
129+
}
130+
131+
public NullValueMappingStrategyGem getNullValueMapMappingStrategy() {
132+
return NullValueMappingStrategyGem.valueOf( mapper.nullValueMapMappingStrategy().getDefaultValue() );
133+
}
134+
127135
public BuilderGem getBuilder() {
128136
// TODO: I realized this is not correct, however it needs to be null in order to keep downward compatibility
129137
// but assuming a default @Builder will make testcases fail. Not having a default means that you need to

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

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,14 @@ public SubclassExhaustiveStrategyGem getSubclassExhaustiveStrategy() {
102102
return next.getSubclassExhaustiveStrategy();
103103
}
104104

105+
public NullValueMappingStrategyGem getNullValueIterableMappingStrategy() {
106+
return next.getNullValueIterableMappingStrategy();
107+
}
108+
109+
public NullValueMappingStrategyGem getNullValueMapMappingStrategy() {
110+
return next.getNullValueMapMappingStrategy();
111+
}
112+
105113
public BuilderGem getBuilder() {
106114
return next.getBuilder();
107115
}

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

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -30,11 +30,11 @@ public class IterableMappingOptions extends DelegatingOptions {
3030
private final IterableMappingGem iterableMapping;
3131

3232
public static IterableMappingOptions fromGem(IterableMappingGem iterableMapping,
33-
MapperOptions mappperOptions, ExecutableElement method,
33+
MapperOptions mapperOptions, ExecutableElement method,
3434
FormattingMessager messager, TypeUtils typeUtils) {
3535

3636
if ( iterableMapping == null || !isConsistent( iterableMapping, method, messager ) ) {
37-
IterableMappingOptions options = new IterableMappingOptions( null, null, null, mappperOptions );
37+
IterableMappingOptions options = new IterableMappingOptions( null, null, null, mapperOptions );
3838
return options;
3939
}
4040

@@ -54,7 +54,7 @@ public static IterableMappingOptions fromGem(IterableMappingGem iterableMapping,
5454
);
5555

5656
IterableMappingOptions options =
57-
new IterableMappingOptions( formatting, selection, iterableMapping, mappperOptions );
57+
new IterableMappingOptions( formatting, selection, iterableMapping, mapperOptions );
5858
return options;
5959
}
6060

@@ -99,7 +99,7 @@ public NullValueMappingStrategyGem getNullValueMappingStrategy() {
9999
.filter( GemValue::hasValue )
100100
.map( GemValue::getValue )
101101
.map( NullValueMappingStrategyGem::valueOf )
102-
.orElse( next().getNullValueMappingStrategy() );
102+
.orElse( next().getNullValueIterableMappingStrategy() );
103103
}
104104

105105
public MappingControl getElementMappingControl(ElementUtils elementUtils) {

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -144,7 +144,7 @@ public NullValueMappingStrategyGem getNullValueMappingStrategy() {
144144
.filter( GemValue::hasValue )
145145
.map( GemValue::getValue )
146146
.map( NullValueMappingStrategyGem::valueOf )
147-
.orElse( next().getNullValueMappingStrategy() );
147+
.orElse( next().getNullValueMapMappingStrategy() );
148148
}
149149

150150
public MappingControl getKeyMappingControl(ElementUtils elementUtils) {

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

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,28 @@ public SubclassExhaustiveStrategyGem getSubclassExhaustiveStrategy() {
134134
next().getSubclassExhaustiveStrategy();
135135
}
136136

137+
@Override
138+
public NullValueMappingStrategyGem getNullValueIterableMappingStrategy() {
139+
if ( mapperConfig.nullValueIterableMappingStrategy().hasValue() ) {
140+
return NullValueMappingStrategyGem.valueOf( mapperConfig.nullValueIterableMappingStrategy().get() );
141+
}
142+
if ( mapperConfig.nullValueMappingStrategy().hasValue() ) {
143+
return NullValueMappingStrategyGem.valueOf( mapperConfig.nullValueMappingStrategy().get() );
144+
}
145+
return next().getNullValueIterableMappingStrategy();
146+
}
147+
148+
@Override
149+
public NullValueMappingStrategyGem getNullValueMapMappingStrategy() {
150+
if ( mapperConfig.nullValueMapMappingStrategy().hasValue() ) {
151+
return NullValueMappingStrategyGem.valueOf( mapperConfig.nullValueMapMappingStrategy().get() );
152+
}
153+
if ( mapperConfig.nullValueMappingStrategy().hasValue() ) {
154+
return NullValueMappingStrategyGem.valueOf( mapperConfig.nullValueMappingStrategy().get() );
155+
}
156+
return next().getNullValueMapMappingStrategy();
157+
}
158+
137159
@Override
138160
public BuilderGem getBuilder() {
139161
return mapperConfig.builder().hasValue() ? mapperConfig.builder().get() : next().getBuilder();

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

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -163,6 +163,28 @@ public SubclassExhaustiveStrategyGem getSubclassExhaustiveStrategy() {
163163
next().getSubclassExhaustiveStrategy();
164164
}
165165

166+
@Override
167+
public NullValueMappingStrategyGem getNullValueIterableMappingStrategy() {
168+
if ( mapper.nullValueIterableMappingStrategy().hasValue() ) {
169+
return NullValueMappingStrategyGem.valueOf( mapper.nullValueIterableMappingStrategy().get() );
170+
}
171+
if ( mapper.nullValueMappingStrategy().hasValue() ) {
172+
return NullValueMappingStrategyGem.valueOf( mapper.nullValueMappingStrategy().get() );
173+
}
174+
return next().getNullValueIterableMappingStrategy();
175+
}
176+
177+
@Override
178+
public NullValueMappingStrategyGem getNullValueMapMappingStrategy() {
179+
if ( mapper.nullValueMapMappingStrategy().hasValue() ) {
180+
return NullValueMappingStrategyGem.valueOf( mapper.nullValueMapMappingStrategy().get() );
181+
}
182+
if ( mapper.nullValueMappingStrategy().hasValue() ) {
183+
return NullValueMappingStrategyGem.valueOf( mapper.nullValueMappingStrategy().get() );
184+
}
185+
return next().getNullValueMapMappingStrategy();
186+
}
187+
166188
@Override
167189
public BuilderGem getBuilder() {
168190
return mapper.builder().hasValue() ? mapper.builder().get() : next().getBuilder();

processor/src/test/java/org/mapstruct/ap/test/nullvaluemapping/CarMapper.java

Lines changed: 5 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@
1616
import org.mapstruct.MapMapping;
1717
import org.mapstruct.Mapper;
1818
import org.mapstruct.Mapping;
19-
import org.mapstruct.Mappings;
2019
import org.mapstruct.ap.test.nullvaluemapping._target.CarDto;
2120
import org.mapstruct.ap.test.nullvaluemapping._target.DriverAndCarDto;
2221
import org.mapstruct.ap.test.nullvaluemapping.source.Car;
@@ -29,18 +28,14 @@ public interface CarMapper {
2928
CarMapper INSTANCE = Mappers.getMapper( CarMapper.class );
3029

3130
@BeanMapping(nullValueMappingStrategy = RETURN_DEFAULT)
32-
@Mappings({
33-
@Mapping(target = "seatCount", source = "numberOfSeats"),
34-
@Mapping(target = "model", constant = "ModelT"),
35-
@Mapping(target = "catalogId", expression = "java( UUID.randomUUID().toString() )")
36-
})
31+
@Mapping(target = "seatCount", source = "numberOfSeats")
32+
@Mapping(target = "model", constant = "ModelT")
33+
@Mapping(target = "catalogId", expression = "java( UUID.randomUUID().toString() )")
3734
CarDto carToCarDto(Car car);
3835

3936
@BeanMapping(nullValueMappingStrategy = RETURN_DEFAULT)
40-
@Mappings({
41-
@Mapping(target = "seatCount", source = "car.numberOfSeats"),
42-
@Mapping(target = "catalogId", expression = "java( UUID.randomUUID().toString() )")
43-
})
37+
@Mapping(target = "seatCount", source = "car.numberOfSeats")
38+
@Mapping(target = "catalogId", expression = "java( UUID.randomUUID().toString() )")
4439
CarDto carToCarDto(Car car, String model);
4540

4641
@IterableMapping(nullValueMappingStrategy = RETURN_DEFAULT)
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
/*
2+
* Copyright MapStruct Authors.
3+
*
4+
* Licensed under the Apache License version 2.0, available at http://www.apache.org/licenses/LICENSE-2.0
5+
*/
6+
package org.mapstruct.ap.test.nullvaluemapping;
7+
8+
import java.util.List;
9+
import java.util.Map;
10+
import java.util.UUID;
11+
12+
import org.mapstruct.IterableMapping;
13+
import org.mapstruct.MapMapping;
14+
import org.mapstruct.Mapper;
15+
import org.mapstruct.Mapping;
16+
import org.mapstruct.ap.test.nullvaluemapping._target.CarDto;
17+
import org.mapstruct.ap.test.nullvaluemapping.source.Car;
18+
import org.mapstruct.factory.Mappers;
19+
20+
@Mapper(imports = UUID.class, config = CentralIterableMappingConfig.class)
21+
public interface CarMapperIterableSettingOnConfig {
22+
23+
CarMapperIterableSettingOnConfig INSTANCE = Mappers.getMapper( CarMapperIterableSettingOnConfig.class );
24+
25+
@Mapping(target = "seatCount", source = "numberOfSeats")
26+
@Mapping(target = "model", constant = "ModelT")
27+
@Mapping(target = "catalogId", expression = "java( UUID.randomUUID().toString() )")
28+
CarDto carToCarDto(Car car);
29+
30+
@IterableMapping(dateFormat = "dummy")
31+
List<CarDto> carsToCarDtos(List<Car> cars);
32+
33+
@MapMapping(valueDateFormat = "dummy")
34+
Map<Integer, CarDto> carsToCarDtoMap(Map<Integer, Car> cars);
35+
}

0 commit comments

Comments
 (0)