diff --git a/core-jdk8/src/main/java/org/mapstruct/Mapping.java b/core-jdk8/src/main/java/org/mapstruct/Mapping.java
index a61da963c..15cb8d0a4 100644
--- a/core-jdk8/src/main/java/org/mapstruct/Mapping.java
+++ b/core-jdk8/src/main/java/org/mapstruct/Mapping.java
@@ -154,4 +154,16 @@ public @interface Mapping {
* @return the dependencies of the mapped property
*/
String[] dependsOn() default { };
+
+ /**
+ *
+ * In case the source property is null the provided default {@link String} value is set.
+ * If the designated target
+ * property is not of type {@code String}, the value will be converted by applying a matching conversion method or
+ * built-in conversion.
+ *
+ * Either this attribute or {@link #constant()} or {@link #expression()} may be specified for a given mapping.
+ * @return Default value to set in case the source property is null.
+ */
+ String defaultValue() default "";
}
diff --git a/core/src/main/java/org/mapstruct/Mapping.java b/core/src/main/java/org/mapstruct/Mapping.java
index e9f2eface..644ba5720 100644
--- a/core/src/main/java/org/mapstruct/Mapping.java
+++ b/core/src/main/java/org/mapstruct/Mapping.java
@@ -151,4 +151,16 @@ public @interface Mapping {
* @return the dependencies of the mapped property
*/
String[] dependsOn() default { };
+
+ /**
+ *
+ * In case the source property is null the provided default {@link String} value is set.
+ * If the designated target
+ * property is not of type {@code String}, the value will be converted by applying a matching conversion method or
+ * built-in conversion.
+ *
+ * Either this attribute or {@link #constant()} or {@link #expression()} may be specified for a given mapping.
+ * @return Default value to set in case the source property is null.
+ */
+ String defaultValue() default "";
}
diff --git a/processor/src/main/java/org/mapstruct/ap/internal/model/BeanMappingMethod.java b/processor/src/main/java/org/mapstruct/ap/internal/model/BeanMappingMethod.java
index e18faa32c..24cb81dbf 100644
--- a/processor/src/main/java/org/mapstruct/ap/internal/model/BeanMappingMethod.java
+++ b/processor/src/main/java/org/mapstruct/ap/internal/model/BeanMappingMethod.java
@@ -302,6 +302,7 @@ public class BeanMappingMethod extends MappingMethod {
.dateFormat( mapping.getDateFormat() )
.existingVariableNames( existingVariableNames )
.dependsOn( mapping.getDependsOn() )
+ .defaultValue( mapping.getDefaultValue() )
.build();
handledTargets.add( mapping.getTargetName() );
unprocessedSourceParameters.remove( sourceRef.getParameter() );
@@ -424,6 +425,7 @@ public class BeanMappingMethod extends MappingMethod {
.qualifiers( mapping != null ? mapping.getQualifiers() : null )
.resultType( mapping != null ? mapping.getResultType() : null )
.dateFormat( mapping != null ? mapping.getDateFormat() : null )
+ .defaultValue( mapping != null ? mapping.getDefaultValue() : null )
.existingVariableNames( existingVariableNames )
.dependsOn( mapping != null ? mapping.getDependsOn() : Collections.emptyList() )
.build();
diff --git a/processor/src/main/java/org/mapstruct/ap/internal/model/PropertyMapping.java b/processor/src/main/java/org/mapstruct/ap/internal/model/PropertyMapping.java
index 37e55cd86..c15760d73 100644
--- a/processor/src/main/java/org/mapstruct/ap/internal/model/PropertyMapping.java
+++ b/processor/src/main/java/org/mapstruct/ap/internal/model/PropertyMapping.java
@@ -18,20 +18,6 @@
*/
package org.mapstruct.ap.internal.model;
-import static org.mapstruct.ap.internal.model.assignment.Assignment.AssignmentType.DIRECT;
-import static org.mapstruct.ap.internal.model.assignment.Assignment.AssignmentType.MAPPED;
-import static org.mapstruct.ap.internal.model.assignment.Assignment.AssignmentType.MAPPED_TYPE_CONVERTED;
-import static org.mapstruct.ap.internal.model.assignment.Assignment.AssignmentType.TYPE_CONVERTED;
-import static org.mapstruct.ap.internal.model.assignment.Assignment.AssignmentType.TYPE_CONVERTED_MAPPED;
-
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.List;
-import java.util.Set;
-
-import javax.lang.model.element.ExecutableElement;
-import javax.lang.model.type.TypeMirror;
-
import org.mapstruct.ap.internal.model.assignment.AdderWrapper;
import org.mapstruct.ap.internal.model.assignment.ArrayCopyWrapper;
import org.mapstruct.ap.internal.model.assignment.Assignment;
@@ -53,6 +39,19 @@ import org.mapstruct.ap.internal.util.Executables;
import org.mapstruct.ap.internal.util.Message;
import org.mapstruct.ap.internal.util.Strings;
+import javax.lang.model.element.ExecutableElement;
+import javax.lang.model.type.TypeMirror;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+import java.util.Set;
+
+import static org.mapstruct.ap.internal.model.assignment.Assignment.AssignmentType.DIRECT;
+import static org.mapstruct.ap.internal.model.assignment.Assignment.AssignmentType.MAPPED;
+import static org.mapstruct.ap.internal.model.assignment.Assignment.AssignmentType.MAPPED_TYPE_CONVERTED;
+import static org.mapstruct.ap.internal.model.assignment.Assignment.AssignmentType.TYPE_CONVERTED;
+import static org.mapstruct.ap.internal.model.assignment.Assignment.AssignmentType.TYPE_CONVERTED_MAPPED;
+
/**
* Represents the mapping between a source and target property, e.g. from {@code String Source#foo} to
* {@code int Target#bar}. Name and type of source and target property can differ. If they have different types, the
@@ -69,6 +68,8 @@ public class PropertyMapping extends ModelElement {
private final Type targetType;
private final Assignment assignment;
private final List dependsOn;
+ private String defaultValue;
+ private Assignment defaultValueAssignment;
@SuppressWarnings("unchecked")
private static class MappingBuilderBase> {
@@ -121,6 +122,7 @@ public class PropertyMapping extends ModelElement {
// initial properties
private String dateFormat;
+ private String defaultValue;
private List qualifiers;
private TypeMirror resultType;
private SourceReference sourceReference;
@@ -145,6 +147,11 @@ public class PropertyMapping extends ModelElement {
return this;
}
+ public PropertyMappingBuilder defaultValue(String defaultValue) {
+ this.defaultValue = defaultValue;
+ return this;
+ }
+
private enum TargetWriteAccessorType {
GETTER,
SETTER,
@@ -237,10 +244,31 @@ public class PropertyMapping extends ModelElement {
targetReadAccessor != null ? targetReadAccessor.getSimpleName().toString() : null,
targetType,
assignment,
- dependsOn
+ dependsOn,
+ getDefaultValueAssignment()
);
}
+ private Assignment getDefaultValueAssignment() {
+ if ( defaultValue != null && !getSourceType().isPrimitive() ) {
+ PropertyMapping build = new ConstantMappingBuilder()
+ .constantExpression( '"' + defaultValue + '"' )
+ .dateFormat( dateFormat )
+ .qualifiers( qualifiers )
+ .resultType( resultType )
+ .dependsOn( dependsOn )
+ .existingVariableNames( existingVariableNames )
+ .mappingContext( ctx )
+ .sourceMethod( method )
+ .targetPropertyName( targetPropertyName )
+ .targetReadAccessor( targetReadAccessor )
+ .targetWriteAccessor( targetWriteAccessor )
+ .build();
+ return build.getAssignment();
+ }
+ return null;
+ }
+
private Assignment assignObject(Type sourceType, Type targetType, TargetWriteAccessorType targetAccessorType,
Assignment rhs) {
@@ -657,7 +685,8 @@ public class PropertyMapping extends ModelElement {
targetReadAccessor != null ? targetReadAccessor.getSimpleName().toString() : null,
targetType,
assignment,
- dependsOn
+ dependsOn,
+ null
);
}
}
@@ -702,7 +731,8 @@ public class PropertyMapping extends ModelElement {
targetReadAccessor != null ? targetReadAccessor.getSimpleName().toString() : null,
targetType,
assignment,
- dependsOn
+ dependsOn,
+ null
);
}
@@ -710,13 +740,14 @@ public class PropertyMapping extends ModelElement {
// Constructor for creating mappings of constant expressions.
private PropertyMapping(String name, String targetWriteAccessorName, String targetReadAccessorName, Type targetType,
- Assignment propertyAssignment, List dependsOn) {
- this( name, null, targetWriteAccessorName, targetReadAccessorName, targetType, propertyAssignment, dependsOn );
+ Assignment propertyAssignment, List dependsOn, Assignment defaultValueAssignment ) {
+ this( name, null, targetWriteAccessorName, targetReadAccessorName,
+ targetType, propertyAssignment, dependsOn, defaultValueAssignment );
}
private PropertyMapping(String name, String sourceBeanName, String targetWriteAccessorName,
String targetReadAccessorName, Type targetType, Assignment assignment,
- List dependsOn) {
+ List dependsOn, Assignment defaultValueAssignment ) {
this.name = name;
this.sourceBeanName = sourceBeanName;
this.targetWriteAccessorName = targetWriteAccessorName;
@@ -724,6 +755,7 @@ public class PropertyMapping extends ModelElement {
this.targetType = targetType;
this.assignment = assignment;
this.dependsOn = dependsOn != null ? dependsOn : Collections.emptyList();
+ this.defaultValueAssignment = defaultValueAssignment;
}
/**
@@ -753,6 +785,10 @@ public class PropertyMapping extends ModelElement {
return assignment;
}
+ public Assignment getDefaultValueAssignment() {
+ return defaultValueAssignment;
+ }
+
@Override
public Set getImportTypes() {
return assignment.getImportTypes();
@@ -762,6 +798,10 @@ public class PropertyMapping extends ModelElement {
return dependsOn;
}
+ public String getDefaultValue() {
+ return defaultValue;
+ }
+
@Override
public String toString() {
return "PropertyMapping {"
@@ -770,6 +810,7 @@ public class PropertyMapping extends ModelElement {
+ "\n targetReadAccessorName='" + targetReadAccessorName + "\',"
+ "\n targetType=" + targetType + ","
+ "\n propertyAssignment=" + assignment + ","
+ + "\n defaultValueAssignment=" + defaultValueAssignment + ","
+ "\n dependsOn=" + dependsOn
+ "\n}";
}
diff --git a/processor/src/main/java/org/mapstruct/ap/internal/model/source/Mapping.java b/processor/src/main/java/org/mapstruct/ap/internal/model/source/Mapping.java
index a3b8fbfcc..2f330c774 100644
--- a/processor/src/main/java/org/mapstruct/ap/internal/model/source/Mapping.java
+++ b/processor/src/main/java/org/mapstruct/ap/internal/model/source/Mapping.java
@@ -18,13 +18,12 @@
*/
package org.mapstruct.ap.internal.model.source;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
+import org.mapstruct.ap.internal.model.common.TypeFactory;
+import org.mapstruct.ap.internal.prism.CollectionMappingStrategyPrism;
+import org.mapstruct.ap.internal.prism.MappingPrism;
+import org.mapstruct.ap.internal.prism.MappingsPrism;
+import org.mapstruct.ap.internal.util.FormattingMessager;
+import org.mapstruct.ap.internal.util.Message;
import javax.lang.model.element.AnnotationMirror;
import javax.lang.model.element.AnnotationValue;
@@ -33,13 +32,13 @@ import javax.lang.model.element.ExecutableElement;
import javax.lang.model.type.DeclaredType;
import javax.lang.model.type.TypeKind;
import javax.lang.model.type.TypeMirror;
-
-import org.mapstruct.ap.internal.model.common.TypeFactory;
-import org.mapstruct.ap.internal.prism.CollectionMappingStrategyPrism;
-import org.mapstruct.ap.internal.prism.MappingPrism;
-import org.mapstruct.ap.internal.prism.MappingsPrism;
-import org.mapstruct.ap.internal.util.FormattingMessager;
-import org.mapstruct.ap.internal.util.Message;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
/**
* Represents a property mapping as configured via {@code @Mapping}.
@@ -55,6 +54,7 @@ public class Mapping {
private final String javaExpression;
private final String targetName;
private final String dateFormat;
+ private final String defaultValue;
private final List qualifiers;
private final TypeMirror resultType;
private final boolean isIgnored;
@@ -95,6 +95,7 @@ public class Mapping {
public static Mapping fromMappingPrism(MappingPrism mappingPrism, ExecutableElement element,
FormattingMessager messager) {
+
if ( mappingPrism.target().isEmpty() ) {
messager.printMessage(
element,
@@ -117,11 +118,20 @@ public class Mapping {
messager.printMessage( element, Message.PROPERTYMAPPING_EXPRESSION_AND_CONSTANT_BOTH_DEFINED );
return null;
}
+ else if ( !mappingPrism.expression().isEmpty() && !mappingPrism.defaultValue().isEmpty() ) {
+ messager.printMessage( element, Message.PROPERTYMAPPING_EXPRESSION_AND_DEFAULT_VALUE_BOTH_DEFINED );
+ return null;
+ }
+ else if ( !mappingPrism.constant().isEmpty() && !mappingPrism.defaultValue().isEmpty() ) {
+ messager.printMessage( element, Message.PROPERTYMAPPING_CONSTANT_AND_DEFAULT_VALUE_BOTH_DEFINED );
+ return null;
+ }
String source = mappingPrism.source().isEmpty() ? null : mappingPrism.source();
String constant = mappingPrism.constant().isEmpty() ? null : mappingPrism.constant();
String expression = getExpression( mappingPrism, element, messager );
String dateFormat = mappingPrism.dateFormat().isEmpty() ? null : mappingPrism.dateFormat();
+ String defaultValue = mappingPrism.defaultValue().isEmpty() ? null : mappingPrism.defaultValue();
boolean resultTypeIsDefined = !TypeKind.VOID.equals( mappingPrism.resultType().getKind() );
TypeMirror resultType = resultTypeIsDefined ? mappingPrism.resultType() : null;
@@ -134,6 +144,7 @@ public class Mapping {
expression,
mappingPrism.target(),
dateFormat,
+ defaultValue,
mappingPrism.qualifiedBy(),
mappingPrism.ignore(),
mappingPrism.mirror,
@@ -147,7 +158,7 @@ public class Mapping {
@SuppressWarnings("checkstyle:parameternumber")
private Mapping(String sourceName, String constant, String javaExpression, String targetName,
- String dateFormat, List qualifiers,
+ String dateFormat, String defaultValue, List qualifiers,
boolean isIgnored, AnnotationMirror mirror,
AnnotationValue sourceAnnotationValue, AnnotationValue targetAnnotationValue,
AnnotationValue dependsOnAnnotationValue,
@@ -157,6 +168,7 @@ public class Mapping {
this.javaExpression = javaExpression;
this.targetName = targetName;
this.dateFormat = dateFormat;
+ this.defaultValue = defaultValue;
this.qualifiers = qualifiers;
this.isIgnored = isIgnored;
this.mirror = mirror;
@@ -229,6 +241,10 @@ public class Mapping {
return dateFormat;
}
+ public String getDefaultValue() {
+ return defaultValue;
+ }
+
public List getQualifiers() {
return qualifiers;
}
@@ -306,6 +322,7 @@ public class Mapping {
null, // expression
sourceName != null ? sourceName : targetName,
dateFormat,
+ null,
qualifiers,
isIgnored,
mirror,
@@ -333,6 +350,7 @@ public class Mapping {
javaExpression,
targetName,
dateFormat,
+ defaultValue,
qualifiers,
isIgnored,
mirror,
diff --git a/processor/src/main/java/org/mapstruct/ap/internal/util/Message.java b/processor/src/main/java/org/mapstruct/ap/internal/util/Message.java
index 30e157511..77377ca67 100644
--- a/processor/src/main/java/org/mapstruct/ap/internal/util/Message.java
+++ b/processor/src/main/java/org/mapstruct/ap/internal/util/Message.java
@@ -44,6 +44,8 @@ public enum Message {
PROPERTYMAPPING_SOURCE_AND_CONSTANT_BOTH_DEFINED( "Source and constant are both defined in @Mapping, either define a source or a constant." ),
PROPERTYMAPPING_SOURCE_AND_EXPRESSION_BOTH_DEFINED( "Source and expression are both defined in @Mapping, either define a source or an expression." ),
PROPERTYMAPPING_EXPRESSION_AND_CONSTANT_BOTH_DEFINED( "Expression and constant are both defined in @Mapping, either define an expression or a constant." ),
+ PROPERTYMAPPING_EXPRESSION_AND_DEFAULT_VALUE_BOTH_DEFINED( "Expression and default value are both defined in @Mapping, either define a defaultValue or an expression." ),
+ PROPERTYMAPPING_CONSTANT_AND_DEFAULT_VALUE_BOTH_DEFINED( "Constant and default value are both defined in @Mapping, either define a defaultValue or a constant." ),
PROPERTYMAPPING_INVALID_EXPRESSION( "Value must be given in the form \"java()\"." ),
PROPERTYMAPPING_REVERSAL_PROBLEM( "Parameter %s cannot be reversed." ),
PROPERTYMAPPING_INVALID_PARAMETER_NAME( "Method has no parameter named \"%s\"." ),
diff --git a/processor/src/main/resources/org/mapstruct/ap/internal/model/BeanMappingMethod.ftl b/processor/src/main/resources/org/mapstruct/ap/internal/model/BeanMappingMethod.ftl
index 5eca1030b..bc56e2e56 100644
--- a/processor/src/main/resources/org/mapstruct/ap/internal/model/BeanMappingMethod.ftl
+++ b/processor/src/main/resources/org/mapstruct/ap/internal/model/BeanMappingMethod.ftl
@@ -47,7 +47,7 @@
<#if (propertyMappingsByParameter[sourceParam.name]?size > 0)>
if ( ${sourceParam.name} != null ) {
<#list propertyMappingsByParameter[sourceParam.name] as propertyMapping>
- <@includeModel object=propertyMapping targetBeanName=resultName existingInstanceMapping=existingInstanceMapping/>
+ <@includeModel object=propertyMapping targetBeanName=resultName existingInstanceMapping=existingInstanceMapping defaultValueAssignment=propertyMapping.defaultValueAssignment/>
#list>
}
#if>
@@ -55,14 +55,14 @@
<#list sourcePrimitiveParameters as sourceParam>
<#if (propertyMappingsByParameter[sourceParam.name]?size > 0)>
<#list propertyMappingsByParameter[sourceParam.name] as propertyMapping>
- <@includeModel object=propertyMapping targetBeanName=resultName existingInstanceMapping=existingInstanceMapping/>
+ <@includeModel object=propertyMapping targetBeanName=resultName existingInstanceMapping=existingInstanceMapping defaultValueAssignment=propertyMapping.defaultValueAssignment/>
#list>
#if>
#list>
<#else>
<#if mapNullToDefault>if ( ${sourceParameters[0].name} != null ) {#if>
<#list propertyMappingsByParameter[sourceParameters[0].name] as propertyMapping>
- <@includeModel object=propertyMapping targetBeanName=resultName existingInstanceMapping=existingInstanceMapping/>
+ <@includeModel object=propertyMapping targetBeanName=resultName existingInstanceMapping=existingInstanceMapping defaultValueAssignment=propertyMapping.defaultValueAssignment/>
#list>
<#if mapNullToDefault>}#if>
#if>
diff --git a/processor/src/main/resources/org/mapstruct/ap/internal/model/PropertyMapping.ftl b/processor/src/main/resources/org/mapstruct/ap/internal/model/PropertyMapping.ftl
index 9dd847339..9464a7dd5 100644
--- a/processor/src/main/resources/org/mapstruct/ap/internal/model/PropertyMapping.ftl
+++ b/processor/src/main/resources/org/mapstruct/ap/internal/model/PropertyMapping.ftl
@@ -23,4 +23,5 @@
existingInstanceMapping=ext.existingInstanceMapping
targetReadAccessorName=targetReadAccessorName
targetWriteAccessorName=targetWriteAccessorName
- targetType=targetType/>
+ targetType=targetType
+ defaultValueAssignment=defaultValueAssignment />
diff --git a/processor/src/main/resources/org/mapstruct/ap/internal/model/assignment/NullCheckWrapper.ftl b/processor/src/main/resources/org/mapstruct/ap/internal/model/assignment/NullCheckWrapper.ftl
index ddb8c018f..73503c1cc 100644
--- a/processor/src/main/resources/org/mapstruct/ap/internal/model/assignment/NullCheckWrapper.ftl
+++ b/processor/src/main/resources/org/mapstruct/ap/internal/model/assignment/NullCheckWrapper.ftl
@@ -20,9 +20,20 @@
-->
if ( ${sourceReference} != null ) {
<@includeModel object=assignment
+ targetBeanName=ext.targetBeanName
+ existingInstanceMapping=ext.existingInstanceMapping
+ targetReadAccessorName=ext.targetReadAccessorName
+ targetWriteAccessorName=ext.targetWriteAccessorName
+ targetType=ext.targetType
+ defaultValue=ext.defaultValueAssignment/>
+}
+<#if ext.defaultValueAssignment?? >
+else {
+ <@includeModel object=ext.defaultValueAssignment
targetBeanName=ext.targetBeanName
existingInstanceMapping=ext.existingInstanceMapping
targetReadAccessorName=ext.targetReadAccessorName
targetWriteAccessorName=ext.targetWriteAccessorName
targetType=ext.targetType/>
}
+#if>
\ No newline at end of file
diff --git a/processor/src/main/resources/org/mapstruct/ap/internal/model/assignment/SetterWrapper.ftl b/processor/src/main/resources/org/mapstruct/ap/internal/model/assignment/SetterWrapper.ftl
index 79fbf8c0f..d39e1f573 100644
--- a/processor/src/main/resources/org/mapstruct/ap/internal/model/assignment/SetterWrapper.ftl
+++ b/processor/src/main/resources/org/mapstruct/ap/internal/model/assignment/SetterWrapper.ftl
@@ -19,10 +19,10 @@
-->
<#if (thrownTypes?size == 0) >
- ${ext.targetBeanName}.${ext.targetWriteAccessorName}( <@_assignment/> );
+ <@assignment_w_defaultValue/>
<#else>
try {
- ${ext.targetBeanName}.${ext.targetWriteAccessorName}( <@_assignment/> );
+ <@assignment_w_defaultValue/>
}
<#list thrownTypes as exceptionType>
catch ( <@includeModel object=exceptionType/> e ) {
@@ -30,11 +30,31 @@
}
#list>
#if>
+
<#macro _assignment>
<@includeModel object=assignment
targetBeanName=ext.targetBeanName
existingInstanceMapping=ext.existingInstanceMapping
targetReadAccessorName=ext.targetReadAccessorName
targetWriteAccessorName=ext.targetWriteAccessorName
+ targetType=ext.targetType
+ defaultValueAssignment=ext.defaultValueAssignment/>
+#macro>
+
+<#macro _defaultValueAssignment>
+ <@includeModel object=ext.defaultValueAssignment.assignment
+ targetBeanName=ext.targetBeanName
+ existingInstanceMapping=ext.existingInstanceMapping
+ targetWriteAccessorName=ext.targetWriteAccessorName
targetType=ext.targetType/>
+#macro>
+
+<#macro assignment_w_defaultValue>
+ ${ext.targetBeanName}.${ext.targetWriteAccessorName}( <@_assignment/> );
+ <#-- if the assignee property is a primitive, defaulValueAssignment will not be set -->
+ <#if ext.defaultValueAssignment?? >
+ if ( ${sourceReference} == null ) {
+ ${ext.targetBeanName}.${ext.targetWriteAccessorName}( <@_defaultValueAssignment/> );
+ }
+ #if>
#macro>
\ No newline at end of file
diff --git a/processor/src/test/java/org/mapstruct/ap/test/defaultvalue/CountryDts.java b/processor/src/test/java/org/mapstruct/ap/test/defaultvalue/CountryDts.java
new file mode 100644
index 000000000..7b7b6b1a2
--- /dev/null
+++ b/processor/src/test/java/org/mapstruct/ap/test/defaultvalue/CountryDts.java
@@ -0,0 +1,58 @@
+/**
+ * Copyright 2012-2015 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.defaultvalue;
+
+public class CountryDts {
+ private String code;
+ private int id;
+ private long zipcode;
+ private String region;
+
+ public String getCode() {
+ return code;
+ }
+
+ public void setCode(String code) {
+ this.code = code;
+ }
+
+ public int getId() {
+ return id;
+ }
+
+ public void setId(int id) {
+ this.id = id;
+ }
+
+ public long getZipcode() {
+ return zipcode;
+ }
+
+ public void setZipcode(long zipcode) {
+ this.zipcode = zipcode;
+ }
+
+ public String getRegion() {
+ return region;
+ }
+
+ public void setRegion(String region) {
+ this.region = region;
+ }
+}
diff --git a/processor/src/test/java/org/mapstruct/ap/test/defaultvalue/CountryEntity.java b/processor/src/test/java/org/mapstruct/ap/test/defaultvalue/CountryEntity.java
new file mode 100644
index 000000000..90a9b7f3d
--- /dev/null
+++ b/processor/src/test/java/org/mapstruct/ap/test/defaultvalue/CountryEntity.java
@@ -0,0 +1,59 @@
+/**
+ * Copyright 2012-2015 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.defaultvalue;
+
+public class CountryEntity {
+ private String code;
+ private Integer id;
+ private long zipcode;
+ private Region region;
+
+ public String getCode() {
+ return code;
+ }
+
+ public void setCode(String code) {
+ this.code = code;
+ }
+
+ public Integer getId() {
+ return id;
+ }
+
+ public void setId(Integer id) {
+ this.id = id;
+ }
+
+ public long getZipcode() {
+ return zipcode;
+ }
+
+ public void setZipcode(long zipcode) {
+ this.zipcode = zipcode;
+ }
+
+ public Region getRegion() {
+ return region;
+ }
+
+ public void setRegion(Region region) {
+ this.region = region;
+ }
+
+}
diff --git a/processor/src/test/java/org/mapstruct/ap/test/defaultvalue/CountryMapper.java b/processor/src/test/java/org/mapstruct/ap/test/defaultvalue/CountryMapper.java
new file mode 100644
index 000000000..bea860abe
--- /dev/null
+++ b/processor/src/test/java/org/mapstruct/ap/test/defaultvalue/CountryMapper.java
@@ -0,0 +1,60 @@
+/**
+ * Copyright 2012-2015 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.defaultvalue;
+
+import org.mapstruct.Mapper;
+import org.mapstruct.Mapping;
+import org.mapstruct.MappingTarget;
+import org.mapstruct.Mappings;
+import org.mapstruct.factory.Mappers;
+
+@Mapper
+public abstract class CountryMapper {
+ public static final CountryMapper INSTANCE = Mappers.getMapper( CountryMapper.class );
+
+ @Mappings( {
+ @Mapping( target = "code", defaultValue = "DE" ),
+ @Mapping( target = "id", defaultValue = "42" ),
+ @Mapping( target = "zipcode", defaultValue = "1337" ),
+ @Mapping( target = "region", defaultValue = "someRegion" ),
+ } )
+ public abstract CountryDts mapToCountryDts(CountryEntity country);
+
+ @Mappings( {
+ @Mapping( target = "code", defaultValue = "DE" ),
+ @Mapping( target = "id", defaultValue = "42" ),
+ @Mapping( target = "zipcode", defaultValue = "1337" ),
+ @Mapping( target = "region", ignore = true )
+
+ } )
+ public abstract void mapToCountryDts(CountryDts countryDts, @MappingTarget CountryEntity country);
+
+ @Mappings( {
+ @Mapping( target = "code", defaultValue = "DE" ),
+ @Mapping( target = "id", defaultValue = "42" ),
+ @Mapping( target = "zipcode", defaultValue = "1337" ),
+ @Mapping( target = "region", ignore = true )
+
+ } )
+ public abstract void mapToCountryDts(CountryEntity source, @MappingTarget CountryEntity target);
+
+ protected String mapToString(Region region) {
+ return ( region != null ) ? region.getCode() : null;
+ }
+}
diff --git a/processor/src/test/java/org/mapstruct/ap/test/defaultvalue/DefaultValueTest.java b/processor/src/test/java/org/mapstruct/ap/test/defaultvalue/DefaultValueTest.java
new file mode 100644
index 000000000..abf16906b
--- /dev/null
+++ b/processor/src/test/java/org/mapstruct/ap/test/defaultvalue/DefaultValueTest.java
@@ -0,0 +1,162 @@
+/**
+ * Copyright 2012-2015 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.defaultvalue;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mapstruct.ap.testutil.IssueKey;
+import org.mapstruct.ap.testutil.WithClasses;
+import org.mapstruct.ap.testutil.compilation.annotation.CompilationResult;
+import org.mapstruct.ap.testutil.compilation.annotation.Diagnostic;
+import org.mapstruct.ap.testutil.compilation.annotation.ExpectedCompilationOutcome;
+import org.mapstruct.ap.testutil.runner.AnnotationProcessorTestRunner;
+
+import java.text.ParseException;
+
+import static org.fest.assertions.Assertions.assertThat;
+
+@IssueKey( "600" )
+@RunWith( AnnotationProcessorTestRunner.class )
+@WithClasses( {
+ CountryEntity.class,
+ CountryDts.class
+} )
+public class DefaultValueTest {
+ @Test
+ @WithClasses( {
+ Region.class,
+ CountryMapper.class
+ } )
+ /**
+ * Checks:
+ *
+ * - On code: Using defaultValue without type conversion
+ * - On id: Type conversion of the defaultValue (string expr to int)
+ * - On name: Using ConstantExpression instead of defaultValue
+ * - On zipcode: Ignoring defaultValue on primitive target types
+ * - On region: Using defaultValue before the assignment by an intern method (mapToString)
+ *
+ */
+ public void shouldDefaultValueAndUseConstantExpression() {
+ CountryEntity countryEntity = new CountryEntity();
+
+ CountryDts countryDts = CountryMapper.INSTANCE.mapToCountryDts( countryEntity );
+
+ // id is null so it should fall back to the default value
+ assertThat( countryDts.getId() ).isEqualTo( 42 );
+
+ // code is null so it should fall back to the default value
+ assertThat( countryDts.getCode() ).isEqualTo( "DE" );
+
+ assertThat( countryDts.getZipcode() ).isEqualTo( 0 );
+
+ assertThat( countryDts.getRegion() ).isEqualTo( "someRegion" );
+ }
+
+ @Test
+ @WithClasses( {
+ Region.class,
+ CountryMapper.class
+ } )
+ public void shouldIgnoreDefaultValue() {
+ CountryEntity countryEntity = new CountryEntity();
+ countryEntity.setCode( "US" );
+ Region region = new Region();
+ region.setCode( "foobar" );
+ countryEntity.setRegion( region );
+
+ CountryDts countryDts = CountryMapper.INSTANCE.mapToCountryDts( countryEntity );
+
+ // the source entity had a code set, so the default value shouldn't be used
+ assertThat( countryDts.getCode() ).isEqualTo( "US" );
+ assertThat( countryDts.getRegion() ).isEqualTo( "foobar" );
+ }
+
+ @Test
+ @WithClasses( {
+ Region.class,
+ CountryMapper.class
+ } )
+ public void shouldHandleUpdateMethodsFromDtsToEntity() {
+ CountryEntity countryEntity = new CountryEntity();
+ CountryDts countryDts = new CountryDts();
+
+ CountryMapper.INSTANCE.mapToCountryDts( countryDts, countryEntity );
+
+ assertThat( countryEntity.getId() ).isEqualTo( 0 );
+ // no code is set, so fall back to default value
+ assertThat( countryEntity.getCode() ).isEqualTo( "DE" );
+ assertThat( countryEntity.getZipcode() ).isEqualTo( 0 );
+ }
+
+ @Test
+ @WithClasses( {
+ Region.class,
+ CountryMapper.class
+ } )
+ public void shouldHandleUpdateMethodsFromEntityToEntity() {
+ CountryEntity source = new CountryEntity();
+ CountryEntity target = new CountryEntity();
+
+ CountryMapper.INSTANCE.mapToCountryDts( source, target );
+
+ // no id is set, so fall back to default value
+ assertThat( target.getId() ).isEqualTo( 42 );
+ // no code is set, so fall back to default value
+ assertThat( target.getCode() ).isEqualTo( "DE" );
+ assertThat( target.getZipcode() ).isEqualTo( 0 );
+ }
+
+ @Test
+ @WithClasses( {
+ ErroneousMapper.class,
+ Region.class,
+ } )
+ @ExpectedCompilationOutcome(
+ value = CompilationResult.FAILED,
+ diagnostics = {
+ @Diagnostic( type = ErroneousMapper.class,
+ kind = javax.tools.Diagnostic.Kind.ERROR,
+ line = 33,
+ messageRegExp = "Constant and default value are both defined in @Mapping,"
+ + " either define a defaultValue or a constant." ),
+ }
+ )
+ public void errorOnDefaultValueAndConstant() throws ParseException {
+ }
+
+ @Test
+ @WithClasses( {
+ ErroneousMapper2.class,
+ Region.class,
+ } )
+ @ExpectedCompilationOutcome(
+ value = CompilationResult.FAILED,
+ diagnostics = {
+ @Diagnostic( type = ErroneousMapper2.class,
+ kind = javax.tools.Diagnostic.Kind.ERROR,
+ line = 33,
+ messageRegExp = "Expression and default value are both defined in @Mapping,"
+ + " either define a defaultValue or an expression." ),
+ }
+ )
+ public void errorOnDefaultValueAndExpression() throws ParseException {
+ }
+
+}
diff --git a/processor/src/test/java/org/mapstruct/ap/test/defaultvalue/ErroneousMapper.java b/processor/src/test/java/org/mapstruct/ap/test/defaultvalue/ErroneousMapper.java
new file mode 100644
index 000000000..e7aca836c
--- /dev/null
+++ b/processor/src/test/java/org/mapstruct/ap/test/defaultvalue/ErroneousMapper.java
@@ -0,0 +1,34 @@
+/**
+ * Copyright 2012-2015 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.defaultvalue;
+
+import org.mapstruct.Mapper;
+import org.mapstruct.Mapping;
+import org.mapstruct.Mappings;
+import org.mapstruct.factory.Mappers;
+
+@Mapper
+public abstract class ErroneousMapper {
+ public static final ErroneousMapper INSTANCE = Mappers.getMapper( ErroneousMapper.class );
+
+ @Mappings( {
+ @Mapping( target = "code", defaultValue = "DE", constant = "FOOBAR" ),
+ } )
+ public abstract CountryDts mapToCountryDts(CountryEntity country);
+}
diff --git a/processor/src/test/java/org/mapstruct/ap/test/defaultvalue/ErroneousMapper2.java b/processor/src/test/java/org/mapstruct/ap/test/defaultvalue/ErroneousMapper2.java
new file mode 100644
index 000000000..0d21466fe
--- /dev/null
+++ b/processor/src/test/java/org/mapstruct/ap/test/defaultvalue/ErroneousMapper2.java
@@ -0,0 +1,34 @@
+/**
+ * Copyright 2012-2015 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.defaultvalue;
+
+import org.mapstruct.Mapper;
+import org.mapstruct.Mapping;
+import org.mapstruct.Mappings;
+import org.mapstruct.factory.Mappers;
+
+@Mapper
+public abstract class ErroneousMapper2 {
+ public static final ErroneousMapper2 INSTANCE = Mappers.getMapper( ErroneousMapper2.class );
+
+ @Mappings( {
+ @Mapping( target = "code", defaultValue = "DE", expression = "java(;)" ),
+ } )
+ public abstract CountryDts mapToCountryDts(CountryEntity country);
+}
diff --git a/processor/src/test/java/org/mapstruct/ap/test/defaultvalue/Region.java b/processor/src/test/java/org/mapstruct/ap/test/defaultvalue/Region.java
new file mode 100644
index 000000000..b10e18524
--- /dev/null
+++ b/processor/src/test/java/org/mapstruct/ap/test/defaultvalue/Region.java
@@ -0,0 +1,31 @@
+/**
+ * Copyright 2012-2015 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.defaultvalue;
+
+public class Region {
+ private String code;
+
+ public String getCode() {
+ return code;
+ }
+
+ public void setCode(String code) {
+ this.code = code;
+ }
+}