mirror of
https://github.com/mapstruct/mapstruct.git
synced 2025-07-12 00:00:08 +08:00
#2953 Add support for globally defining nullValueMapMappingStrategy and nullValueIterableMappingStrategy
This commit is contained in:
parent
82b19b0d8a
commit
fd27380185
@ -266,6 +266,30 @@ If a policy is given for a specific bean mapping via `@BeanMapping#ignoreUnmappe
|
||||
disableBuilders`
|
||||
|If set to `true`, then MapStruct will not use builder patterns when doing the mapping. This is equivalent to doing `@Mapper( builder = @Builder( disableBuilder = true ) )` for all of your mappers.
|
||||
|`false`
|
||||
|
||||
|`mapstruct.nullValueIterableMappingStrategy`
|
||||
|The strategy to be applied when `null` is passed as a source value to an iterable mapping.
|
||||
|
||||
Supported values are:
|
||||
|
||||
* `RETURN_NULL`: if `null` is passed as a source value, then `null` will be returned
|
||||
* `RETURN_DEFAULT`: if `null` is passed then a default value (empty collection) will be returned
|
||||
|
||||
If a strategy is given for a specific mapper via `@Mapper#nullValueIterableMappingStrategy()`, the value from the annotation takes precedence.
|
||||
If a strategy is given for a specific iterable mapping via `@IterableMapping#nullValueMappingStrategy()`, it takes precedence over both `@Mapper#nullValueIterableMappingStrategy()` and the option.
|
||||
|`RETURN_NULL`
|
||||
|
||||
|`mapstruct.nullValueMapMappingStrategy`
|
||||
|The strategy to be applied when `null` is passed as a source value to a map mapping.
|
||||
|
||||
Supported values are:
|
||||
|
||||
* `RETURN_NULL`: if `null` is passed as a source value, then `null` will be returned
|
||||
* `RETURN_DEFAULT`: if `null` is passed then a default value (empty map) will be returned
|
||||
|
||||
If a strategy is given for a specific mapper via `@Mapper#nullValueMapMappingStrategy()`, the value from the annotation takes precedence.
|
||||
If a strategy is given for a specific map mapping via `@MapMapping#nullValueMappingStrategy()`, it takes precedence over both `@Mapper#nullValueMapMappingStrategy()` and the option.
|
||||
|`RETURN_NULL`
|
||||
|===
|
||||
|
||||
=== Using MapStruct with the Java Module System
|
||||
|
@ -12,6 +12,7 @@ import java.util.Comparator;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.ServiceLoader;
|
||||
import java.util.Set;
|
||||
@ -32,6 +33,7 @@ import javax.lang.model.type.TypeMirror;
|
||||
import javax.lang.model.util.ElementKindVisitor6;
|
||||
import javax.tools.Diagnostic.Kind;
|
||||
|
||||
import org.mapstruct.ap.internal.gem.NullValueMappingStrategyGem;
|
||||
import org.mapstruct.ap.internal.model.Mapper;
|
||||
import org.mapstruct.ap.internal.option.Options;
|
||||
import org.mapstruct.ap.internal.gem.MapperGem;
|
||||
@ -87,7 +89,9 @@ import static javax.lang.model.element.ElementKind.CLASS;
|
||||
MappingProcessor.DEFAULT_COMPONENT_MODEL,
|
||||
MappingProcessor.DEFAULT_INJECTION_STRATEGY,
|
||||
MappingProcessor.DISABLE_BUILDERS,
|
||||
MappingProcessor.VERBOSE
|
||||
MappingProcessor.VERBOSE,
|
||||
MappingProcessor.NULL_VALUE_ITERABLE_MAPPING_STRATEGY,
|
||||
MappingProcessor.NULL_VALUE_MAP_MAPPING_STRATEGY,
|
||||
})
|
||||
public class MappingProcessor extends AbstractProcessor {
|
||||
|
||||
@ -106,6 +110,8 @@ public class MappingProcessor extends AbstractProcessor {
|
||||
protected static final String ALWAYS_GENERATE_SERVICE_FILE = "mapstruct.alwaysGenerateServicesFile";
|
||||
protected static final String DISABLE_BUILDERS = "mapstruct.disableBuilders";
|
||||
protected static final String VERBOSE = "mapstruct.verbose";
|
||||
protected static final String NULL_VALUE_ITERABLE_MAPPING_STRATEGY = "mapstruct.nullValueIterableMappingStrategy";
|
||||
protected static final String NULL_VALUE_MAP_MAPPING_STRATEGY = "mapstruct.nullValueMapMappingStrategy";
|
||||
|
||||
private Options options;
|
||||
|
||||
@ -139,6 +145,9 @@ public class MappingProcessor extends AbstractProcessor {
|
||||
private Options createOptions() {
|
||||
String unmappedTargetPolicy = processingEnv.getOptions().get( UNMAPPED_TARGET_POLICY );
|
||||
String unmappedSourcePolicy = processingEnv.getOptions().get( UNMAPPED_SOURCE_POLICY );
|
||||
String nullValueIterableMappingStrategy = processingEnv.getOptions()
|
||||
.get( NULL_VALUE_ITERABLE_MAPPING_STRATEGY );
|
||||
String nullValueMapMappingStrategy = processingEnv.getOptions().get( NULL_VALUE_MAP_MAPPING_STRATEGY );
|
||||
|
||||
return new Options(
|
||||
Boolean.parseBoolean( processingEnv.getOptions().get( SUPPRESS_GENERATOR_TIMESTAMP ) ),
|
||||
@ -149,7 +158,12 @@ public class MappingProcessor extends AbstractProcessor {
|
||||
processingEnv.getOptions().get( DEFAULT_INJECTION_STRATEGY ),
|
||||
Boolean.parseBoolean( processingEnv.getOptions().get( ALWAYS_GENERATE_SERVICE_FILE ) ),
|
||||
Boolean.parseBoolean( processingEnv.getOptions().get( DISABLE_BUILDERS ) ),
|
||||
Boolean.parseBoolean( processingEnv.getOptions().get( VERBOSE ) )
|
||||
Boolean.parseBoolean( processingEnv.getOptions().get( VERBOSE ) ),
|
||||
nullValueIterableMappingStrategy != null ?
|
||||
NullValueMappingStrategyGem.valueOf( nullValueIterableMappingStrategy.toUpperCase( Locale.ROOT ) ) :
|
||||
null,
|
||||
nullValueMapMappingStrategy != null ?
|
||||
NullValueMappingStrategyGem.valueOf( nullValueMapMappingStrategy.toUpperCase( Locale.ROOT ) ) : null
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -132,10 +132,18 @@ public class DefaultOptions extends DelegatingOptions {
|
||||
}
|
||||
|
||||
public NullValueMappingStrategyGem getNullValueIterableMappingStrategy() {
|
||||
NullValueMappingStrategyGem nullValueIterableMappingStrategy = options.getNullValueIterableMappingStrategy();
|
||||
if ( nullValueIterableMappingStrategy != null ) {
|
||||
return nullValueIterableMappingStrategy;
|
||||
}
|
||||
return NullValueMappingStrategyGem.valueOf( mapper.nullValueIterableMappingStrategy().getDefaultValue() );
|
||||
}
|
||||
|
||||
public NullValueMappingStrategyGem getNullValueMapMappingStrategy() {
|
||||
NullValueMappingStrategyGem nullValueMapMappingStrategy = options.getNullValueMapMappingStrategy();
|
||||
if ( nullValueMapMappingStrategy != null ) {
|
||||
return nullValueMapMappingStrategy;
|
||||
}
|
||||
return NullValueMappingStrategyGem.valueOf( mapper.nullValueMapMappingStrategy().getDefaultValue() );
|
||||
}
|
||||
|
||||
|
@ -5,6 +5,7 @@
|
||||
*/
|
||||
package org.mapstruct.ap.internal.option;
|
||||
|
||||
import org.mapstruct.ap.internal.gem.NullValueMappingStrategyGem;
|
||||
import org.mapstruct.ap.internal.gem.ReportingPolicyGem;
|
||||
|
||||
/**
|
||||
@ -23,14 +24,21 @@ public class Options {
|
||||
private final String defaultInjectionStrategy;
|
||||
private final boolean disableBuilders;
|
||||
private final boolean verbose;
|
||||
private final NullValueMappingStrategyGem nullValueIterableMappingStrategy;
|
||||
private final NullValueMappingStrategyGem nullValueMapMappingStrategy;
|
||||
|
||||
//CHECKSTYLE:OFF
|
||||
public Options(boolean suppressGeneratorTimestamp, boolean suppressGeneratorVersionComment,
|
||||
ReportingPolicyGem unmappedTargetPolicy,
|
||||
ReportingPolicyGem unmappedSourcePolicy,
|
||||
String defaultComponentModel, String defaultInjectionStrategy,
|
||||
boolean alwaysGenerateSpi,
|
||||
boolean disableBuilders,
|
||||
boolean verbose) {
|
||||
boolean verbose,
|
||||
NullValueMappingStrategyGem nullValueIterableMappingStrategy,
|
||||
NullValueMappingStrategyGem nullValueMapMappingStrategy
|
||||
) {
|
||||
//CHECKSTYLE:ON
|
||||
this.suppressGeneratorTimestamp = suppressGeneratorTimestamp;
|
||||
this.suppressGeneratorVersionComment = suppressGeneratorVersionComment;
|
||||
this.unmappedTargetPolicy = unmappedTargetPolicy;
|
||||
@ -40,6 +48,8 @@ public class Options {
|
||||
this.alwaysGenerateSpi = alwaysGenerateSpi;
|
||||
this.disableBuilders = disableBuilders;
|
||||
this.verbose = verbose;
|
||||
this.nullValueIterableMappingStrategy = nullValueIterableMappingStrategy;
|
||||
this.nullValueMapMappingStrategy = nullValueMapMappingStrategy;
|
||||
}
|
||||
|
||||
public boolean isSuppressGeneratorTimestamp() {
|
||||
@ -77,4 +87,12 @@ public class Options {
|
||||
public boolean isVerbose() {
|
||||
return verbose;
|
||||
}
|
||||
|
||||
public NullValueMappingStrategyGem getNullValueIterableMappingStrategy() {
|
||||
return nullValueIterableMappingStrategy;
|
||||
}
|
||||
|
||||
public NullValueMappingStrategyGem getNullValueMapMappingStrategy() {
|
||||
return nullValueMapMappingStrategy;
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,30 @@
|
||||
/*
|
||||
* 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.nullvaluemapping;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.mapstruct.Mapper;
|
||||
import org.mapstruct.Mapping;
|
||||
import org.mapstruct.ap.test.nullvaluemapping._target.CarDto;
|
||||
import org.mapstruct.ap.test.nullvaluemapping.source.Car;
|
||||
import org.mapstruct.factory.Mappers;
|
||||
|
||||
/**
|
||||
* @author Filip Hrisafov
|
||||
*/
|
||||
@Mapper
|
||||
public interface CarListMapper {
|
||||
|
||||
CarListMapper INSTANCE = Mappers.getMapper( CarListMapper.class );
|
||||
|
||||
@Mapping(target = "seatCount", ignore = true)
|
||||
@Mapping(target = "model", ignore = true)
|
||||
@Mapping(target = "catalogId", ignore = true)
|
||||
CarDto map(Car car);
|
||||
|
||||
List<CarDto> carsToCarDtoList(List<Car> cars);
|
||||
}
|
@ -0,0 +1,31 @@
|
||||
/*
|
||||
* 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.nullvaluemapping;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.mapstruct.Mapper;
|
||||
import org.mapstruct.Mapping;
|
||||
import org.mapstruct.NullValueMappingStrategy;
|
||||
import org.mapstruct.ap.test.nullvaluemapping._target.CarDto;
|
||||
import org.mapstruct.ap.test.nullvaluemapping.source.Car;
|
||||
import org.mapstruct.factory.Mappers;
|
||||
|
||||
/**
|
||||
* @author Filip Hrisafov
|
||||
*/
|
||||
@Mapper(nullValueIterableMappingStrategy = NullValueMappingStrategy.RETURN_NULL)
|
||||
public interface CarListMapperSettingOnMapper {
|
||||
|
||||
CarListMapperSettingOnMapper INSTANCE = Mappers.getMapper( CarListMapperSettingOnMapper.class );
|
||||
|
||||
@Mapping(target = "seatCount", ignore = true)
|
||||
@Mapping(target = "model", ignore = true)
|
||||
@Mapping(target = "catalogId", ignore = true)
|
||||
CarDto map(Car car);
|
||||
|
||||
List<CarDto> carsToCarDtoList(List<Car> cars);
|
||||
}
|
@ -0,0 +1,30 @@
|
||||
/*
|
||||
* 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.nullvaluemapping;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import org.mapstruct.Mapper;
|
||||
import org.mapstruct.Mapping;
|
||||
import org.mapstruct.ap.test.nullvaluemapping._target.CarDto;
|
||||
import org.mapstruct.ap.test.nullvaluemapping.source.Car;
|
||||
import org.mapstruct.factory.Mappers;
|
||||
|
||||
/**
|
||||
* @author Filip Hrisafov
|
||||
*/
|
||||
@Mapper
|
||||
public interface CarMapMapper {
|
||||
|
||||
CarMapMapper INSTANCE = Mappers.getMapper( CarMapMapper.class );
|
||||
|
||||
@Mapping(target = "seatCount", ignore = true)
|
||||
@Mapping(target = "model", ignore = true)
|
||||
@Mapping(target = "catalogId", ignore = true)
|
||||
CarDto map(Car car);
|
||||
|
||||
Map<Integer, CarDto> carsToCarDtoMap(Map<Integer, Car> cars);
|
||||
}
|
@ -0,0 +1,31 @@
|
||||
/*
|
||||
* 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.nullvaluemapping;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import org.mapstruct.Mapper;
|
||||
import org.mapstruct.Mapping;
|
||||
import org.mapstruct.NullValueMappingStrategy;
|
||||
import org.mapstruct.ap.test.nullvaluemapping._target.CarDto;
|
||||
import org.mapstruct.ap.test.nullvaluemapping.source.Car;
|
||||
import org.mapstruct.factory.Mappers;
|
||||
|
||||
/**
|
||||
* @author Filip Hrisafov
|
||||
*/
|
||||
@Mapper(nullValueMapMappingStrategy = NullValueMappingStrategy.RETURN_NULL)
|
||||
public interface CarMapMapperSettingOnMapper {
|
||||
|
||||
CarMapMapperSettingOnMapper INSTANCE = Mappers.getMapper( CarMapMapperSettingOnMapper.class );
|
||||
|
||||
@Mapping(target = "seatCount", ignore = true)
|
||||
@Mapping(target = "model", ignore = true)
|
||||
@Mapping(target = "catalogId", ignore = true)
|
||||
CarDto map(Car car);
|
||||
|
||||
Map<Integer, CarDto> carsToCarDtoMap(Map<Integer, Car> cars);
|
||||
}
|
@ -0,0 +1,45 @@
|
||||
/*
|
||||
* 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.nullvaluemapping;
|
||||
|
||||
import org.mapstruct.ap.test.nullvaluemapping._target.CarDto;
|
||||
import org.mapstruct.ap.test.nullvaluemapping.source.Car;
|
||||
import org.mapstruct.ap.testutil.IssueKey;
|
||||
import org.mapstruct.ap.testutil.ProcessorTest;
|
||||
import org.mapstruct.ap.testutil.WithClasses;
|
||||
import org.mapstruct.ap.testutil.compilation.annotation.ProcessorOption;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
/**
|
||||
* @author Filip Hrisafov
|
||||
*/
|
||||
@WithClasses({
|
||||
CarDto.class,
|
||||
Car.class
|
||||
})
|
||||
@IssueKey("2953")
|
||||
public class NullValueIterableMappingStrategyTest {
|
||||
|
||||
@ProcessorTest
|
||||
@ProcessorOption(name = "mapstruct.nullValueIterableMappingStrategy", value = "return_default")
|
||||
@WithClasses({
|
||||
CarListMapper.class
|
||||
})
|
||||
void globalNullIterableMappingStrategy() {
|
||||
assertThat( CarListMapper.INSTANCE.carsToCarDtoList( null ) ).isEmpty();
|
||||
}
|
||||
|
||||
@ProcessorTest
|
||||
@ProcessorOption(name = "mapstruct.nullValueIterableMappingStrategy", value = "return_default")
|
||||
@WithClasses({
|
||||
CarListMapperSettingOnMapper.class
|
||||
})
|
||||
void globalNullMapMappingStrategyWithOverrideInMapper() {
|
||||
// Explicit definition in @Mapper should override global
|
||||
assertThat( CarListMapperSettingOnMapper.INSTANCE.carsToCarDtoList( null ) ).isNull();
|
||||
}
|
||||
}
|
@ -0,0 +1,45 @@
|
||||
/*
|
||||
* 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.nullvaluemapping;
|
||||
|
||||
import org.mapstruct.ap.test.nullvaluemapping._target.CarDto;
|
||||
import org.mapstruct.ap.test.nullvaluemapping.source.Car;
|
||||
import org.mapstruct.ap.testutil.IssueKey;
|
||||
import org.mapstruct.ap.testutil.ProcessorTest;
|
||||
import org.mapstruct.ap.testutil.WithClasses;
|
||||
import org.mapstruct.ap.testutil.compilation.annotation.ProcessorOption;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
/**
|
||||
* @author Filip Hrisafov
|
||||
*/
|
||||
@WithClasses({
|
||||
CarDto.class,
|
||||
Car.class
|
||||
})
|
||||
@IssueKey("2953")
|
||||
public class NullValueMapMappingStrategyTest {
|
||||
|
||||
@ProcessorTest
|
||||
@ProcessorOption(name = "mapstruct.nullValueMapMappingStrategy", value = "return_default")
|
||||
@WithClasses({
|
||||
CarMapMapper.class
|
||||
})
|
||||
void globalNullMapMappingStrategy() {
|
||||
assertThat( CarMapMapper.INSTANCE.carsToCarDtoMap( null ) ).isEmpty();
|
||||
}
|
||||
|
||||
@ProcessorTest
|
||||
@ProcessorOption(name = "mapstruct.nullValueMapMappingStrategy", value = "return_default")
|
||||
@WithClasses({
|
||||
CarMapMapperSettingOnMapper.class
|
||||
})
|
||||
void globalNullMapMappingStrategyWithOverrideInMapper() {
|
||||
// Explicit definition in @Mapper should override global
|
||||
assertThat( CarMapMapperSettingOnMapper.INSTANCE.carsToCarDtoMap( null ) ).isNull();
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user