diff --git a/processor/src/main/java/org/mapstruct/ap/internal/model/MapMappingMethod.java b/processor/src/main/java/org/mapstruct/ap/internal/model/MapMappingMethod.java index 7506b69fd..35c8f81d2 100644 --- a/processor/src/main/java/org/mapstruct/ap/internal/model/MapMappingMethod.java +++ b/processor/src/main/java/org/mapstruct/ap/internal/model/MapMappingMethod.java @@ -151,17 +151,7 @@ public class MapMappingMethod extends MappingMethod { } if ( valueAssignment == null ) { - valueAssignment = forgeMapping( valueSourceRHS, valueSourceType, valueTargetType ); - -// if ( method instanceof ForgedMethod ) { -// // leave messaging to calling property mapping -// return null; -// } -// else { -// ctx.getMessager().printMessage( method.getExecutable(), -// Message.MAPMAPPING_VALUE_MAPPING_NOT_FOUND ); -// } } // mapNullToDefault 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 dcb9c08d5..0d9d217f7 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 @@ -37,7 +37,6 @@ import org.mapstruct.ap.internal.model.assignment.ArrayCopyWrapper; import org.mapstruct.ap.internal.model.assignment.Assignment; import org.mapstruct.ap.internal.model.assignment.EnumConstantWrapper; import org.mapstruct.ap.internal.model.assignment.GetterWrapperForCollectionsAndMaps; -import org.mapstruct.ap.internal.model.assignment.NullCheckWrapper; import org.mapstruct.ap.internal.model.assignment.SetterWrapper; import org.mapstruct.ap.internal.model.assignment.SetterWrapperForCollectionsAndMaps; import org.mapstruct.ap.internal.model.assignment.UpdateWrapper; @@ -435,10 +434,9 @@ public class PropertyMapping extends ModelElement { targetPropertyName, arrayType, targetType, - existingVariableNames, isFieldAssignment() ); - return new NullCheckWrapper( assignment ); + return assignment; } private SourceRHS getSourceRHS( SourceReference sourceReference ) { diff --git a/processor/src/main/java/org/mapstruct/ap/internal/model/assignment/ArrayCopyWrapper.java b/processor/src/main/java/org/mapstruct/ap/internal/model/assignment/ArrayCopyWrapper.java index fd187329b..f11eb9451 100644 --- a/processor/src/main/java/org/mapstruct/ap/internal/model/assignment/ArrayCopyWrapper.java +++ b/processor/src/main/java/org/mapstruct/ap/internal/model/assignment/ArrayCopyWrapper.java @@ -18,16 +18,10 @@ */ package org.mapstruct.ap.internal.model.assignment; -import static org.mapstruct.ap.internal.util.Strings.decapitalize; -import static org.mapstruct.ap.internal.util.Strings.getSaveVariableName; - -import java.util.Collection; -import java.util.Collections; import java.util.HashSet; import java.util.Set; import org.mapstruct.ap.internal.model.common.Type; -import org.mapstruct.ap.internal.util.Strings; /** * Decorates the assignment as a Map or Collection constructor @@ -36,16 +30,18 @@ import org.mapstruct.ap.internal.util.Strings; */ public class ArrayCopyWrapper extends AssignmentWrapper { - private final String targetPropertyName; private final Type arraysType; private final Type targetType; - public ArrayCopyWrapper(Assignment decoratedAssignment, String targetPropertyName, Type arraysType, - Type targetType, Collection existingVariableNames, boolean fieldAssignment) { - super( decoratedAssignment, fieldAssignment ); - this.targetPropertyName = Strings.getSaveVariableName( targetPropertyName, existingVariableNames ); + public ArrayCopyWrapper(Assignment rhs, + String targetPropertyName, + Type arraysType, + Type targetType, + boolean fieldAssignment) { + super( rhs, fieldAssignment ); this.arraysType = arraysType; this.targetType = targetType; + rhs.setSourceLocalVarName( rhs.createLocalVarName( targetPropertyName ) ); } @Override @@ -57,7 +53,7 @@ public class ArrayCopyWrapper extends AssignmentWrapper { return imported; } - public String getLocalVarName() { - return getSaveVariableName( decapitalize( targetPropertyName ), Collections.emptyList() ); + public boolean isIncludeSourceNullCheck() { + return true; } } diff --git a/processor/src/main/java/org/mapstruct/ap/internal/model/assignment/Assignment.java b/processor/src/main/java/org/mapstruct/ap/internal/model/assignment/Assignment.java index 09ef8bed1..2573cb9f7 100644 --- a/processor/src/main/java/org/mapstruct/ap/internal/model/assignment/Assignment.java +++ b/processor/src/main/java/org/mapstruct/ap/internal/model/assignment/Assignment.java @@ -109,17 +109,18 @@ public interface Assignment { Type getSourceType(); /** - * safe (local) element variable name when dealing with collections. + * Creates an unique safe (local) variable name. * * @param desiredName the desired name - * @return the desired name, made unique + * + * @return the desired name, made unique in the scope of the bean mapping. */ String createLocalVarName( String desiredName ); /** - * a local variable name for supporting a null check and avoiding executing a nested method forged method twice + * See {@link #setSourceLocalVarName(java.lang.String) } * - * @return local variable name (can be null) + * @return local variable name (can be null if not set) */ String getSourceLocalVarName(); @@ -132,7 +133,9 @@ public interface Assignment { String getSourceParameterName(); /** - * Use sourceLocalVarName iso sourceReference + * Replaces the sourceReference at the call site in the assignment in the template with this sourceLocalVarName. + * The sourceLocalVarName can subsequently be used for e.g. null checking. + * * @param sourceLocalVarName source local variable name */ void setSourceLocalVarName(String sourceLocalVarName); diff --git a/processor/src/main/java/org/mapstruct/ap/internal/model/assignment/NullCheckWrapper.java b/processor/src/main/java/org/mapstruct/ap/internal/model/assignment/NullCheckWrapper.java deleted file mode 100644 index 937465d99..000000000 --- a/processor/src/main/java/org/mapstruct/ap/internal/model/assignment/NullCheckWrapper.java +++ /dev/null @@ -1,32 +0,0 @@ -/** - * Copyright 2012-2016 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.internal.model.assignment; - -/** - * Wraps the assignment in a null check. - * - * @author Sjaak Derksen - */ -public class NullCheckWrapper extends AssignmentWrapper { - - public NullCheckWrapper( Assignment decoratedAssignment ) { - super( decoratedAssignment, false ); - } - -} diff --git a/processor/src/main/java/org/mapstruct/ap/internal/model/assignment/UpdateNullCheckWrapper.java b/processor/src/main/java/org/mapstruct/ap/internal/model/assignment/UpdateNullCheckWrapper.java deleted file mode 100644 index c769f3658..000000000 --- a/processor/src/main/java/org/mapstruct/ap/internal/model/assignment/UpdateNullCheckWrapper.java +++ /dev/null @@ -1,33 +0,0 @@ -/** - * Copyright 2012-2016 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.internal.model.assignment; - -/** - * Wraps an update-assignment in a null check and sets the target property to {@code null}, if the source is - * {@code null}. - * - * @author Andreas Gudian - */ -public class UpdateNullCheckWrapper extends AssignmentWrapper { - - public UpdateNullCheckWrapper(Assignment decoratedAssignment, boolean fieldAssignment) { - super( decoratedAssignment, fieldAssignment ); - } - -} diff --git a/processor/src/main/resources/org/mapstruct/ap/internal/model/assignment/ArrayCopyWrapper.ftl b/processor/src/main/resources/org/mapstruct/ap/internal/model/assignment/ArrayCopyWrapper.ftl index 767b9ede8..408ccd382 100644 --- a/processor/src/main/resources/org/mapstruct/ap/internal/model/assignment/ArrayCopyWrapper.ftl +++ b/processor/src/main/resources/org/mapstruct/ap/internal/model/assignment/ArrayCopyWrapper.ftl @@ -19,25 +19,9 @@ --> <#import "../macro/CommonMacros.ftl" as lib> -<#if (thrownTypes?size == 0) > - <@includeModel object=ext.targetType/> ${localVarName} = <@_assignment/>; - ${ext.targetBeanName}.${ext.targetWriteAccessorName}<@lib.handleWrite>Arrays.copyOf( ${localVarName}, ${localVarName}.length ); -<#else> - try { - <@includeModel object=ext.targetType/> ${localVarName} = <@_assignment/>; - ${ext.targetBeanName}.${ext.targetWriteAccessorName}<@lib.handleWrite>Arrays.copyOf(>Arrays.copyOf( ${localVarName}, ${localVarName}.length ); - } - <#list thrownTypes as exceptionType> - catch ( <@includeModel object=exceptionType/> e ) { - throw new RuntimeException( e ); - } - - -<#macro _assignment> - <@includeModel object=assignment - targetBeanName=ext.targetBeanName - existingInstanceMapping=ext.existingInstanceMapping - targetReadAccessorName=ext.targetReadAccessorName - targetWriteAccessorName=ext.targetWriteAccessorName - targetType=ext.targetType/> - +<@lib.handleExceptions> + <@lib.sourceLocalVarAssignment/> + <@lib.handleSourceReferenceNullCheck> + ${ext.targetBeanName}.${ext.targetWriteAccessorName}<@lib.handleWrite>Arrays.copyOf( ${sourceLocalVarName}, ${sourceLocalVarName}.length ); + + \ No newline at end of file diff --git a/processor/src/main/resources/org/mapstruct/ap/internal/model/assignment/GetterWrapperForCollectionsAndMaps.ftl b/processor/src/main/resources/org/mapstruct/ap/internal/model/assignment/GetterWrapperForCollectionsAndMaps.ftl index 1cc8cad11..ec220a930 100644 --- a/processor/src/main/resources/org/mapstruct/ap/internal/model/assignment/GetterWrapperForCollectionsAndMaps.ftl +++ b/processor/src/main/resources/org/mapstruct/ap/internal/model/assignment/GetterWrapperForCollectionsAndMaps.ftl @@ -25,8 +25,8 @@ if ( ${ext.targetBeanName}.${ext.targetWriteAccessorName}<@lib.handleWriteAccesi <#if ext.existingInstanceMapping> ${ext.targetBeanName}.${ext.targetWriteAccessorName}<@lib.handleWriteAccesing />.clear(); - <@lib.handleNullCheck> + <@lib.handleLocalVarNullCheck> ${ext.targetBeanName}.${ext.targetWriteAccessorName}<@lib.handleWriteAccesing />.<#if ext.targetType.collectionType>addAll<#else>putAll( ${nullCheckLocalVarName} ); - + } 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 deleted file mode 100644 index 1f0037942..000000000 --- a/processor/src/main/resources/org/mapstruct/ap/internal/model/assignment/NullCheckWrapper.ftl +++ /dev/null @@ -1,45 +0,0 @@ -<#-- @ftlvariable name="" type="org.mapstruct.ap.internal.model.assignment.NullCheckWrapper" --> -<#-- - - Copyright 2012-2016 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 sourceLocalVarName??> -<@includeModel object=sourceType/> ${sourceLocalVarName} = ${sourceReference}; -if ( ${sourceLocalVarName} != null ) { - <@_assignment object=assignment defaultValue=ext.defaultValueAssignment/> -} -<#else> -if ( <#if sourcePresenceCheckerReference?? >${sourcePresenceCheckerReference}<#else>${sourceReference} != null ) { - <@_assignment object=assignment defaultValue=ext.defaultValueAssignment/> -} - -<#if ext.defaultValueAssignment?? > -else { - <@_assignment object=ext.defaultValueAssignment/> -} - -<#macro _assignment object defaultValue=""> - <@includeModel object=object - targetBeanName=ext.targetBeanName - existingInstanceMapping=ext.existingInstanceMapping - targetReadAccessorName=ext.targetReadAccessorName - targetWriteAccessorName=ext.targetWriteAccessorName - targetType=ext.targetType - defaultValue=defaultValue/> - 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 468e6fcf0..3eb625127 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 @@ -21,31 +21,7 @@ <#import "../macro/CommonMacros.ftl" as lib> <@lib.handleExceptions> <@lib.sourceLocalVarAssignment/> - <#if sourcePresenceCheckerReference??> - if ( ${sourcePresenceCheckerReference} ) { - <@assignment/>; - } - <@elseDefaultAssignment/> - <#elseif includeSourceNullCheck || ext.defaultValueAssignment??> - if ( <#if sourceLocalVarName??>${sourceLocalVarName}<#else>${sourceReference} != null ) { - <@assignment/>; - } - <@elseDefaultAssignment/> - <#else> - <@assignment/>; - - -<#-- - standard assignment ---> -<#macro assignment>${ext.targetBeanName}.${ext.targetWriteAccessorName}<@lib.handleWrite><@lib.handleAssignment/> -<#-- - add default assignment when required ---> -<#macro elseDefaultAssignment> - <#if ext.defaultValueAssignment?? > - else { - <@lib.handeDefaultAssigment/> - } - - \ No newline at end of file + <@lib.handleSourceReferenceNullCheck> + ${ext.targetBeanName}.${ext.targetWriteAccessorName}<@lib.handleWrite><@lib.handleAssignment/>; + + \ No newline at end of file diff --git a/processor/src/main/resources/org/mapstruct/ap/internal/model/assignment/SetterWrapperForCollectionsAndMaps.ftl b/processor/src/main/resources/org/mapstruct/ap/internal/model/assignment/SetterWrapperForCollectionsAndMaps.ftl index ef6c1e0c7..0018150dc 100644 --- a/processor/src/main/resources/org/mapstruct/ap/internal/model/assignment/SetterWrapperForCollectionsAndMaps.ftl +++ b/processor/src/main/resources/org/mapstruct/ap/internal/model/assignment/SetterWrapperForCollectionsAndMaps.ftl @@ -23,11 +23,11 @@ <@lib.handleExceptions> <#if ext.existingInstanceMapping> if ( ${ext.targetBeanName}.${ext.targetReadAccessorName} != null ) { - <@lib.handleNullCheck> + <@lib.handleLocalVarNullCheck> ${ext.targetBeanName}.${ext.targetReadAccessorName}.clear(); ${ext.targetBeanName}.${ext.targetReadAccessorName}.<#if ext.targetType.collectionType>addAll<#else>putAll( ${nullCheckLocalVarName} ); - - <#if !ext.defaultValueAssignment?? && !sourcePresenceCheckerReference?? && !includeSourceNullCheck>else {<#-- the opposite (defaultValueAssignment) case is handeld inside lib.handleNullCheck --> + + <#if !ext.defaultValueAssignment?? && !sourcePresenceCheckerReference?? && !includeSourceNullCheck>else {<#-- the opposite (defaultValueAssignment) case is handeld inside lib.handleLocalVarNullCheck --> ${ext.targetBeanName}.${ext.targetWriteAccessorName}<@lib.handleWrite>null; } @@ -43,9 +43,9 @@ assigns the target via the regular target write accessor (usually the setter) --> <#macro callTargetWriteAccessor> - <@lib.handleNullCheck> + <@lib.handleLocalVarNullCheck> ${ext.targetBeanName}.${ext.targetWriteAccessorName}<@lib.handleWrite><#if directAssignment><@wrapLocalVarInCollectionInitializer/><#else>${nullCheckLocalVarName}; - + <#-- wraps the local variable in a collection initializer (new collection, or EnumSet.copyOf) diff --git a/processor/src/main/resources/org/mapstruct/ap/internal/model/assignment/UpdateNullCheckWrapper.ftl b/processor/src/main/resources/org/mapstruct/ap/internal/model/assignment/UpdateNullCheckWrapper.ftl deleted file mode 100644 index 1e87e687a..000000000 --- a/processor/src/main/resources/org/mapstruct/ap/internal/model/assignment/UpdateNullCheckWrapper.ftl +++ /dev/null @@ -1,32 +0,0 @@ -<#-- - - Copyright 2012-2016 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. - ---> -<#import '../macro/CommonMacros.ftl' as lib> -if ( <#if sourcePresenceCheckerReference?? >${sourcePresenceCheckerReference}<#else>${sourceReference} != null ) { - <@includeModel object=assignment - targetBeanName=ext.targetBeanName - existingInstanceMapping=ext.existingInstanceMapping - targetReadAccessorName=ext.targetReadAccessorName - targetWriteAccessorName=ext.targetWriteAccessorName - targetType=ext.targetType/> -} -else { - ${ext.targetBeanName}.${ext.targetWriteAccessorName}<@lib.handleWrite>null; -} diff --git a/processor/src/main/resources/org/mapstruct/ap/internal/model/macro/CommonMacros.ftl b/processor/src/main/resources/org/mapstruct/ap/internal/model/macro/CommonMacros.ftl index 2a52ed235..34d93b827 100644 --- a/processor/src/main/resources/org/mapstruct/ap/internal/model/macro/CommonMacros.ftl +++ b/processor/src/main/resources/org/mapstruct/ap/internal/model/macro/CommonMacros.ftl @@ -18,18 +18,51 @@ limitations under the License. --> - <#-- - macro: handleNullCheck + macro: handleSourceReferenceNullCheck + + purpose: macro surrounds nested with either a source presence checker or a null check. It acts directly on the + source reference. It adds an else clause with the default assigment when applicable. + + requires: caller to implement boolean:getIncludeSourceNullCheck() +--> +<#macro handleSourceReferenceNullCheck> + <#if sourcePresenceCheckerReference??> + if ( ${sourcePresenceCheckerReference} ) { + <#nested> + } + <@elseDefaultAssignment/> + <#elseif includeSourceNullCheck || ext.defaultValueAssignment??> + if ( <#if sourceLocalVarName??>${sourceLocalVarName}<#else>${sourceReference} != null ) { + <#nested> + } + <@elseDefaultAssignment/> + <#else> + <#nested> + + +<#-- + local macro related to handleSourceReferenceNullCheck +--> +<#macro elseDefaultAssignment> + <#if ext.defaultValueAssignment?? > + else { + <@handeDefaultAssigment/> + } + + +<#-- + macro: handleLocalVarNullCheck purpose: macro surrounds nested with either a source presence checker or a null check. It always uses a local variable. Note that the local variable assignemnt is inside the IF statement for the source presence check. Note also, that the else clause contains the default variable assignment if present. - TODO: is only used by collection mapping currently.. should perhas be moved to there and not in common + requires: caller to implement String:getNullCheckLocalVarName() + caller to implement Type:getNullCheckLocalVarType() --> -<#macro handleNullCheck> +<#macro handleLocalVarNullCheck> <#if sourcePresenceCheckerReference??> if ( ${sourcePresenceCheckerReference} ) { <@includeModel object=nullCheckLocalVarType/> ${nullCheckLocalVarName} = <@lib.handleAssignment/>; @@ -47,7 +80,6 @@ } - <#-- macro: handleExceptions @@ -130,10 +162,11 @@ Performs a default assignment with a default value. <#-- macro: sourceLocalVarAssignment - purpose: assigment for source local variables + purpose: assignment for source local variables. The sourceLocalVarName replaces the sourceReference in the + assignmentcall. --> <#macro sourceLocalVarAssignment> <#if sourceLocalVarName??> <@includeModel object=sourceType/> ${sourceLocalVarName} = ${sourceReference}; - + \ No newline at end of file