From 6d682c511839e744a680e554fb1f15b093fe40d0 Mon Sep 17 00:00:00 2001 From: sjaakd Date: Wed, 18 Jun 2014 22:02:28 +0200 Subject: [PATCH] #214 addressing superfluous NPE checks and adding NPE rudimentary unit tests --- .../PrimitiveToPrimitiveConversion.java | 2 +- .../PrimitiveToWrapperConversion.java | 2 +- .../org/mapstruct/ap/model/Assignment.java | 23 ++++- .../mapstruct/ap/model/PropertyMapping.java | 87 ++++--------------- .../model/assignment/AssignmentFactory.java | 4 +- .../model/assignment/AssignmentWrapper.java | 4 +- .../assignment/{Simple.java => Direct.java} | 10 +-- .../GetterCollectionOrMapWrapper.java | 49 +++++++++++ .../ap/model/assignment/MethodReference.java | 14 ++- .../SetterCollectionOrMapWrapper.java | 48 ++++++++++ .../ap/model/assignment/TypeConversion.java | 12 ++- .../org/mapstruct/ap/model/common/Type.java | 4 + .../ap/processor/MapperCreationProcessor.java | 78 +++++++++++------ .../processor/creation/MappingResolver.java | 8 +- ...pstruct.ap.model.IterableMappingMethod.ftl | 2 +- ...rg.mapstruct.ap.model.MapMappingMethod.ftl | 4 +- ...org.mapstruct.ap.model.PropertyMapping.ftl | 32 ++----- ....mapstruct.ap.model.assignment.Direct.ftl} | 0 ...ssignment.GetterCollectionOrMapWrapper.ftl | 40 +++++++++ ...ct.ap.model.assignment.LocalVarWrapper.ftl | 6 +- ...l.assignment.NewCollectionOrMapWrapper.ftl | 2 +- ...t.ap.model.assignment.NullCheckWrapper.ftl | 7 +- ...ssignment.SetterCollectionOrMapWrapper.ftl | 55 ++++++++++++ ...ruct.ap.model.assignment.SetterWrapper.ftl | 9 +- ...uct.ap.model.assignment.TypeConversion.ftl | 2 +- .../NoSetterCollectionMappingTest.java | 19 ++++ .../defaultimplementation/NoSetterMapper.java | 3 + .../org/mapstruct/ap/test/npe/NullObject.java | 27 ++++++ .../ap/test/npe/NullObjectMapper.java | 31 +++++++ .../ap/test/npe/NullPtrCheckTest.java | 73 ++++++++++++++++ .../org/mapstruct/ap/test/npe/Source.java | 59 +++++++++++++ .../ap/test/npe/SourceTargetMapper.java | 34 ++++++++ .../org/mapstruct/ap/test/npe/Target.java | 59 +++++++++++++ 33 files changed, 652 insertions(+), 157 deletions(-) rename processor/src/main/java/org/mapstruct/ap/model/assignment/{Simple.java => Direct.java} (87%) create mode 100644 processor/src/main/java/org/mapstruct/ap/model/assignment/GetterCollectionOrMapWrapper.java create mode 100644 processor/src/main/java/org/mapstruct/ap/model/assignment/SetterCollectionOrMapWrapper.java rename processor/src/main/resources/{org.mapstruct.ap.model.assignment.Simple.ftl => org.mapstruct.ap.model.assignment.Direct.ftl} (100%) create mode 100644 processor/src/main/resources/org.mapstruct.ap.model.assignment.GetterCollectionOrMapWrapper.ftl create mode 100644 processor/src/main/resources/org.mapstruct.ap.model.assignment.SetterCollectionOrMapWrapper.ftl create mode 100644 processor/src/test/java/org/mapstruct/ap/test/npe/NullObject.java create mode 100644 processor/src/test/java/org/mapstruct/ap/test/npe/NullObjectMapper.java create mode 100644 processor/src/test/java/org/mapstruct/ap/test/npe/NullPtrCheckTest.java create mode 100644 processor/src/test/java/org/mapstruct/ap/test/npe/Source.java create mode 100644 processor/src/test/java/org/mapstruct/ap/test/npe/SourceTargetMapper.java create mode 100644 processor/src/test/java/org/mapstruct/ap/test/npe/Target.java diff --git a/processor/src/main/java/org/mapstruct/ap/conversion/PrimitiveToPrimitiveConversion.java b/processor/src/main/java/org/mapstruct/ap/conversion/PrimitiveToPrimitiveConversion.java index 84095fa47..e32bf3d2f 100644 --- a/processor/src/main/java/org/mapstruct/ap/conversion/PrimitiveToPrimitiveConversion.java +++ b/processor/src/main/java/org/mapstruct/ap/conversion/PrimitiveToPrimitiveConversion.java @@ -44,6 +44,6 @@ public class PrimitiveToPrimitiveConversion extends SimpleConversion { @Override public String getFromExpression(ConversionContext conversionContext) { - return "(" + sourceType + ")"; + return "(" + sourceType + ") "; } } diff --git a/processor/src/main/java/org/mapstruct/ap/conversion/PrimitiveToWrapperConversion.java b/processor/src/main/java/org/mapstruct/ap/conversion/PrimitiveToWrapperConversion.java index b80d14b74..7ceb46bc6 100644 --- a/processor/src/main/java/org/mapstruct/ap/conversion/PrimitiveToWrapperConversion.java +++ b/processor/src/main/java/org/mapstruct/ap/conversion/PrimitiveToWrapperConversion.java @@ -50,7 +50,7 @@ public class PrimitiveToWrapperConversion extends SimpleConversion { return ""; } else { - return "(" + targetType.getName() + ")"; + return "(" + targetType.getName() + ") "; } } diff --git a/processor/src/main/java/org/mapstruct/ap/model/Assignment.java b/processor/src/main/java/org/mapstruct/ap/model/Assignment.java index 6bdba87fa..a14ed8092 100644 --- a/processor/src/main/java/org/mapstruct/ap/model/Assignment.java +++ b/processor/src/main/java/org/mapstruct/ap/model/Assignment.java @@ -29,6 +29,21 @@ import org.mapstruct.ap.model.common.Type; */ public interface Assignment { + public static enum AssignmentType { + /** assignment is direct */ + DIRECT, + /** assignment is type converted */ + TYPE_CONVERTED, + /** assignment is mapped (builtin/custom) */ + MAPPED, + /** 2 mapping methods (builtin/custom) are applied to get the target */ + MAPPED_TWICE, + /** assignment is first mapped (builtin/custom), then the result is type converted */ + MAPPED_TYPE_CONVERTED, + /** assignment is first type converted, and then mapped (builtin/custom) */ + TYPE_CONVERTED_MAPPED + } + /** * returns all types required as import by the assignment statement. * @@ -62,10 +77,10 @@ public interface Assignment { String getSourceReference(); /** - * Returns whether the implemented assignment is a plain source assignment (Simple assignment) - * (so not a MethodReference or TypeConversion). + * Returns whether the type of assignment * - * @return true when this is a (wrapped) Simple Assignment + * @return {@link AssignmentType} */ - boolean isSimple(); + AssignmentType getType(); + } diff --git a/processor/src/main/java/org/mapstruct/ap/model/PropertyMapping.java b/processor/src/main/java/org/mapstruct/ap/model/PropertyMapping.java index 90aa3fc54..adb8c4a83 100644 --- a/processor/src/main/java/org/mapstruct/ap/model/PropertyMapping.java +++ b/processor/src/main/java/org/mapstruct/ap/model/PropertyMapping.java @@ -24,6 +24,8 @@ import java.util.Set; import org.mapstruct.ap.model.common.ModelElement; import org.mapstruct.ap.model.common.Type; +import static org.mapstruct.ap.model.Assignment.AssignmentType.DIRECT; + /** * 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 @@ -35,65 +37,31 @@ import org.mapstruct.ap.model.common.Type; public class PropertyMapping extends ModelElement { private final String sourceBeanName; - private final String sourceName; - private final String sourceAccessorName; - private final Type sourceType; - private final String targetName; private final String targetAccessorName; private final Type targetType; - private final boolean isTargetAccessorSetter; - private final String targetReadAccessorName; - private final Assignment propertyAssignment; + private final Assignment assignment; - /** - * Constructor for creating mappings of constant expressions. - */ - public PropertyMapping(Type sourceType, String targetName, String targetAccessorName, Type targetType, - Assignment propertyAssignment) { - this( null, null, null, sourceType, targetName, targetAccessorName, targetType, propertyAssignment ); + // Constructor for creating mappings of constant expressions. + public PropertyMapping(String targetAccessorName, Type targetType, Assignment propertyAssignment) { + this( null, targetAccessorName, targetType, propertyAssignment ); } - public PropertyMapping(String sourceBeanName, String sourceName, String sourceAccessorName, Type sourceType, - String targetName, String targetAccessorName, Type targetType, - Assignment propertyAssignment) { + public PropertyMapping(String sourceBeanName, String targetAccessorName, Type targetType, Assignment assignment) { this.sourceBeanName = sourceBeanName; - this.sourceName = sourceName; - this.sourceAccessorName = sourceAccessorName; - this.sourceType = sourceType; - this.targetName = targetName; this.targetAccessorName = targetAccessorName; this.targetType = targetType; - this.isTargetAccessorSetter = targetAccessorName.startsWith( "set" ); - this.targetReadAccessorName = - this.isTargetAccessorSetter ? "get" + targetAccessorName.substring( 3 ) : targetAccessorName; - this.propertyAssignment = propertyAssignment; + this.assignment = assignment; } public String getSourceBeanName() { return sourceBeanName; } - public String getSourceName() { - return sourceName; - } - - public String getSourceAccessorName() { - return sourceAccessorName; - } - - public Type getSourceType() { - return sourceType; - } - - public String getTargetName() { - return targetName; - } - public String getTargetAccessorName() { return targetAccessorName; } @@ -102,41 +70,20 @@ public class PropertyMapping extends ModelElement { return targetType; } - public Assignment getPropertyAssignment() { - return propertyAssignment; - } - - /** - * Whether the target accessor is a setter method or not. The only case where it is not a setter but a getter is a - * collection-typed property without a getter, to which elements are set by adding the source elements to the - * collection retrieved via the getter. - * - * @return {@code true} if the target accessor is a setter, {@code false} otherwise - */ - public boolean isTargetAccessorSetter() { - return isTargetAccessorSetter; - } - - /** - * @return the read-accessor for the target property (i.e. the getter method) - */ - public String getTargetReadAccessorName() { - return targetReadAccessorName; + public Assignment getAssignment() { + return assignment; } @Override public Set getImportTypes() { Set importTypes = new HashSet(); - if ( propertyAssignment != null ) { - if ( isTargetAccessorSetter() - && propertyAssignment.isSimple() - && ( targetType.isCollectionType() || targetType.isMapType() ) ) { + if ( assignment.getType() == DIRECT ) { + if ( targetType.isCollectionOrMapType() ) { importTypes.addAll( targetType.getImportTypes() ); } - - if ( !propertyAssignment.isSimple() ) { - importTypes.addAll( propertyAssignment.getImportTypes() ); - } + } + else { + importTypes.addAll( assignment.getImportTypes() ); } return importTypes; } @@ -144,11 +91,9 @@ public class PropertyMapping extends ModelElement { @Override public String toString() { return "PropertyMapping {" + - "\n sourceName='" + sourceAccessorName + "\'," + - "\n sourceType=" + sourceType + "," + "\n targetName='" + targetAccessorName + "\'," + "\n targetType=" + targetType + "," + - "\n propertyAssignment=" + propertyAssignment + + "\n propertyAssignment=" + assignment + "\n}"; } } diff --git a/processor/src/main/java/org/mapstruct/ap/model/assignment/AssignmentFactory.java b/processor/src/main/java/org/mapstruct/ap/model/assignment/AssignmentFactory.java index 1c92f51d8..436c651af 100644 --- a/processor/src/main/java/org/mapstruct/ap/model/assignment/AssignmentFactory.java +++ b/processor/src/main/java/org/mapstruct/ap/model/assignment/AssignmentFactory.java @@ -56,8 +56,8 @@ public class AssignmentFactory { return new MethodReference( method, contextParam ); } - public static Simple createSimple(String sourceRef) { - return new Simple( sourceRef ); + public static Direct createSimple(String sourceRef) { + return new Direct( sourceRef ); } } diff --git a/processor/src/main/java/org/mapstruct/ap/model/assignment/AssignmentWrapper.java b/processor/src/main/java/org/mapstruct/ap/model/assignment/AssignmentWrapper.java index 31e53217f..1e5901c84 100644 --- a/processor/src/main/java/org/mapstruct/ap/model/assignment/AssignmentWrapper.java +++ b/processor/src/main/java/org/mapstruct/ap/model/assignment/AssignmentWrapper.java @@ -62,7 +62,7 @@ public abstract class AssignmentWrapper extends ModelElement implements Assignme } @Override - public boolean isSimple() { - return decoratedAssignment.isSimple(); + public AssignmentType getType() { + return decoratedAssignment.getType(); } } diff --git a/processor/src/main/java/org/mapstruct/ap/model/assignment/Simple.java b/processor/src/main/java/org/mapstruct/ap/model/assignment/Direct.java similarity index 87% rename from processor/src/main/java/org/mapstruct/ap/model/assignment/Simple.java rename to processor/src/main/java/org/mapstruct/ap/model/assignment/Direct.java index 0aba731bb..2815c1f26 100644 --- a/processor/src/main/java/org/mapstruct/ap/model/assignment/Simple.java +++ b/processor/src/main/java/org/mapstruct/ap/model/assignment/Direct.java @@ -26,15 +26,15 @@ import org.mapstruct.ap.model.common.ModelElement; import org.mapstruct.ap.model.common.Type; /** - * Simple Assignment. Just a source reference + * Direct Assignment. Just a source reference * * @author Sjaak Derksen */ -public class Simple extends ModelElement implements Assignment { +public class Direct extends ModelElement implements Assignment { private final String sourceReference; - public Simple( String sourceReference ) { + public Direct( String sourceReference ) { this.sourceReference = sourceReference; } @@ -59,7 +59,7 @@ public class Simple extends ModelElement implements Assignment { } @Override - public boolean isSimple() { - return true; + public AssignmentType getType() { + return AssignmentType.DIRECT; } } diff --git a/processor/src/main/java/org/mapstruct/ap/model/assignment/GetterCollectionOrMapWrapper.java b/processor/src/main/java/org/mapstruct/ap/model/assignment/GetterCollectionOrMapWrapper.java new file mode 100644 index 000000000..7bd62de24 --- /dev/null +++ b/processor/src/main/java/org/mapstruct/ap/model/assignment/GetterCollectionOrMapWrapper.java @@ -0,0 +1,49 @@ +/** + * 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.model.assignment; + +import org.mapstruct.ap.model.Assignment; + +/** + * This wrapper handles the situation were an assignment must be done via a target getter method because there + * is no setter available. + * + * The wrapper checks if there is an collection or map initialized on the target bean (not null). If so it uses the + * addAll (for collections) or putAll (for maps). The collection / map is cleared in case of a pre-existing target + * {@link org.mapstruct.MappingTarget }before adding the source entries. The goal is that the same collection / map + * is used as target. + * + * Nothing can be added if the getter on the target returns null. + * + * @author Sjaak Derksen + */ +public class GetterCollectionOrMapWrapper extends AssignmentWrapper { + + private final String targetGetterName; + + public GetterCollectionOrMapWrapper( Assignment decoratedAssignment, String targetGetterName ) { + super( decoratedAssignment ); + this.targetGetterName = targetGetterName; + } + + public String getTargetGetterName() { + return targetGetterName; + } + +} diff --git a/processor/src/main/java/org/mapstruct/ap/model/assignment/MethodReference.java b/processor/src/main/java/org/mapstruct/ap/model/assignment/MethodReference.java index c6842ce59..4f206d454 100644 --- a/processor/src/main/java/org/mapstruct/ap/model/assignment/MethodReference.java +++ b/processor/src/main/java/org/mapstruct/ap/model/assignment/MethodReference.java @@ -148,7 +148,17 @@ public class MethodReference extends MappingMethod implements Assignment, Factor } @Override - public boolean isSimple() { - return false; + public AssignmentType getType() { + + switch ( assignment.getType() ) { + case DIRECT: + return AssignmentType.MAPPED; + case MAPPED: + return AssignmentType.MAPPED_TWICE; + case TYPE_CONVERTED: + return AssignmentType.TYPE_CONVERTED_MAPPED; + default: + return null; + } } } diff --git a/processor/src/main/java/org/mapstruct/ap/model/assignment/SetterCollectionOrMapWrapper.java b/processor/src/main/java/org/mapstruct/ap/model/assignment/SetterCollectionOrMapWrapper.java new file mode 100644 index 000000000..facf42fc4 --- /dev/null +++ b/processor/src/main/java/org/mapstruct/ap/model/assignment/SetterCollectionOrMapWrapper.java @@ -0,0 +1,48 @@ +/** + * 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.model.assignment; + +import org.mapstruct.ap.model.Assignment; + +/** + * This wrapper handles the situation were an assignment is done via the setter. + * + * In case of a pre-existing target the wrapper checks if there is an collection or map initialized on the target bean + * (not null). If so it uses the addAll (for collections) or putAll (for maps). The collection / map is cleared in case + * of a pre-existing target {@link org.mapstruct.MappingTarget }before adding the source entries. + * + * If there is no pre-existing target, or the target Collection / Map is not initialized (null) the setter is used to + * create a new Collection / Map with the copy constructor. + * + * @author Sjaak Derksen + */ +public class SetterCollectionOrMapWrapper extends AssignmentWrapper { + + private final String targetGetterName; + + public SetterCollectionOrMapWrapper( Assignment decoratedAssignment, String targetSetterName ) { + super( decoratedAssignment ); + this.targetGetterName = "get" + targetSetterName.substring( 3 ); + } + + public String getTargetGetterName() { + return targetGetterName; + } + +} diff --git a/processor/src/main/java/org/mapstruct/ap/model/assignment/TypeConversion.java b/processor/src/main/java/org/mapstruct/ap/model/assignment/TypeConversion.java index bd9cac0d5..829aa6ad6 100644 --- a/processor/src/main/java/org/mapstruct/ap/model/assignment/TypeConversion.java +++ b/processor/src/main/java/org/mapstruct/ap/model/assignment/TypeConversion.java @@ -92,7 +92,15 @@ public class TypeConversion extends ModelElement implements Assignment { } @Override - public boolean isSimple() { - return false; + public AssignmentType getType() { + + switch ( assignment.getType() ) { + case DIRECT: + return AssignmentType.TYPE_CONVERTED; + case MAPPED: + return AssignmentType.MAPPED_TYPE_CONVERTED; + default: + return null; + } } } diff --git a/processor/src/main/java/org/mapstruct/ap/model/common/Type.java b/processor/src/main/java/org/mapstruct/ap/model/common/Type.java index 63783b600..725089572 100644 --- a/processor/src/main/java/org/mapstruct/ap/model/common/Type.java +++ b/processor/src/main/java/org/mapstruct/ap/model/common/Type.java @@ -183,6 +183,10 @@ public class Type extends ModelElement implements Comparable { return isMapType; } + public boolean isCollectionOrMapType() { + return isCollectionType || isMapType; + } + public String getFullyQualifiedName() { return qualifiedName; } diff --git a/processor/src/main/java/org/mapstruct/ap/processor/MapperCreationProcessor.java b/processor/src/main/java/org/mapstruct/ap/processor/MapperCreationProcessor.java index e52c49c16..db9bae67e 100644 --- a/processor/src/main/java/org/mapstruct/ap/processor/MapperCreationProcessor.java +++ b/processor/src/main/java/org/mapstruct/ap/processor/MapperCreationProcessor.java @@ -26,7 +26,6 @@ import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.Set; - import javax.annotation.processing.Messager; import javax.lang.model.element.ExecutableElement; import javax.lang.model.element.TypeElement; @@ -36,8 +35,9 @@ import javax.lang.model.util.ElementFilter; import javax.lang.model.util.Elements; import javax.lang.model.util.Types; import javax.tools.Diagnostic.Kind; - import org.mapstruct.ap.model.Assignment; +import static org.mapstruct.ap.model.Assignment.AssignmentType.DIRECT; +import static org.mapstruct.ap.model.Assignment.AssignmentType.TYPE_CONVERTED; import org.mapstruct.ap.model.BeanMappingMethod; import org.mapstruct.ap.model.Decorator; import org.mapstruct.ap.model.DefaultMapperReference; @@ -51,9 +51,11 @@ import org.mapstruct.ap.model.MapperReference; import org.mapstruct.ap.model.MappingMethod; import org.mapstruct.ap.model.PropertyMapping; import org.mapstruct.ap.model.assignment.AssignmentFactory; +import org.mapstruct.ap.model.assignment.GetterCollectionOrMapWrapper; import org.mapstruct.ap.model.assignment.LocalVarWrapper; import org.mapstruct.ap.model.assignment.NewCollectionOrMapWrapper; import org.mapstruct.ap.model.assignment.NullCheckWrapper; +import org.mapstruct.ap.model.assignment.SetterCollectionOrMapWrapper; import org.mapstruct.ap.model.assignment.SetterWrapper; import org.mapstruct.ap.model.common.Parameter; import org.mapstruct.ap.model.common.Type; @@ -79,6 +81,8 @@ import org.mapstruct.ap.util.Strings; */ public class MapperCreationProcessor implements ModelElementProcessor, Mapper> { + private enum TargetAccessorType { GETTER, SETTER }; + private Elements elementUtils; private Types typeUtils; private Messager messager; @@ -655,14 +659,17 @@ public class MapperCreationProcessor implements ModelElementProcessor mapperReferences, diff --git a/processor/src/main/java/org/mapstruct/ap/processor/creation/MappingResolver.java b/processor/src/main/java/org/mapstruct/ap/processor/creation/MappingResolver.java index 6f3bd8f97..ca5f34521 100644 --- a/processor/src/main/java/org/mapstruct/ap/processor/creation/MappingResolver.java +++ b/processor/src/main/java/org/mapstruct/ap/processor/creation/MappingResolver.java @@ -35,7 +35,7 @@ import org.mapstruct.ap.model.Assignment; import org.mapstruct.ap.model.MapperReference; import org.mapstruct.ap.model.VirtualMappingMethod; import org.mapstruct.ap.model.assignment.AssignmentFactory; -import org.mapstruct.ap.model.assignment.Simple; +import org.mapstruct.ap.model.assignment.Direct; import org.mapstruct.ap.model.common.ConversionContext; import org.mapstruct.ap.model.common.DefaultConversionContext; import org.mapstruct.ap.model.common.Type; @@ -111,7 +111,7 @@ public class MappingResolver { *
    *
  1. MethodReference
  2. *
  3. TypeConversion
  4. - *
  5. Simple Assignment (empty TargetAssignment)
  6. + *
  7. Direct Assignment (empty TargetAssignment)
  8. *
  9. null, no assignment found
  10. *
*/ @@ -342,7 +342,7 @@ public class MappingResolver { ); if ( conversionXRef != null ) { methodRefY.setAssignment( conversionXRef ); - conversionXRef.setAssignment( new Simple( sourceReference ) ); + conversionXRef.setAssignment( new Direct( sourceReference ) ); break; } else { @@ -382,7 +382,7 @@ public class MappingResolver { conversionYRef = resolveViaConversion( methodXCandidate.getReturnType(), targetType ); if ( conversionYRef != null ) { conversionYRef.setAssignment( methodRefX ); - methodRefX.setAssignment( new Simple( sourceReference ) ); + methodRefX.setAssignment( new Direct( sourceReference ) ); break; } else { diff --git a/processor/src/main/resources/org.mapstruct.ap.model.IterableMappingMethod.ftl b/processor/src/main/resources/org.mapstruct.ap.model.IterableMappingMethod.ftl index acef47362..a9ab81d37 100644 --- a/processor/src/main/resources/org.mapstruct.ap.model.IterableMappingMethod.ftl +++ b/processor/src/main/resources/org.mapstruct.ap.model.IterableMappingMethod.ftl @@ -32,7 +32,7 @@ for ( <@includeModel object=sourceParameter.type.typeParameters[0]/> ${loopVariableName} : ${sourceParameter.name} ) { - <@includeModel object=elementAssignment target="${resultName}.add" targetType="${resultType.typeParameters[0].name}"/> + <@includeModel object=elementAssignment targetBeanName=resultName targetAccessorName="add" targetType="${resultType.typeParameters[0].name}"/> } <#if returnType.name != "void"> diff --git a/processor/src/main/resources/org.mapstruct.ap.model.MapMappingMethod.ftl b/processor/src/main/resources/org.mapstruct.ap.model.MapMappingMethod.ftl index f84b3a312..1cd02f06c 100644 --- a/processor/src/main/resources/org.mapstruct.ap.model.MapMappingMethod.ftl +++ b/processor/src/main/resources/org.mapstruct.ap.model.MapMappingMethod.ftl @@ -34,12 +34,12 @@ for ( java.util.Map.Entry<<#list sourceParameter.type.typeParameters as typeParameter><@includeModel object=typeParameter /><#if typeParameter_has_next>, > ${entryVariableName} : ${sourceParameter.name}.entrySet() ) { <#-- key --> <@includeModel object=keyAssignment - target=keyVariableName + targetAccessorName=keyVariableName targetType=typeName(resultType.typeParameters[0]) isLocalVar=true/> <#-- value --> <@includeModel object=valueAssignment - target=valueVariableName + targetAccessorName=valueVariableName targetType=typeName(resultType.typeParameters[1]) isLocalVar=true/> ${resultName}.put( ${keyVariableName}, ${valueVariableName} ); diff --git a/processor/src/main/resources/org.mapstruct.ap.model.PropertyMapping.ftl b/processor/src/main/resources/org.mapstruct.ap.model.PropertyMapping.ftl index 32faa815a..f7e0679b0 100644 --- a/processor/src/main/resources/org.mapstruct.ap.model.PropertyMapping.ftl +++ b/processor/src/main/resources/org.mapstruct.ap.model.PropertyMapping.ftl @@ -18,29 +18,9 @@ limitations under the License. --> - <#if !( targetType.collectionType || targetType.mapType ) > - <#-- non collections or maps --> - <@assignment aTargetType=targetType/> -<#else> - <#-- collections or maps --> - <#if ( ext.existingInstanceMapping || !targetAccessorSetter ) > - if ( ${ext.targetBeanName}.${targetReadAccessorName}() != null ) { - <#if ext.existingInstanceMapping> - ${ext.targetBeanName}.${targetReadAccessorName}().clear(); - <#t> - <#if targetType.collectionType> - <@assignment aTarget="${ext.targetBeanName}.${targetReadAccessorName}().addAll"/> - <#else> - <@assignment aTarget="${ext.targetBeanName}.${targetReadAccessorName}().putAll"/> - - } - <#if targetAccessorSetter> - else <@assignment/> - - <#elseif targetAccessorSetter> - <@assignment/> - - - <#macro assignment aTarget="${ext.targetBeanName}.${targetAccessorName}" aTargetType=targetType> - <@includeModel object=propertyAssignment target=aTarget targetType=aTargetType raw=true/> - +<@includeModel object=assignment + targetBeanName=ext.targetBeanName + raw=ext.raw + existingInstanceMapping=ext.existingInstanceMapping + targetAccessorName=targetAccessorName + targetType=targetType/> diff --git a/processor/src/main/resources/org.mapstruct.ap.model.assignment.Simple.ftl b/processor/src/main/resources/org.mapstruct.ap.model.assignment.Direct.ftl similarity index 100% rename from processor/src/main/resources/org.mapstruct.ap.model.assignment.Simple.ftl rename to processor/src/main/resources/org.mapstruct.ap.model.assignment.Direct.ftl diff --git a/processor/src/main/resources/org.mapstruct.ap.model.assignment.GetterCollectionOrMapWrapper.ftl b/processor/src/main/resources/org.mapstruct.ap.model.assignment.GetterCollectionOrMapWrapper.ftl new file mode 100644 index 000000000..510990110 --- /dev/null +++ b/processor/src/main/resources/org.mapstruct.ap.model.assignment.GetterCollectionOrMapWrapper.ftl @@ -0,0 +1,40 @@ +<#-- + + 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. + +--> +if ( ${ext.targetBeanName}.${targetGetterName}() != null ) { + <#if ext.existingInstanceMapping> + ${ext.targetBeanName}.${targetGetterName}().clear(); + + <#if ext.targetType.collectionType> + <@includeModel object=assignment + targetBeanName=ext.targetBeanName + raw=ext.raw + existingInstanceMapping=ext.existingInstanceMapping + targetAccessorName="${targetGetterName}().addAll" + targetType=ext.targetType/> + <#else> + <@includeModel object=assignment + targetBeanName=ext.targetBeanName + raw=ext.raw + existingInstanceMapping=ext.existingInstanceMapping + targetAccessorName="${targetGetterName}().putAll" + targetType=ext.targetType/> + +} diff --git a/processor/src/main/resources/org.mapstruct.ap.model.assignment.LocalVarWrapper.ftl b/processor/src/main/resources/org.mapstruct.ap.model.assignment.LocalVarWrapper.ftl index 92879e807..d5e0f5593 100644 --- a/processor/src/main/resources/org.mapstruct.ap.model.assignment.LocalVarWrapper.ftl +++ b/processor/src/main/resources/org.mapstruct.ap.model.assignment.LocalVarWrapper.ftl @@ -19,11 +19,11 @@ --> <#if (exceptionTypes?size == 0) > - ${ext.targetType} ${ext.target} = <@includeModel object=assignment target=ext.target targetType=ext.targetType raw=ext.raw/>; + ${ext.targetType} ${ext.targetAccessorName} = <@includeModel object=assignment targetType=ext.targetType raw=ext.raw/>; <#else> - ${ext.targetType} ${ext.target}; + ${ext.targetType} ${ext.targetAccessorName}; try { - ${ext.target} = <@includeModel object=assignment target=ext.target targetType=ext.targetType raw=ext.raw/>; + ${ext.targetAccessorName} = <@includeModel object=assignment targetType=ext.targetType raw=ext.raw/>; } <#list exceptionTypes as exceptionType> catch ( <@includeModel object=exceptionType/> e ) { diff --git a/processor/src/main/resources/org.mapstruct.ap.model.assignment.NewCollectionOrMapWrapper.ftl b/processor/src/main/resources/org.mapstruct.ap.model.assignment.NewCollectionOrMapWrapper.ftl index 1a013b644..f3d554a68 100644 --- a/processor/src/main/resources/org.mapstruct.ap.model.assignment.NewCollectionOrMapWrapper.ftl +++ b/processor/src/main/resources/org.mapstruct.ap.model.assignment.NewCollectionOrMapWrapper.ftl @@ -24,5 +24,5 @@ new <#if ext.targetType.implementationType??> <#else> <@includeModel object=ext.targetType/> -( <@includeModel object=assignment target=ext.target targetType=ext.targetType raw=ext.raw/> ) +( <@includeModel object=assignment targetBeanName=ext.targetBeanName targetAccessorName=ext.targetAccessorName targetType=ext.targetType raw=ext.raw/> ) \ No newline at end of file diff --git a/processor/src/main/resources/org.mapstruct.ap.model.assignment.NullCheckWrapper.ftl b/processor/src/main/resources/org.mapstruct.ap.model.assignment.NullCheckWrapper.ftl index 983b304f8..96bc29d0a 100644 --- a/processor/src/main/resources/org.mapstruct.ap.model.assignment.NullCheckWrapper.ftl +++ b/processor/src/main/resources/org.mapstruct.ap.model.assignment.NullCheckWrapper.ftl @@ -19,5 +19,10 @@ --> if ( ${sourceReference} != null ) { - <@includeModel object=assignment target=ext.target targetType=ext.targetType raw=ext.raw/> + <@includeModel object=assignment + targetBeanName=ext.targetBeanName + raw=ext.raw + existingInstanceMapping=ext.existingInstanceMapping + targetAccessorName=ext.targetAccessorName + targetType=ext.targetType/> } diff --git a/processor/src/main/resources/org.mapstruct.ap.model.assignment.SetterCollectionOrMapWrapper.ftl b/processor/src/main/resources/org.mapstruct.ap.model.assignment.SetterCollectionOrMapWrapper.ftl new file mode 100644 index 000000000..f46684dba --- /dev/null +++ b/processor/src/main/resources/org.mapstruct.ap.model.assignment.SetterCollectionOrMapWrapper.ftl @@ -0,0 +1,55 @@ +<#-- + + 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. + +--> +<#if ( ext.existingInstanceMapping ) > + if ( ${ext.targetBeanName}.${targetGetterName}() != null ) { + ${ext.targetBeanName}.${targetGetterName}().clear(); + <#if ext.targetType.collectionType> + <@includeModel object=assignment + targetBeanName=ext.targetBeanName + raw=ext.raw + existingInstanceMapping=ext.existingInstanceMapping + targetAccessorName="${targetGetterName}().addAll" + targetType=ext.targetType/> + <#else> + <@includeModel object=assignment + targetBeanName=ext.targetBeanName + raw=ext.raw + existingInstanceMapping=ext.existingInstanceMapping + targetAccessorName="${targetGetterName}().putAll" + targetType=ext.targetType/> + + } + else { + <@includeModel object=assignment + targetBeanName=ext.targetBeanName + raw=ext.raw + existingInstanceMapping=ext.existingInstanceMapping + targetAccessorName=ext.targetAccessorName + targetType=ext.targetType/> + } +<#else> + <@includeModel object=assignment + targetBeanName=ext.targetBeanName + raw=ext.raw + existingInstanceMapping=ext.existingInstanceMapping + targetAccessorName=ext.targetAccessorName + targetType=ext.targetType/> + \ No newline at end of file diff --git a/processor/src/main/resources/org.mapstruct.ap.model.assignment.SetterWrapper.ftl b/processor/src/main/resources/org.mapstruct.ap.model.assignment.SetterWrapper.ftl index 3aa72d1f9..9cdc77764 100644 --- a/processor/src/main/resources/org.mapstruct.ap.model.assignment.SetterWrapper.ftl +++ b/processor/src/main/resources/org.mapstruct.ap.model.assignment.SetterWrapper.ftl @@ -19,14 +19,17 @@ --> <#if (exceptionTypes?size == 0) > - ${ext.target}( <@includeModel object=assignment target=ext.target targetType=ext.targetType raw=ext.raw/> ); + ${ext.targetBeanName}.${ext.targetAccessorName}( <@_assignment/> ); <#else> try { - ${ext.target}( <@includeModel object=assignment target=ext.target targetType=ext.targetType raw=ext.raw/> ); + ${ext.targetBeanName}.${ext.targetAccessorName}( <@_assignment/> ); } <#list exceptionTypes as exceptionType> catch ( <@includeModel object=exceptionType/> e ) { throw new RuntimeException( e ); } - \ No newline at end of file + +<#macro _assignment> + <@includeModel object=assignment raw=ext.raw targetType=ext.targetType/> + \ No newline at end of file diff --git a/processor/src/main/resources/org.mapstruct.ap.model.assignment.TypeConversion.ftl b/processor/src/main/resources/org.mapstruct.ap.model.assignment.TypeConversion.ftl index 6f540715b..d4bb2d66e 100644 --- a/processor/src/main/resources/org.mapstruct.ap.model.assignment.TypeConversion.ftl +++ b/processor/src/main/resources/org.mapstruct.ap.model.assignment.TypeConversion.ftl @@ -18,4 +18,4 @@ limitations under the License. --> -${openExpression}<@includeModel object=assignment target=ext.target targetType=ext.targetType raw=ext.raw/>${closeExpression} \ No newline at end of file +${openExpression}<@includeModel object=assignment targetType=ext.targetType raw=ext.raw/>${closeExpression} \ No newline at end of file diff --git a/processor/src/test/java/org/mapstruct/ap/test/collection/defaultimplementation/NoSetterCollectionMappingTest.java b/processor/src/test/java/org/mapstruct/ap/test/collection/defaultimplementation/NoSetterCollectionMappingTest.java index 380509b03..af12cc3de 100644 --- a/processor/src/test/java/org/mapstruct/ap/test/collection/defaultimplementation/NoSetterCollectionMappingTest.java +++ b/processor/src/test/java/org/mapstruct/ap/test/collection/defaultimplementation/NoSetterCollectionMappingTest.java @@ -20,6 +20,8 @@ package org.mapstruct.ap.test.collection.defaultimplementation; import java.util.Arrays; import java.util.HashMap; +import java.util.List; +import java.util.Map; import org.junit.Test; import org.junit.runner.RunWith; @@ -53,5 +55,22 @@ public class NoSetterCollectionMappingTest { assertThat( target.getListValues() ).containsExactly( "foo", "bar" ); assertThat( target.getMapValues() ).includes( entry( "fooKey", "fooVal" ), entry( "barKey", "barVal" ) ); + + // now test existing instances + + NoSetterSource source2 = new NoSetterSource(); + source2.setListValues( Arrays.asList( "baz" ) ); + List originalCollectionInstance = target.getListValues(); + Map originalMapInstance = target.getMapValues(); + + NoSetterTarget target2 = NoSetterMapper.INSTANCE.toTargetWithExistingTarget( source2, target ); + + assertThat( target2.getListValues() ).isSameAs( originalCollectionInstance ); + assertThat( target2.getListValues() ).containsExactly( "baz" ); + assertThat( target2.getMapValues() ).isSameAs( originalMapInstance ); + // source2 mapvalues is empty, so the map is not cleared + assertThat( target2.getMapValues() ).includes( entry( "fooKey", "fooVal" ), entry( "barKey", "barVal" ) ); + + } } diff --git a/processor/src/test/java/org/mapstruct/ap/test/collection/defaultimplementation/NoSetterMapper.java b/processor/src/test/java/org/mapstruct/ap/test/collection/defaultimplementation/NoSetterMapper.java index 61f536598..822b96cf6 100644 --- a/processor/src/test/java/org/mapstruct/ap/test/collection/defaultimplementation/NoSetterMapper.java +++ b/processor/src/test/java/org/mapstruct/ap/test/collection/defaultimplementation/NoSetterMapper.java @@ -19,6 +19,7 @@ package org.mapstruct.ap.test.collection.defaultimplementation; import org.mapstruct.Mapper; +import org.mapstruct.MappingTarget; import org.mapstruct.factory.Mappers; /** @@ -31,4 +32,6 @@ public interface NoSetterMapper { NoSetterMapper INSTANCE = Mappers.getMapper( NoSetterMapper.class ); NoSetterTarget toTarget(NoSetterSource source); + + NoSetterTarget toTargetWithExistingTarget(NoSetterSource source, @MappingTarget NoSetterTarget preExistTarget); } diff --git a/processor/src/test/java/org/mapstruct/ap/test/npe/NullObject.java b/processor/src/test/java/org/mapstruct/ap/test/npe/NullObject.java new file mode 100644 index 000000000..bcba6d1a5 --- /dev/null +++ b/processor/src/test/java/org/mapstruct/ap/test/npe/NullObject.java @@ -0,0 +1,27 @@ +/** + * 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.npe; + +/** + * + * @author Sjaak Derksen + */ +public class NullObject { + +} diff --git a/processor/src/test/java/org/mapstruct/ap/test/npe/NullObjectMapper.java b/processor/src/test/java/org/mapstruct/ap/test/npe/NullObjectMapper.java new file mode 100644 index 000000000..15f1303cd --- /dev/null +++ b/processor/src/test/java/org/mapstruct/ap/test/npe/NullObjectMapper.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.test.npe; + +/** + * + * @author Sjaak Derksen + */ +public class NullObjectMapper { + + + public String toNullString(NullObject in) { + return in.toString(); + } +} diff --git a/processor/src/test/java/org/mapstruct/ap/test/npe/NullPtrCheckTest.java b/processor/src/test/java/org/mapstruct/ap/test/npe/NullPtrCheckTest.java new file mode 100644 index 000000000..3e19da5a8 --- /dev/null +++ b/processor/src/test/java/org/mapstruct/ap/test/npe/NullPtrCheckTest.java @@ -0,0 +1,73 @@ +/** + * 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.npe; + +import static org.fest.assertions.Assertions.assertThat; +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.runner.AnnotationProcessorTestRunner; + +/** + * Test for correct handling of null checks. + * + * @author Sjaak Derksen + */ +@IssueKey( "134" ) +@WithClasses( { + SourceTargetMapper.class, + NullObjectMapper.class, + NullObject.class, + Source.class, + Target.class +} ) +@RunWith( AnnotationProcessorTestRunner.class ) +public class NullPtrCheckTest { + + @Test( expected = NullPointerException.class ) + public void shouldThrowNullptrWhenCustomMapperIsInvoked() { + + Source source = new Source(); + source.setNumber( "5" ); + SourceTargetMapper.INSTANCE.sourceToTarget( source ); + } + + @Test + public void shouldSurroundTypeConversionWithNPECheck() { + + Source source = new Source(); + source.setSomeObject( new NullObject() ); + Target target = SourceTargetMapper.INSTANCE.sourceToTarget( source ); + + assertThat( target.getNumber() ).isNull(); + + } + + @Test + public void shouldSurroundArrayListConstructionWithNPECheck() { + + Source source = new Source(); + source.setSomeObject( new NullObject() ); + Target target = SourceTargetMapper.INSTANCE.sourceToTarget( source ); + + assertThat( target.getSomeList() ).isNull(); + } + +} diff --git a/processor/src/test/java/org/mapstruct/ap/test/npe/Source.java b/processor/src/test/java/org/mapstruct/ap/test/npe/Source.java new file mode 100644 index 000000000..e96efb091 --- /dev/null +++ b/processor/src/test/java/org/mapstruct/ap/test/npe/Source.java @@ -0,0 +1,59 @@ +/** + * 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.npe; + +import java.util.List; + +/** + * + * @author Sjaak Derksen + */ +public class Source { + + private NullObject someObject; + private String number; + private List someList; + + public NullObject getSomeObject() { + return someObject; + } + + public void setSomeObject( NullObject someObject ) { + this.someObject = someObject; + } + + public String getNumber() { + return number; + } + + public void setNumber( String number ) { + this.number = number; + } + + public List getSomeList() { + return someList; + } + + public void setSomeList( List someList ) { + this.someList = someList; + } + + + +} diff --git a/processor/src/test/java/org/mapstruct/ap/test/npe/SourceTargetMapper.java b/processor/src/test/java/org/mapstruct/ap/test/npe/SourceTargetMapper.java new file mode 100644 index 000000000..8a939a4f7 --- /dev/null +++ b/processor/src/test/java/org/mapstruct/ap/test/npe/SourceTargetMapper.java @@ -0,0 +1,34 @@ +/** + * 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.npe; + +import org.mapstruct.Mapper; +import org.mapstruct.factory.Mappers; + +/** + * + * @author Sjaak Derksen + */ +@Mapper (uses = NullObjectMapper.class) +public interface SourceTargetMapper { + + SourceTargetMapper INSTANCE = Mappers.getMapper( SourceTargetMapper.class ); + + Target sourceToTarget(Source source); +} diff --git a/processor/src/test/java/org/mapstruct/ap/test/npe/Target.java b/processor/src/test/java/org/mapstruct/ap/test/npe/Target.java new file mode 100644 index 000000000..33e771f16 --- /dev/null +++ b/processor/src/test/java/org/mapstruct/ap/test/npe/Target.java @@ -0,0 +1,59 @@ +/** + * 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.npe; + +import java.util.List; + +/** + * + * @author Sjaak Derksen + */ +public class Target { + + private String someObject; + private Integer number; + private List someList; + + public String getSomeObject() { + return someObject; + } + + public void setSomeObject( String someObject ) { + this.someObject = someObject; + } + + public Integer getNumber() { + return number; + } + + public void setNumber( Integer number ) { + this.number = number; + } + + public List getSomeList() { + return someList; + } + + public void setSomeList( List someList ) { + this.someList = someList; + } + + + +}