#996 refactor ArrayCopyWrapper

This commit is contained in:
sjaakd 2016-12-18 22:43:14 +01:00
parent fc0f13a7a1
commit 1f0533ca94
13 changed files with 75 additions and 237 deletions

View File

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

View File

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

View File

@ -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<String> 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.<String>emptyList() );
public boolean isIncludeSourceNullCheck() {
return true;
}
}

View File

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

View File

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

View File

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

View File

@ -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 )</@lib.handleWrite>;
<#else>
try {
<@includeModel object=ext.targetType/> ${localVarName} = <@_assignment/>;
${ext.targetBeanName}.${ext.targetWriteAccessorName}<@lib.handleWrite>Arrays.copyOf(>Arrays.copyOf( ${localVarName}, ${localVarName}.length )</@lib.handleWrite>;
}
<#list thrownTypes as exceptionType>
catch ( <@includeModel object=exceptionType/> e ) {
throw new RuntimeException( e );
}
</#list>
</#if>
<#macro _assignment>
<@includeModel object=assignment
targetBeanName=ext.targetBeanName
existingInstanceMapping=ext.existingInstanceMapping
targetReadAccessorName=ext.targetReadAccessorName
targetWriteAccessorName=ext.targetWriteAccessorName
targetType=ext.targetType/>
</#macro>
<@lib.handleExceptions>
<@lib.sourceLocalVarAssignment/>
<@lib.handleSourceReferenceNullCheck>
${ext.targetBeanName}.${ext.targetWriteAccessorName}<@lib.handleWrite>Arrays.copyOf( ${sourceLocalVarName}, ${sourceLocalVarName}.length )</@lib.handleWrite>;
</@lib.handleSourceReferenceNullCheck>
</@lib.handleExceptions>

View File

@ -25,8 +25,8 @@ if ( ${ext.targetBeanName}.${ext.targetWriteAccessorName}<@lib.handleWriteAccesi
<#if ext.existingInstanceMapping>
${ext.targetBeanName}.${ext.targetWriteAccessorName}<@lib.handleWriteAccesing />.clear();
</#if>
<@lib.handleNullCheck>
<@lib.handleLocalVarNullCheck>
${ext.targetBeanName}.${ext.targetWriteAccessorName}<@lib.handleWriteAccesing />.<#if ext.targetType.collectionType>addAll<#else>putAll</#if>( ${nullCheckLocalVarName} );
</@lib.handleNullCheck>
</@lib.handleLocalVarNullCheck>
</@lib.handleExceptions>
}

View File

@ -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</#if> ) {
<@_assignment object=assignment defaultValue=ext.defaultValueAssignment/>
}
</#if>
<#if ext.defaultValueAssignment?? >
else {
<@_assignment object=ext.defaultValueAssignment/>
}
</#if>
<#macro _assignment object defaultValue="">
<@includeModel object=object
targetBeanName=ext.targetBeanName
existingInstanceMapping=ext.existingInstanceMapping
targetReadAccessorName=ext.targetReadAccessorName
targetWriteAccessorName=ext.targetWriteAccessorName
targetType=ext.targetType
defaultValue=defaultValue/>
</#macro>

View File

@ -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}</#if> != null ) {
<@assignment/>;
}
<@elseDefaultAssignment/>
<#else>
<@assignment/>;
</#if>
</@lib.handleExceptions>
<#--
standard assignment
-->
<#macro assignment>${ext.targetBeanName}.${ext.targetWriteAccessorName}<@lib.handleWrite><@lib.handleAssignment/></@lib.handleWrite></#macro>
<#--
add default assignment when required
-->
<#macro elseDefaultAssignment>
<#if ext.defaultValueAssignment?? >
else {
<@lib.handeDefaultAssigment/>
}
</#if>
</#macro>
<@lib.handleSourceReferenceNullCheck>
${ext.targetBeanName}.${ext.targetWriteAccessorName}<@lib.handleWrite><@lib.handleAssignment/></@lib.handleWrite>;
</@lib.handleSourceReferenceNullCheck>
</@lib.handleExceptions>

View File

@ -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</#if>( ${nullCheckLocalVarName} );
</@lib.handleNullCheck>
<#if !ext.defaultValueAssignment?? && !sourcePresenceCheckerReference?? && !includeSourceNullCheck>else {<#-- the opposite (defaultValueAssignment) case is handeld inside lib.handleNullCheck -->
</@lib.handleLocalVarNullCheck>
<#if !ext.defaultValueAssignment?? && !sourcePresenceCheckerReference?? && !includeSourceNullCheck>else {<#-- the opposite (defaultValueAssignment) case is handeld inside lib.handleLocalVarNullCheck -->
${ext.targetBeanName}.${ext.targetWriteAccessorName}<@lib.handleWrite>null</@lib.handleWrite>;
}
</#if>
@ -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}</#if></@lib.handleWrite>;
</@lib.handleNullCheck>
</@lib.handleLocalVarNullCheck>
</#macro>
<#--
wraps the local variable in a collection initializer (new collection, or EnumSet.copyOf)

View File

@ -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</#if> ) {
<@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</@lib.handleWrite>;
}

View File

@ -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}</#if> != null ) {
<#nested>
}
<@elseDefaultAssignment/>
<#else>
<#nested>
</#if>
</#macro>
<#--
local macro related to handleSourceReferenceNullCheck
-->
<#macro elseDefaultAssignment>
<#if ext.defaultValueAssignment?? >
else {
<@handeDefaultAssigment/>
}
</#if>
</#macro>
<#--
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 @@
}
</#if>
</#macro>
<#--
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};
</#if>
</#macro>
</#macro>