#600 added defaultValue feature

This commit is contained in:
luxmeter 2015-08-01 14:58:22 +02:00 committed by Andreas Gudian
parent b0b2f51331
commit 964f676af6
17 changed files with 598 additions and 41 deletions

View File

@ -154,4 +154,16 @@ public @interface Mapping {
* @return the dependencies of the mapped property
*/
String[] dependsOn() default { };
/**
* <p>
* 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.
* </p>
* 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 "";
}

View File

@ -151,4 +151,16 @@ public @interface Mapping {
* @return the dependencies of the mapped property
*/
String[] dependsOn() default { };
/**
* <p>
* 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.
* </p>
* 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 "";
}

View File

@ -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.<String>emptyList() )
.build();

View File

@ -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<String> dependsOn;
private String defaultValue;
private Assignment defaultValueAssignment;
@SuppressWarnings("unchecked")
private static class MappingBuilderBase<T extends MappingBuilderBase<T>> {
@ -121,6 +122,7 @@ public class PropertyMapping extends ModelElement {
// initial properties
private String dateFormat;
private String defaultValue;
private List<TypeMirror> 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<String> dependsOn) {
this( name, null, targetWriteAccessorName, targetReadAccessorName, targetType, propertyAssignment, dependsOn );
Assignment propertyAssignment, List<String> 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<String> dependsOn) {
List<String> 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.<String>emptyList();
this.defaultValueAssignment = defaultValueAssignment;
}
/**
@ -753,6 +785,10 @@ public class PropertyMapping extends ModelElement {
return assignment;
}
public Assignment getDefaultValueAssignment() {
return defaultValueAssignment;
}
@Override
public Set<Type> 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}";
}

View File

@ -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<TypeMirror> 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<TypeMirror> qualifiers,
String dateFormat, String defaultValue, List<TypeMirror> 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<TypeMirror> 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,

View File

@ -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(<EXPRESSION>)\"." ),
PROPERTYMAPPING_REVERSAL_PROBLEM( "Parameter %s cannot be reversed." ),
PROPERTYMAPPING_INVALID_PARAMETER_NAME( "Method has no parameter named \"%s\"." ),

View File

@ -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>

View File

@ -23,4 +23,5 @@
existingInstanceMapping=ext.existingInstanceMapping
targetReadAccessorName=targetReadAccessorName
targetWriteAccessorName=targetWriteAccessorName
targetType=targetType/>
targetType=targetType
defaultValueAssignment=defaultValueAssignment />

View File

@ -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>

View File

@ -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>

View File

@ -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;
}
}

View File

@ -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;
}
}

View File

@ -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;
}
}

View File

@ -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:
* <ul>
* <li>On code: Using defaultValue without type conversion</li>
* <li>On id: Type conversion of the defaultValue (string expr to int)</li>
* <li>On name: Using ConstantExpression instead of defaultValue</li>
* <li>On zipcode: Ignoring defaultValue on primitive target types</li>
* <li>On region: Using defaultValue before the assignment by an intern method (mapToString)</li>
* </ul>
*/
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 {
}
}

View File

@ -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);
}

View File

@ -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);
}

View File

@ -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;
}
}