Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -697,20 +697,34 @@ public Type replaceSuperBoundWith( Type compare, Type replacement ) {
return this;
}

DeclaredType declaredType = typeUtils.getDeclaredType(
TypeElement typeElementWithoutBounds;
Type componentTypeWithoutBounds;
TypeMirror typeMirrorWithoutBounds;
if ( this.componentType != null ) {
typeElementWithoutBounds = null;
componentTypeWithoutBounds = this.componentType.replaceSuperBoundWith( compare, replacement );
typeMirrorWithoutBounds = typeUtils.getArrayType( componentTypeWithoutBounds.getTypeMirror() );
}
else {
DeclaredType declaredType = typeUtils.getDeclaredType(
typeElement,
mirrors
);
);
typeMirrorWithoutBounds = declaredType;
typeElementWithoutBounds = (TypeElement) declaredType.asElement();
componentTypeWithoutBounds = null;
}

return new Type(
typeUtils,
elementUtils,
typeFactory,
accessorNaming,
declaredType,
(TypeElement) declaredType.asElement(),
typeMirrorWithoutBounds,
typeElementWithoutBounds,
bounds,
implementationType,
componentType,
componentTypeWithoutBounds,
packageName,
name,
qualifiedName,
Expand Down Expand Up @@ -740,20 +754,34 @@ public Type withoutBounds() {
mirrors.add( typeParameter.getTypeBound().getTypeMirror() );
}

DeclaredType declaredType = typeUtils.getDeclaredType(
typeElement,
mirrors.toArray( new TypeMirror[] {} )
);
TypeElement typeElementWithoutBounds;
Type componentTypeWithoutBounds;
TypeMirror typeMirrorWithoutBounds;
if ( this.componentType != null ) {
typeElementWithoutBounds = null;
componentTypeWithoutBounds = this.componentType.withoutBounds();
typeMirrorWithoutBounds = typeUtils.getArrayType( componentTypeWithoutBounds.getTypeMirror() );
}
else {
DeclaredType declaredType = typeUtils.getDeclaredType(
typeElement,
mirrors.toArray( new TypeMirror[] {} )
);
typeMirrorWithoutBounds = declaredType;
typeElementWithoutBounds = (TypeElement) declaredType.asElement();
componentTypeWithoutBounds = null;
}

return new Type(
typeUtils,
elementUtils,
typeFactory,
accessorNaming,
declaredType,
(TypeElement) declaredType.asElement(),
typeMirrorWithoutBounds,
typeElementWithoutBounds,
bounds,
implementationType,
componentType,
componentTypeWithoutBounds,
packageName,
name,
qualifiedName,
Expand All @@ -772,7 +800,7 @@ public Type withoutBounds() {
}

private Type replaceGeneric(Type oldGenericType, Type newType) {
if ( !typeParameters.contains( oldGenericType ) || newType == null ) {
if ( !typeParameters.contains( oldGenericType ) || newType == null || oldGenericType.equals( newType ) ) {
return this;
}
newType = newType.getBoxedEquivalent();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -518,6 +518,9 @@ private List<Type> extractTypes(List<? extends TypeMirror> typeMirrors) {
}

private List<Type> getTypeParameters(TypeMirror mirror, boolean isImplementationType) {
while ( mirror.getKind() == TypeKind.ARRAY ) {
mirror = getComponentType( mirror );
}
if ( mirror.getKind() != TypeKind.DECLARED ) {
return java.util.Collections.emptyList();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

-->
<#-- @ftlvariable name="" type="org.mapstruct.ap.internal.model.IterableMappingMethod" -->
<#import "macro/CommonMacros.ftl" as lib>
<#list annotations as annotation>
<#nt><@includeModel object=annotation/>
</#list>
Expand All @@ -28,7 +29,7 @@
}
return<#if returnType.name != "void"> ${resultName}</#if>;
<#else>
return new <@includeModel object=resultElementType/>[0];
return <@lib.constructArrayType targetType=resultType targetSize=0/>;
</#if>
<#else>
<#if existingInstanceMapping>
Expand All @@ -43,8 +44,7 @@

<#if resultType.arrayType>
<#if !existingInstanceMapping>
<#assign elementTypeString><@includeModel object=resultElementType/></#assign>
${elementTypeString}[] ${resultName} = new ${elementTypeString?keep_before('[]')}[<@iterableSize/>]${elementTypeString?replace('[^\\[\\]]+', '', 'r')};
<@includeModel object=resultElementType/>[] ${resultName} = <@lib.constructArrayType targetType=resultType targetSize=iterableSize()/>;
</#if>
<#else>
<#if existingInstanceMapping>
Expand All @@ -64,7 +64,7 @@
int ${index1Name} = 0;
for ( <@includeModel object=sourceElementType/> ${loopVariableName} : ${sourceParameter.name} ) {
<#if existingInstanceMapping>
if ( ( ${index1Name} >= ${resultName}.length ) || ( ${index1Name} >= <@iterableSize/> ) ) {
if ( ( ${index1Name} >= ${resultName}.length ) || ( ${index1Name} >= ${iterableSize()} ) ) {
break;
}
</#if>
Expand Down Expand Up @@ -95,15 +95,13 @@
</#list>
</@compress>
</#macro>
<#macro iterableSize>
<@compress single_line=true>
<#if sourceParameter.type.arrayType>
${sourceParameter.name}.length
<#else>
${sourceParameter.name}.size()
</#if>
</@compress>
</#macro>
<#function iterableSize>
<#if sourceParameter.type.arrayType>
<#return sourceParameter.name + ".length">
<#else>
<#return sourceParameter.name + ".size()">
</#if>
</#function>
<#macro iterableLocalVarDef>
<@compress single_line=true>
<#if resultType.fullyQualifiedName == "java.lang.Iterable">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

-->
<#-- @ftlvariable name="" type="org.mapstruct.ap.internal.model.StreamMappingMethod" -->
<#import "macro/CommonMacros.ftl" as lib>
<#list annotations as annotation>
<#nt><@includeModel object=annotation/>
</#list>
Expand All @@ -29,7 +30,7 @@
}
return<#if returnType.name != "void"> ${resultName}</#if>;
<#else>
return new <@includeModel object=resultElementType/>[0];
return <@lib.constructArrayType targetType=resultType targetSize=0/>;
</#if>
<#elseif resultType.iterableType>
<#if existingInstanceMapping>
Expand Down Expand Up @@ -88,15 +89,15 @@
<#if resultType.arrayType>
<#if existingInstanceMapping>
int ${index1Name} = 0;
for ( <@includeModel object=resultElementType/> ${loopVariableName} : ${sourceParameter.name}.limit( ${resultName}.length )<@streamMapSupplier />.toArray( ${resultElementType}[]::new ) ) {
for ( <@includeModel object=resultElementType/> ${loopVariableName} : ${sourceParameter.name}.limit( ${resultName}.length )<@streamMapSupplier />.toArray( <@includeModel object=resultElementType raw=true/>[]::new ) ) {
if ( ( ${index1Name} >= ${resultName}.length ) ) {
break;
}
${resultName}[${index1Name}++] = ${loopVariableName};
}
<#else>
<#if canReturnImmediatelly><#if returnType.name != "void">return </#if><#else> <#if needVarDefine>${resultElementType}[] <#else>${resultName} = </#if></#if>${sourceParameter.name}<@streamMapSupplier />
.toArray( <@includeModel object=resultElementType/>[]::new );
.toArray( <@includeModel object=resultElementType raw=true/>[]::new );
</#if>
<#elseif resultType.iterableType>
<#if existingInstanceMapping || !canReturnImmediatelly>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
<#elseif hasSuperBound()>
? super <@includeModel object=typeBound />
<#else>
<#if ext.asVarArgs!false>${createReferenceName()?remove_ending("[]")}...<#else>${createReferenceName()}</#if></#if><#if (!ext.raw?? && typeParameters?size > 0) ><<#list typeParameters as typeParameter><@includeModel object=typeParameter /><#if typeParameter_has_next>, </#if></#list>>
<#assign createReferenceName = createReferenceName() />
${createReferenceName?keep_before("[]")}<#if (!ext.raw?? && typeParameters?size > 0) ><<#list typeParameters as typeParameter><@includeModel object=typeParameter /><#if typeParameter_has_next>, </#if></#list>></#if>${createReferenceName?keep_after("[]")}<#if ext.asVarArgs!false>...<#elseif isArrayType()>[]</#if>
</#if>
</@compress>
Original file line number Diff line number Diff line change
Expand Up @@ -166,6 +166,12 @@ Performs a default assignment with a default value.
<@constructTargetObject targetType=ext.targetType/>
</#if>
</@compress></#macro>
<#--
-->
<#macro constructArrayType targetType targetSize><@compress single_line=true>
<#assign targetTypeString><@includeModel object=targetType raw=true/></#assign>
new ${targetTypeString?keep_before("[")}[${targetSize}]${targetTypeString?keep_after("]")}
</@compress></#macro>
<#--
macro: constructTargetObject

Expand All @@ -178,7 +184,7 @@ Performs a default assignment with a default value.
<#if targetType.implementationType??>
new <@includeModel object=targetType.implementationType raw=true/><#if targetType.implementationType.typeParameters?size != 0><></#if>()
<#elseif targetType.arrayType>
new <@includeModel object=targetType.componentType/>[0]
<@constructArrayType targetType=targetType targetSize=0/>
<#elseif targetType.sensibleDefault??>
${targetType.sensibleDefault}
<#elseif targetType.optionalType>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,9 @@
import java.util.List;

import org.junit.jupiter.api.extension.RegisterExtension;
import org.mapstruct.ap.test.array._target.GenericScientistDto;
import org.mapstruct.ap.test.array._target.ScientistDto;
import org.mapstruct.ap.test.array.source.GenericScientist;
import org.mapstruct.ap.test.array.source.Scientist;
import org.mapstruct.ap.testutil.IssueKey;
import org.mapstruct.ap.testutil.ProcessorTest;
Expand All @@ -18,7 +20,8 @@

import static org.assertj.core.api.Assertions.assertThat;

@WithClasses( { Scientist.class, ScientistDto.class, ScienceMapper.class } )
@WithClasses( { Scientist.class, ScientistDto.class, GenericScientist.class, GenericScientistDto.class,
ScienceMapper.class } )
@IssueKey("108")
public class ArrayMappingTest {

Expand Down Expand Up @@ -56,30 +59,134 @@ public void shouldForgeMappingForIntToString() {
}

@ProcessorTest
public void shouldMapArrayToArray() {
public void shouldMapArrayToArrayAndNullToNull() {
ScientistDto[] dtos = ScienceMapper.INSTANCE
.scientistsToDtos( new Scientist[]{ new Scientist( "Bob" ), new Scientist( "Larry" ) } );
.scientistsToDtosReturnNull( new Scientist[]{ new Scientist( "Bob" ), new Scientist( "Larry" ) } );

assertThat( dtos ).isNotNull();
assertThat( dtos ).extracting( "name" ).containsOnly( "Bob", "Larry" );

assertThat( ScienceMapper.INSTANCE.scientistsToDtosReturnNull( (Scientist[]) null ) ).isNull();
}

@ProcessorTest
public void shouldMapArrayToArrayAndNullToDefault() {
ScientistDto[] dtos = ScienceMapper.INSTANCE
.scientistsToDtosReturnDefault( new Scientist[]{ new Scientist( "Bob" ), new Scientist( "Larry" ) } );

assertThat( dtos ).isNotNull();
assertThat( dtos ).extracting( "name" ).containsOnly( "Bob", "Larry" );

assertThat( ScienceMapper.INSTANCE.scientistsToDtosReturnDefault( (Scientist[]) null ) ).isEmpty();
}

@ProcessorTest
public void shouldMapListToArray() {
public void shouldMapListToArrayAndNullToNull() {
ScientistDto[] dtos = ScienceMapper.INSTANCE
.scientistsToDtos( Arrays.asList( new Scientist( "Bob" ), new Scientist( "Larry" ) ) );
.scientistsToDtosReturnNull( Arrays.asList( new Scientist( "Bob" ), new Scientist( "Larry" ) ) );

assertThat( dtos ).isNotNull();
assertThat( dtos ).extracting( "name" ).containsOnly( "Bob", "Larry" );

assertThat( ScienceMapper.INSTANCE.scientistsToDtosReturnNull( (List<Scientist>) null ) ).isNull();
}

@ProcessorTest
public void shouldMapArrayToList() {
public void shouldMapListToArrayAndNullToDefault() {
ScientistDto[] dtos = ScienceMapper.INSTANCE
.scientistsToDtosReturnDefault( Arrays.asList( new Scientist( "Bob" ), new Scientist( "Larry" ) ) );

assertThat( dtos ).isNotNull();
assertThat( dtos ).extracting( "name" ).containsOnly( "Bob", "Larry" );

assertThat( ScienceMapper.INSTANCE.scientistsToDtosReturnDefault( (List<Scientist>) null ) ).isEmpty();
}

@ProcessorTest
public void shouldMapArrayToListAndNullToNull() {
List<ScientistDto> dtos = ScienceMapper.INSTANCE
.scientistsToDtosAsList( new Scientist[]{ new Scientist( "Bob" ), new Scientist( "Larry" ) } );
.scientistsToDtosAsListReturnNull( new Scientist[]{ new Scientist( "Bob" ), new Scientist( "Larry" ) } );

assertThat( dtos ).isNotNull();
assertThat( dtos ).extracting( "name" ).containsOnly( "Bob", "Larry" );

assertThat( ScienceMapper.INSTANCE.scientistsToDtosAsListReturnNull( null ) ).isNull();
}

@ProcessorTest
public void shouldMapArrayToListAndNullToDefault() {
List<ScientistDto> dtos = ScienceMapper.INSTANCE
.scientistsToDtosAsListReturnDefault(
new Scientist[]{ new Scientist( "Bob" ), new Scientist( "Larry" ) } );

assertThat( dtos ).isNotNull();
assertThat( dtos ).extracting( "name" ).containsOnly( "Bob", "Larry" );

assertThat( ScienceMapper.INSTANCE.scientistsToDtosAsListReturnDefault( null ) ).isEmpty();
}

@ProcessorTest
@SuppressWarnings("unchecked")
public void shouldMapGenericArrayToGenericArrayAndNullToNull() {
GenericScientistDto<String>[] dtos = ScienceMapper.INSTANCE
.genericScientistToDtosReturnNull(
new GenericScientist[]{ new GenericScientist<>( "Bob" ), new GenericScientist<>( "Larry" ) } );

assertThat( dtos ).isNotNull();
assertThat( dtos ).extracting( "name" ).containsOnly( "Bob", "Larry" );

assertThat( ScienceMapper.INSTANCE.genericScientistToDtosReturnNull( (GenericScientist<String>[]) null ) )
.isNull();
}

@ProcessorTest
@SuppressWarnings("unchecked")
public void shouldMapGenericArrayToGenericArrayAndNullToDefault() {
GenericScientistDto<String>[] dtos = ScienceMapper.INSTANCE.genericScientistToDtosReturnDefault(
new GenericScientist[]{ new GenericScientist<>( "Bob" ), new GenericScientist<>( "Larry" ) } );

assertThat( dtos ).isNotNull();
assertThat( dtos ).extracting( "name" ).containsOnly( "Bob", "Larry" );

assertThat( ScienceMapper.INSTANCE.genericScientistToDtosReturnDefault( (GenericScientist<String>[]) null ) )
.isEmpty();
}

@ProcessorTest
public void shouldMapListToGenericArrayAndNullToNull() {
GenericScientistDto<String>[] dtos = ScienceMapper.INSTANCE.genericScientistToDtosReturnNull(
Arrays.asList( new GenericScientist<>( "Bob" ), new GenericScientist<>( "Larry" ) ) );

assertThat( dtos ).isNotNull();
assertThat( dtos ).extracting( "name" ).containsOnly( "Bob", "Larry" );

assertThat( ScienceMapper.INSTANCE.genericScientistToDtosReturnNull( (List<GenericScientist<String>>) null ) )
.isNull();
}

@ProcessorTest
public void shouldMapListToGenericArrayAndNullToDefault() {
GenericScientistDto<String>[] dtos = ScienceMapper.INSTANCE
.genericScientistToDtosReturnDefault(
Arrays.asList( new GenericScientist<>("Bob"), new GenericScientist<>( "Larry" ) ) );

assertThat( dtos ).isNotNull();
assertThat( dtos ).extracting( "name" ).containsOnly( "Bob", "Larry" );

assertThat( ScienceMapper.INSTANCE
.genericScientistToDtosReturnDefault( (List<GenericScientist<String>>) null ) ).isEmpty();
}

@ProcessorTest
@SuppressWarnings("unchecked")
public void shouldMapGenericArrayToListAndNullToNull() {
List<GenericScientist<String>> dtos = ScienceMapper.INSTANCE.genericScientistToDtosAsList(
new GenericScientist[]{ new GenericScientist<>( "Bob" ), new GenericScientist<>( "Larry" ) } );

assertThat( dtos ).isNotNull();
assertThat( dtos ).extracting( "name" ).containsOnly( "Bob", "Larry" );

assertThat( ScienceMapper.INSTANCE.genericScientistToDtosAsList( null ) ).isNull();
}

@ProcessorTest
Expand Down
Loading
Loading