#895 Fix generating forged iterable methods for mapping multi-dimensional Array types

This commit is contained in:
Andreas Gudian 2016-09-15 22:50:00 +02:00
parent 371e0884a4
commit 5927431791
6 changed files with 119 additions and 6 deletions

View File

@ -41,7 +41,6 @@ public class SetterWrapperForCollectionsAndMaps extends AssignmentWrapper {
private final String targetGetterName; private final String targetGetterName;
private final Assignment newCollectionOrMapAssignment; private final Assignment newCollectionOrMapAssignment;
private final Type targetType;
private final String localVarName; private final String localVarName;
public SetterWrapperForCollectionsAndMaps(Assignment decoratedAssignment, public SetterWrapperForCollectionsAndMaps(Assignment decoratedAssignment,
@ -53,7 +52,6 @@ public class SetterWrapperForCollectionsAndMaps extends AssignmentWrapper {
this.targetGetterName = targetGetterName; this.targetGetterName = targetGetterName;
this.newCollectionOrMapAssignment = newCollectionOrMapAssignment; this.newCollectionOrMapAssignment = newCollectionOrMapAssignment;
this.targetType = targetType;
this.localVarName = Strings.getSaveVariableName( targetType.getName(), existingVariableNames ); this.localVarName = Strings.getSaveVariableName( targetType.getName(), existingVariableNames );
existingVariableNames.add( localVarName ); existingVariableNames.add( localVarName );
} }

View File

@ -57,12 +57,12 @@ public class ForgedMethod implements Method {
*/ */
public ForgedMethod(String name, Type sourceType, Type targetType, MapperConfiguration mapperConfiguration, public ForgedMethod(String name, Type sourceType, Type targetType, MapperConfiguration mapperConfiguration,
ExecutableElement positionHintElement) { ExecutableElement positionHintElement) {
String sourceParamName = Strings.decapitalize( sourceType.getName().replace( "[]", "" ) ); String sourceParamName = Strings.decapitalize( sourceType.getName() );
String sourceParamSafeName = Strings.getSaveVariableName( sourceParamName ); String sourceParamSafeName = Strings.getSaveVariableName( sourceParamName );
this.parameters = Arrays.asList( new Parameter( sourceParamSafeName, sourceType ) ); this.parameters = Arrays.asList( new Parameter( sourceParamSafeName, sourceType ) );
this.returnType = targetType; this.returnType = targetType;
this.thrownTypes = new ArrayList<Type>(); this.thrownTypes = new ArrayList<Type>();
this.name = name; this.name = Strings.sanitizeIdentifierName( name );
this.mapperConfiguration = mapperConfiguration; this.mapperConfiguration = mapperConfiguration;
this.positionHintElement = positionHintElement; this.positionHintElement = positionHintElement;
} }

View File

@ -150,7 +150,7 @@ public class Strings {
* any Java keyword; starting with a lower-case letter * any Java keyword; starting with a lower-case letter
*/ */
public static String getSaveVariableName(String name, Collection<String> existingVariableNames) { public static String getSaveVariableName(String name, Collection<String> existingVariableNames) {
name = decapitalize( name ); name = decapitalize( sanitizeIdentifierName( name ) );
Set<String> conflictingNames = new HashSet<String>( KEYWORDS ); Set<String> conflictingNames = new HashSet<String>( KEYWORDS );
conflictingNames.addAll( existingVariableNames ); conflictingNames.addAll( existingVariableNames );
@ -162,4 +162,11 @@ public class Strings {
return name; return name;
} }
/**
* @param identifier identifier to sanitize
* @return the identifier without any characters that are not allowed as part of a Java identifier.
*/
public static String sanitizeIdentifierName(String identifier) {
return identifier.replace( "[]", "Array" );
}
} }

View File

@ -54,7 +54,8 @@
<#if resultType.arrayType> <#if resultType.arrayType>
<#if !existingInstanceMapping> <#if !existingInstanceMapping>
<@includeModel object=resultElementType/>[] ${resultName} = new <@includeModel object=resultElementType/>[<@iterableSize/>]; <#assign elementTypeString><@includeModel object=resultElementType/></#assign>
${elementTypeString}[] ${resultName} = new ${elementTypeString?keep_before('[]')}[<@iterableSize/>]${elementTypeString?replace('[^\\[\\]]+', '', 'r')};
</#if> </#if>
<#else> <#else>
<#if existingInstanceMapping> <#if existingInstanceMapping>

View File

@ -0,0 +1,50 @@
/**
* 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.test.bugs._895;
import static org.assertj.core.api.Assertions.assertThat;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mapstruct.ap.test.bugs._895.MultiArrayMapper.WithArrayOfByteArray;
import org.mapstruct.ap.test.bugs._895.MultiArrayMapper.WithListOfByteArray;
import org.mapstruct.ap.testutil.WithClasses;
import org.mapstruct.ap.testutil.runner.AnnotationProcessorTestRunner;
import org.mapstruct.factory.Mappers;
/**
* Verifies that forged iterable mapping methods for multi-dimensional arrays are generated properly.
*
* @author Andreas Gudian
*/
@RunWith(AnnotationProcessorTestRunner.class)
@WithClasses(MultiArrayMapper.class)
public class Issue895Test {
@Test
public void properlyMapsMultiDimensionalArrays() {
WithArrayOfByteArray arrayOfByteArray = new WithArrayOfByteArray();
arrayOfByteArray.setBytes( new byte[][] { new byte[] { 0, 1 }, new byte[] { 1, 2 } } );
WithListOfByteArray listOfByteArray = Mappers.getMapper( MultiArrayMapper.class ).convert( arrayOfByteArray );
assertThat( listOfByteArray.getBytes() ).containsExactly( new byte[] { 0, 1 }, new byte[] { 1, 2 } );
arrayOfByteArray = Mappers.getMapper( MultiArrayMapper.class ).convert( listOfByteArray );
assertThat( arrayOfByteArray.getBytes() ).containsExactly( new byte[] { 0, 1 }, new byte[] { 1, 2 } );
}
}

View File

@ -0,0 +1,57 @@
/**
* 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.test.bugs._895;
import java.util.List;
import org.mapstruct.Mapper;
/**
* @author Andreas Gudian
*/
@Mapper
public interface MultiArrayMapper {
WithListOfByteArray convert(WithArrayOfByteArray b);
WithArrayOfByteArray convert(WithListOfByteArray b);
class WithArrayOfByteArray {
private byte[][] bytes;
public byte[][] getBytes() {
return bytes;
}
public void setBytes(byte[][] bytes) {
this.bytes = bytes;
}
}
class WithListOfByteArray {
private List<byte[]> bytes;
public List<byte[]> getBytes() {
return bytes;
}
public void setBytes(List<byte[]> bytes) {
this.bytes = bytes;
}
}
}