diff --git a/core-common/src/main/java/org/mapstruct/MapNullToDefault.java b/core-common/src/main/java/org/mapstruct/MapNullToDefault.java index a61fc41e7..ed95c0020 100644 --- a/core-common/src/main/java/org/mapstruct/MapNullToDefault.java +++ b/core-common/src/main/java/org/mapstruct/MapNullToDefault.java @@ -24,16 +24,17 @@ import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; /** - * Advises the code generator to apply all the {@link Mapping}s from an inverse mapping method to the annotated method - * as well. An inverse mapping method is a method which has the annotated method's source type as target type (return - * type or indicated through a parameter annotated with {@link MappingTarget}) and the annotated method's target type as - * source type. + * Determines what kind to return in case of a null source argument. *
- * Any mappings given on the annotated method itself are added to those mappings inherited from the inverse method. In - * case of a conflict local mappings take precedence over inherited mappings. - *
- * If more than one matching inverse method exists, the name of the method to inherit the configuration from must be - * specified via {@link #name()} + * For: + *
+ *
+ * When given via {@link MapNullToDefault#mapNullToDefaultStrategy()}, causes the setting specified via + * {@link Mapper#mapNullToDefaultStrategy()} to be applied, if present. + *
+ * Otherwise causes
+ * {@link #MAP_NULL_TO_NULL} to be applied.
+ */
+ DEFAULT;
+}
diff --git a/core-common/src/main/java/org/mapstruct/Mapper.java b/core-common/src/main/java/org/mapstruct/Mapper.java
index 031126752..741483aa9 100644
--- a/core-common/src/main/java/org/mapstruct/Mapper.java
+++ b/core-common/src/main/java/org/mapstruct/Mapper.java
@@ -104,4 +104,10 @@ public @interface Mapper {
*/
CollectionMappingStrategy collectionMappingStrategy() default CollectionMappingStrategy.DEFAULT;
+ /**
+ * The strategy to be applied when for returning a target when the source equals null.
+ *
+ * @return The strategy applied when determining whether to return null or an empty object, list or map.
+ */
+ MapNullToDefaultStrategy mapNullToDefaultStrategy() default MapNullToDefaultStrategy.DEFAULT;
}
diff --git a/core-common/src/main/java/org/mapstruct/MapperConfig.java b/core-common/src/main/java/org/mapstruct/MapperConfig.java
index a84f52cdc..336d30d42 100644
--- a/core-common/src/main/java/org/mapstruct/MapperConfig.java
+++ b/core-common/src/main/java/org/mapstruct/MapperConfig.java
@@ -81,4 +81,11 @@ public @interface MapperConfig {
* @return The strategy applied when propagating the value of collection-typed properties.
*/
CollectionMappingStrategy collectionMappingStrategy() default CollectionMappingStrategy.DEFAULT;
+
+ /**
+ * The strategy to be applied when for returning a target when the source equals null.
+ *
+ * @return The strategy applied when determining whether to return null or an empty object, list or map.
+ */
+ MapNullToDefaultStrategy mapNullToDefaultStrategy() default MapNullToDefaultStrategy.DEFAULT;
}
diff --git a/processor/src/main/java/org/mapstruct/ap/model/BeanMappingMethod.java b/processor/src/main/java/org/mapstruct/ap/model/BeanMappingMethod.java
index b7c605146..c2575d26d 100644
--- a/processor/src/main/java/org/mapstruct/ap/model/BeanMappingMethod.java
+++ b/processor/src/main/java/org/mapstruct/ap/model/BeanMappingMethod.java
@@ -101,7 +101,8 @@ public class BeanMappingMethod extends MappingMethod {
// mapNullToDefault
MapNullToDefaultPrism prism = MapNullToDefaultPrism.getInstanceOn( method.getExecutable() );
- boolean mapNullToDefault = ( prism != null ) && prism.value();
+ boolean mapNullToDefault =
+ MapperConfig.getInstanceOn( ctx.getMapperTypeElement() ).isMapToDefault( prism );
MethodReference factoryMethod = AssignmentFactory.createFactoryMethod( method.getReturnType(), ctx );
return new BeanMappingMethod( method, propertyMappings, factoryMethod, mapNullToDefault );
diff --git a/processor/src/main/java/org/mapstruct/ap/model/IterableMappingMethod.java b/processor/src/main/java/org/mapstruct/ap/model/IterableMappingMethod.java
index 738000505..08b935e83 100644
--- a/processor/src/main/java/org/mapstruct/ap/model/IterableMappingMethod.java
+++ b/processor/src/main/java/org/mapstruct/ap/model/IterableMappingMethod.java
@@ -32,6 +32,7 @@ import org.mapstruct.ap.model.common.Type;
import org.mapstruct.ap.model.common.TypeFactory;
import org.mapstruct.ap.model.source.Method;
import org.mapstruct.ap.prism.MapNullToDefaultPrism;
+import org.mapstruct.ap.util.MapperConfig;
import org.mapstruct.ap.util.Strings;
/**
@@ -109,7 +110,8 @@ public class IterableMappingMethod extends MappingMethod {
// mapNullToDefault
MapNullToDefaultPrism prism = MapNullToDefaultPrism.getInstanceOn( method.getExecutable() );
- boolean mapNullToDefault = ( prism != null ) && prism.value();
+ boolean mapNullToDefault
+ = MapperConfig.getInstanceOn( ctx.getMapperTypeElement() ).isMapToDefault( prism );
MethodReference factoryMethod = AssignmentFactory.createFactoryMethod( method.getReturnType(), ctx );
return new IterableMappingMethod(
diff --git a/processor/src/main/java/org/mapstruct/ap/model/MapMappingMethod.java b/processor/src/main/java/org/mapstruct/ap/model/MapMappingMethod.java
index d1a87658a..73fc211a0 100644
--- a/processor/src/main/java/org/mapstruct/ap/model/MapMappingMethod.java
+++ b/processor/src/main/java/org/mapstruct/ap/model/MapMappingMethod.java
@@ -32,6 +32,7 @@ import org.mapstruct.ap.model.common.Type;
import org.mapstruct.ap.model.common.TypeFactory;
import org.mapstruct.ap.model.source.Method;
import org.mapstruct.ap.prism.MapNullToDefaultPrism;
+import org.mapstruct.ap.util.MapperConfig;
import org.mapstruct.ap.util.Strings;
/**
@@ -141,7 +142,8 @@ public class MapMappingMethod extends MappingMethod {
// mapNullToDefault
MapNullToDefaultPrism prism = MapNullToDefaultPrism.getInstanceOn( method.getExecutable() );
- boolean mapNullToDefault = ( prism != null ) && prism.value();
+ boolean mapNullToDefault =
+ MapperConfig.getInstanceOn( ctx.getMapperTypeElement() ).isMapToDefault( prism );
MethodReference factoryMethod = AssignmentFactory.createFactoryMethod( method.getReturnType(), ctx );
diff --git a/processor/src/main/java/org/mapstruct/ap/prism/MapNullToDefaultStrategyPrism.java b/processor/src/main/java/org/mapstruct/ap/prism/MapNullToDefaultStrategyPrism.java
new file mode 100644
index 000000000..56584c7c3
--- /dev/null
+++ b/processor/src/main/java/org/mapstruct/ap/prism/MapNullToDefaultStrategyPrism.java
@@ -0,0 +1,31 @@
+/**
+ * Copyright 2012-2014 Gunnar Morling (http://www.gunnarmorling.de/)
+ * and/or other contributors as indicated by the @authors tag. See the
+ * copyright.txt file in the distribution for a full listing of all
+ * contributors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.mapstruct.ap.prism;
+
+/**
+ * Prism for the enum {@link org.mapstruct.MapNullToDefaultStrategy}
+ *
+ * @author Sjaak Derksen
+ */
+public enum MapNullToDefaultStrategyPrism {
+
+ MAP_NULL_TO_NULL,
+ MAP_NULL_TO_DEFAULT,
+ DEFAULT;
+}
diff --git a/processor/src/main/java/org/mapstruct/ap/util/MapperConfig.java b/processor/src/main/java/org/mapstruct/ap/util/MapperConfig.java
index b249f7e1c..b9671fe32 100644
--- a/processor/src/main/java/org/mapstruct/ap/util/MapperConfig.java
+++ b/processor/src/main/java/org/mapstruct/ap/util/MapperConfig.java
@@ -29,6 +29,9 @@ import javax.lang.model.type.DeclaredType;
import javax.lang.model.type.TypeKind;
import javax.lang.model.type.TypeMirror;
+import org.mapstruct.ap.prism.MapNullToDefaultStrategyPrism;
+import org.mapstruct.ap.prism.MapNullToDefaultPrism;
+
import org.mapstruct.ap.option.ReportingPolicy;
import org.mapstruct.ap.prism.CollectionMappingStrategyPrism;
import org.mapstruct.ap.prism.MapperConfigPrism;
@@ -84,13 +87,12 @@ public class MapperConfig {
}
public String unmappedTargetPolicy() {
- if ( !ReportingPolicy.valueOf( mapperPrism.unmappedTargetPolicy() ).equals( ReportingPolicy.DEFAULT ) ) {
+ if ( ReportingPolicy.valueOf( mapperPrism.unmappedTargetPolicy() ) != ReportingPolicy.DEFAULT ) {
// it is not the default configuration
return mapperPrism.unmappedTargetPolicy();
}
else if ( mapperConfigPrism != null &&
- !ReportingPolicy.valueOf( mapperConfigPrism.unmappedTargetPolicy() )
- .equals( ReportingPolicy.DEFAULT ) ) {
+ ReportingPolicy.valueOf( mapperConfigPrism.unmappedTargetPolicy() ) != ReportingPolicy.DEFAULT ) {
return mapperConfigPrism.unmappedTargetPolicy();
}
else {
@@ -117,6 +119,41 @@ public class MapperConfig {
return CollectionMappingStrategyPrism.ACCESSOR_ONLY;
}
+ public boolean isMapToDefault(MapNullToDefaultPrism mapNullToDefault) {
+
+ // check on method level
+ if ( mapNullToDefault != null ) {
+ MapNullToDefaultStrategyPrism methodPolicy
+ = MapNullToDefaultStrategyPrism.valueOf( mapNullToDefault.value() );
+ if ( methodPolicy != MapNullToDefaultStrategyPrism.DEFAULT ) {
+ return methodPolicy == MapNullToDefaultStrategyPrism.MAP_NULL_TO_DEFAULT;
+ }
+ }
+
+ // check on mapper level
+ MapNullToDefaultStrategyPrism mapperPolicy =
+ MapNullToDefaultStrategyPrism.valueOf( mapperPrism.mapNullToDefaultStrategy() );
+
+ if ( mapperPolicy != MapNullToDefaultStrategyPrism.DEFAULT ) {
+ // it is not the default mapper configuration, so return the mapper configured value
+ return mapperPolicy == MapNullToDefaultStrategyPrism.MAP_NULL_TO_DEFAULT;
+ }
+
+ // check on mapping config level
+ else if ( mapperConfigPrism != null ) {
+ // try the config mapper configuration
+ MapNullToDefaultStrategyPrism configPolicy =
+ MapNullToDefaultStrategyPrism.valueOf( mapperConfigPrism.mapNullToDefaultStrategy() );
+ if ( configPolicy != MapNullToDefaultStrategyPrism.DEFAULT ) {
+ // its not the default configuration, so return the mapper config configured value
+ return configPolicy == MapNullToDefaultStrategyPrism.MAP_NULL_TO_DEFAULT;
+ }
+ }
+ // when nothing specified, return MAP_NULL_TO_NULL (default option)
+ return false;
+ }
+
+
public String componentModel() {
if ( !mapperPrism.componentModel().equals( "default" ) ) {
return mapperPrism.componentModel();
diff --git a/processor/src/test/java/org/mapstruct/ap/test/mapnulltodefault/CarMapperSettingOnConfig.java b/processor/src/test/java/org/mapstruct/ap/test/mapnulltodefault/CarMapperSettingOnConfig.java
new file mode 100644
index 000000000..463c91520
--- /dev/null
+++ b/processor/src/test/java/org/mapstruct/ap/test/mapnulltodefault/CarMapperSettingOnConfig.java
@@ -0,0 +1,53 @@
+/**
+ * Copyright 2012-2014 Gunnar Morling (http://www.gunnarmorling.de/)
+ * and/or other contributors as indicated by the @authors tag. See the
+ * copyright.txt file in the distribution for a full listing of all
+ * contributors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.mapstruct.ap.test.mapnulltodefault;
+
+import java.util.List;
+import java.util.Map;
+import java.util.UUID;
+
+import org.mapstruct.Mapper;
+import org.mapstruct.MapNullToDefault;
+import org.mapstruct.MapNullToDefaultStrategy;
+import org.mapstruct.Mapping;
+import org.mapstruct.Mappings;
+import org.mapstruct.ap.test.mapnulltodefault.source.Car;
+import org.mapstruct.ap.test.mapnulltodefault.target.CarDto;
+import org.mapstruct.factory.Mappers;
+
+@Mapper(imports = UUID.class, config = CentralConfig.class )
+public interface CarMapperSettingOnConfig {
+
+ CarMapperSettingOnConfig INSTANCE = Mappers.getMapper( CarMapperSettingOnConfig.class );
+
+ @Mappings({
+ @Mapping(target = "seatCount", source = "numberOfSeats"),
+ @Mapping(target = "model", constant = "ModelT"),
+ @Mapping(target = "catalogId", expression = "java( UUID.randomUUID().toString() )")
+ })
+ CarDto carToCarDto(Car car);
+
+
+ @MapNullToDefault(MapNullToDefaultStrategy.DEFAULT)
+ List