#1700 Optimizing code for adders and stream adders (#1701)

This commit is contained in:
Sjaak Derksen 2019-01-29 20:02:23 +01:00 committed by GitHub
parent 0981959ff0
commit 07c7a29adc
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
20 changed files with 233 additions and 38 deletions

View File

@ -169,8 +169,8 @@ public class MethodReference extends ModelElement implements Assignment {
} }
@Override @Override
public String createLocalVarName( String desiredName ) { public String createUniqueVarName(String desiredName ) {
return assignment.createLocalVarName( desiredName ); return assignment.createUniqueVarName( desiredName );
} }
@Override @Override
@ -183,6 +183,16 @@ public class MethodReference extends ModelElement implements Assignment {
assignment.setSourceLocalVarName( sourceLocalVarName ); assignment.setSourceLocalVarName( sourceLocalVarName );
} }
@Override
public String getSourceLoopVarName() {
return assignment.getSourceLoopVarName();
}
@Override
public void setSourceLoopVarName(String sourceLoopVarName) {
assignment.setSourceLoopVarName( sourceLoopVarName );
}
@Override @Override
public String getSourceParameterName() { public String getSourceParameterName() {
return assignment.getSourceParameterName(); return assignment.getSourceParameterName();

View File

@ -621,7 +621,7 @@ public class PropertyMapping extends ModelElement {
// create a local variable to which forged method can be assigned. // create a local variable to which forged method can be assigned.
String desiredName = last( sourceReference.getPropertyEntries() ).getName(); String desiredName = last( sourceReference.getPropertyEntries() ).getName();
sourceRhs.setSourceLocalVarName( sourceRhs.createLocalVarName( desiredName ) ); sourceRhs.setSourceLocalVarName( sourceRhs.createUniqueVarName( desiredName ) );
return sourceRhs; return sourceRhs;

View File

@ -89,8 +89,8 @@ public class TypeConversion extends ModelElement implements Assignment {
} }
@Override @Override
public String createLocalVarName( String desiredName ) { public String createUniqueVarName(String desiredName ) {
return assignment.createLocalVarName( desiredName ); return assignment.createUniqueVarName( desiredName );
} }
@Override @Override
@ -103,6 +103,16 @@ public class TypeConversion extends ModelElement implements Assignment {
assignment.setSourceLocalVarName( sourceLocalVarName ); assignment.setSourceLocalVarName( sourceLocalVarName );
} }
@Override
public String getSourceLoopVarName() {
return assignment.getSourceLoopVarName();
}
@Override
public void setSourceLoopVarName(String sourceLoopVarName) {
assignment.setSourceLoopVarName( sourceLoopVarName );
}
@Override @Override
public String getSourceParameterName() { public String getSourceParameterName() {
return assignment.getSourceParameterName(); return assignment.getSourceParameterName();

View File

@ -33,8 +33,12 @@ public class AdderWrapper extends AssignmentWrapper {
String adderIteratorName ) { String adderIteratorName ) {
super( rhs, fieldAssignment ); super( rhs, fieldAssignment );
this.thrownTypesToExclude = thrownTypesToExclude; this.thrownTypesToExclude = thrownTypesToExclude;
// a method local var has been added earlier.
// localVar is iteratorVariable
String desiredName = Nouns.singularize( adderIteratorName ); String desiredName = Nouns.singularize( adderIteratorName );
rhs.setSourceLocalVarName( rhs.createLocalVarName( desiredName ) ); rhs.setSourceLoopVarName( rhs.createUniqueVarName( desiredName ) );
adderType = first( getSourceType().determineTypeArguments( Collection.class ) ); adderType = first( getSourceType().determineTypeArguments( Collection.class ) );
} }
@ -56,6 +60,18 @@ public class AdderWrapper extends AssignmentWrapper {
return adderType; return adderType;
} }
public boolean isIncludeSourceNullCheck() {
return true;
}
public boolean isSetExplicitlyToNull() {
return false;
}
public boolean isSetExplicitlyToDefault() {
return false;
}
@Override @Override
public Set<Type> getImportTypes() { public Set<Type> getImportTypes() {
Set<Type> imported = new HashSet<>(); Set<Type> imported = new HashSet<>();

View File

@ -33,7 +33,7 @@ public class ArrayCopyWrapper extends AssignmentWrapper {
super( rhs, fieldAssignment ); super( rhs, fieldAssignment );
this.arraysType = arraysType; this.arraysType = arraysType;
this.targetType = targetType; this.targetType = targetType;
rhs.setSourceLocalVarName( rhs.createLocalVarName( targetPropertyName ) ); rhs.setSourceLocalVarName( rhs.createUniqueVarName( targetPropertyName ) );
this.setExplicitlyToDefault = setExplicitlyToDefault; this.setExplicitlyToDefault = setExplicitlyToDefault;
this.setExplicitlyToNull = setExplicitlyToNull; this.setExplicitlyToNull = setExplicitlyToNull;
} }

View File

@ -76,6 +76,16 @@ public abstract class AssignmentWrapper extends ModelElement implements Assignme
decoratedAssignment.setSourceLocalVarName( sourceLocalVarName ); decoratedAssignment.setSourceLocalVarName( sourceLocalVarName );
} }
@Override
public String getSourceLoopVarName() {
return decoratedAssignment.getSourceLoopVarName();
}
@Override
public void setSourceLoopVarName(String sourceLoopVarName) {
decoratedAssignment.setSourceLoopVarName( sourceLoopVarName );
}
@Override @Override
public String getSourceParameterName() { public String getSourceParameterName() {
return decoratedAssignment.getSourceParameterName(); return decoratedAssignment.getSourceParameterName();
@ -92,8 +102,8 @@ public abstract class AssignmentWrapper extends ModelElement implements Assignme
} }
@Override @Override
public String createLocalVarName( String desiredName ) { public String createUniqueVarName(String desiredName ) {
return decoratedAssignment.createLocalVarName( desiredName ); return decoratedAssignment.createUniqueVarName( desiredName );
} }
/** /**

View File

@ -34,7 +34,7 @@ public class StreamAdderWrapper extends AssignmentWrapper {
super( rhs, fieldAssignment ); super( rhs, fieldAssignment );
this.thrownTypesToExclude = thrownTypesToExclude; this.thrownTypesToExclude = thrownTypesToExclude;
String desiredName = Nouns.singularize( targetPropertyName ); String desiredName = Nouns.singularize( targetPropertyName );
rhs.setSourceLocalVarName( rhs.createLocalVarName( desiredName ) ); rhs.setSourceLocalVarName( rhs.createUniqueVarName( desiredName ) );
adderType = first( getSourceType().determineTypeArguments( Stream.class ) ); adderType = first( getSourceType().determineTypeArguments( Stream.class ) );
} }
@ -56,6 +56,18 @@ public class StreamAdderWrapper extends AssignmentWrapper {
return adderType; return adderType;
} }
public boolean isIncludeSourceNullCheck() {
return true;
}
public boolean isSetExplicitlyToNull() {
return false;
}
public boolean isSetExplicitlyToDefault() {
return false;
}
@Override @Override
public Set<Type> getImportTypes() { public Set<Type> getImportTypes() {
Set<Type> imported = new HashSet<>(); Set<Type> imported = new HashSet<>();

View File

@ -37,7 +37,7 @@ public class WrapperForCollectionsAndMaps extends AssignmentWrapper {
else { else {
this.nullCheckLocalVarType = targetType; this.nullCheckLocalVarType = targetType;
} }
this.nullCheckLocalVarName = rhs.createLocalVarName( nullCheckLocalVarType.getName() ); this.nullCheckLocalVarName = rhs.createUniqueVarName( nullCheckLocalVarType.getName() );
} }
@Override @Override

View File

@ -106,7 +106,7 @@ public interface Assignment {
* *
* @return the desired name, made unique in the scope of the bean mapping. * @return the desired name, made unique in the scope of the bean mapping.
*/ */
String createLocalVarName( String desiredName ); String createUniqueVarName(String desiredName );
/** /**
* See {@link #setSourceLocalVarName(java.lang.String) } * See {@link #setSourceLocalVarName(java.lang.String) }
@ -131,6 +131,23 @@ public interface Assignment {
*/ */
void setSourceLocalVarName(String sourceLocalVarName); void setSourceLocalVarName(String sourceLocalVarName);
/**
* See {@link #getSourceLoopVarName()} (java.lang.String) }
*
* @return loop variable (can be null if not set)
*/
String getSourceLoopVarName();
/**
* Replaces the sourceLocalVar or sourceReference at the call site in the assignment in the template with this
* sourceLoopVarName.
* The sourceLocalVar can subsequently be used for e.g. null checking.
*
* @param sourceLoopVarName loop variable
*/
void setSourceLoopVarName(String sourceLoopVarName);
/** /**
* Returns whether the type of assignment * Returns whether the type of assignment
* *

View File

@ -27,6 +27,7 @@ public class SourceRHS extends ModelElement implements Assignment {
private final String sourceReference; private final String sourceReference;
private final Type sourceType; private final Type sourceType;
private String sourceLocalVarName; private String sourceLocalVarName;
private String sourceLoopVarName;
private final Set<String> existingVariableNames; private final Set<String> existingVariableNames;
private final String sourceErrorMessagePart; private final String sourceErrorMessagePart;
private final String sourcePresenceCheckerReference; private final String sourcePresenceCheckerReference;
@ -69,7 +70,7 @@ public class SourceRHS extends ModelElement implements Assignment {
} }
@Override @Override
public String createLocalVarName(String desiredName) { public String createUniqueVarName(String desiredName) {
String result = Strings.getSafeVariableName( desiredName, existingVariableNames ); String result = Strings.getSafeVariableName( desiredName, existingVariableNames );
existingVariableNames.add( result ); existingVariableNames.add( result );
return result; return result;
@ -85,6 +86,14 @@ public class SourceRHS extends ModelElement implements Assignment {
this.sourceLocalVarName = sourceLocalVarName; this.sourceLocalVarName = sourceLocalVarName;
} }
public String getSourceLoopVarName() {
return sourceLoopVarName;
}
public void setSourceLoopVarName(String sourceLoopVarName) {
this.sourceLoopVarName = sourceLoopVarName;
}
@Override @Override
public Set<Type> getImportTypes() { public Set<Type> getImportTypes() {
return Collections.emptySet(); return Collections.emptySet();

View File

@ -8,9 +8,10 @@
<#-- @ftlvariable name="" type="org.mapstruct.ap.internal.model.assignment.AdderWrapper" --> <#-- @ftlvariable name="" type="org.mapstruct.ap.internal.model.assignment.AdderWrapper" -->
<#import "../macro/CommonMacros.ftl" as lib> <#import "../macro/CommonMacros.ftl" as lib>
<@lib.handleExceptions> <@lib.handleExceptions>
if ( ${sourceReference} != null ) { <@lib.sourceLocalVarAssignment/>
for ( <@includeModel object=adderType.typeBound/> ${sourceLocalVarName} : ${sourceReference} ) { <@lib.handleSourceReferenceNullCheck>
for ( <@includeModel object=adderType.typeBound/> ${sourceLoopVarName} : <#if sourceLocalVarName??>${sourceLocalVarName}<#else>${sourceReference}</#if> ) {
${ext.targetBeanName}.${ext.targetWriteAccessorName}<@lib.handleWrite><@lib.handleAssignment/></@lib.handleWrite>; ${ext.targetBeanName}.${ext.targetWriteAccessorName}<@lib.handleWrite><@lib.handleAssignment/></@lib.handleWrite>;
} }
} </@lib.handleSourceReferenceNullCheck>
</@lib.handleExceptions> </@lib.handleExceptions>

View File

@ -8,7 +8,8 @@
<#-- @ftlvariable name="" type="org.mapstruct.ap.internal.model.assignment.StreamAdderWrapper" --> <#-- @ftlvariable name="" type="org.mapstruct.ap.internal.model.assignment.StreamAdderWrapper" -->
<#import "../macro/CommonMacros.ftl" as lib> <#import "../macro/CommonMacros.ftl" as lib>
<@lib.handleExceptions> <@lib.handleExceptions>
if ( ${sourceReference} != null ) { <@lib.sourceLocalVarAssignment/>
${sourceReference}.forEach( ${ext.targetBeanName}::${ext.targetWriteAccessorName} ); <@lib.handleSourceReferenceNullCheck>
} <#if sourceLocalVarName??>${sourceLocalVarName}<#else>${sourceReference}</#if>.forEach( ${ext.targetBeanName}::${ext.targetWriteAccessorName} );
</@lib.handleSourceReferenceNullCheck>
</@lib.handleExceptions> </@lib.handleExceptions>

View File

@ -6,4 +6,4 @@
--> -->
<#-- @ftlvariable name="" type="org.mapstruct.ap.internal.model.common.SourceRHS" --> <#-- @ftlvariable name="" type="org.mapstruct.ap.internal.model.common.SourceRHS" -->
<#if sourceLocalVarName??>${sourceLocalVarName}<#else>${sourceReference}</#if> <#if sourceLoopVarName??>${sourceLoopVarName}<#elseif sourceLocalVarName??>${sourceLocalVarName}<#else>${sourceReference}</#if>

View File

@ -3,10 +3,12 @@
* *
* Licensed under the Apache License version 2.0, available at http://www.apache.org/licenses/LICENSE-2.0 * Licensed under the Apache License version 2.0, available at http://www.apache.org/licenses/LICENSE-2.0
*/ */
package org.mapstruct.ap.test.bugs._1561.java8; package org.mapstruct.ap.test.bugs._1561;
import org.mapstruct.CollectionMappingStrategy; import org.mapstruct.CollectionMappingStrategy;
import org.mapstruct.InheritInverseConfiguration;
import org.mapstruct.Mapper; import org.mapstruct.Mapper;
import org.mapstruct.Mapping;
import org.mapstruct.factory.Mappers; import org.mapstruct.factory.Mappers;
/** /**
@ -18,7 +20,9 @@ public interface Issue1561Mapper {
Issue1561Mapper Issue1561Mapper
INSTANCE = Mappers.getMapper( Issue1561Mapper.class ); INSTANCE = Mappers.getMapper( Issue1561Mapper.class );
@Mapping( target = "nestedTarget.properties", source = "properties")
Target map(Source source); Target map(Source source);
@InheritInverseConfiguration
Source map(Target target); Source map(Target target);
} }

View File

@ -3,13 +3,15 @@
* *
* Licensed under the Apache License version 2.0, available at http://www.apache.org/licenses/LICENSE-2.0 * Licensed under the Apache License version 2.0, available at http://www.apache.org/licenses/LICENSE-2.0
*/ */
package org.mapstruct.ap.test.bugs._1561.java8; package org.mapstruct.ap.test.bugs._1561;
import org.junit.Rule;
import org.junit.Test; import org.junit.Test;
import org.junit.runner.RunWith; import org.junit.runner.RunWith;
import org.mapstruct.ap.testutil.IssueKey; import org.mapstruct.ap.testutil.IssueKey;
import org.mapstruct.ap.testutil.WithClasses; import org.mapstruct.ap.testutil.WithClasses;
import org.mapstruct.ap.testutil.runner.AnnotationProcessorTestRunner; import org.mapstruct.ap.testutil.runner.AnnotationProcessorTestRunner;
import org.mapstruct.ap.testutil.runner.GeneratedSource;
import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThat;
@ -21,10 +23,16 @@ import static org.assertj.core.api.Assertions.assertThat;
@WithClasses({ @WithClasses({
Issue1561Mapper.class, Issue1561Mapper.class,
Source.class, Source.class,
Target.class Target.class,
NestedTarget.class
}) })
public class Issue1561Test { public class Issue1561Test {
@Rule
public final GeneratedSource generatedSource = new GeneratedSource().addComparisonToFixtureFor(
Issue1561Mapper.class
);
@Test @Test
public void shouldCorrectlyUseAdder() { public void shouldCorrectlyUseAdder() {
@ -34,12 +42,10 @@ public class Issue1561Test {
Target target = Issue1561Mapper.INSTANCE.map( source ); Target target = Issue1561Mapper.INSTANCE.map( source );
assertThat( target.getProperties() ) assertThat( target.getNestedTarget().getProperties() ).containsExactly( "first", "second" );
.containsExactly( "first", "second" );
Source mapped = Issue1561Mapper.INSTANCE.map( target ); Source mapped = Issue1561Mapper.INSTANCE.map( target );
assertThat( mapped.getProperties() ) assertThat( mapped.getProperties() ).containsExactly( "first", "second" );
.containsExactly( "first", "second" );
} }
} }

View File

@ -3,7 +3,7 @@
* *
* Licensed under the Apache License version 2.0, available at http://www.apache.org/licenses/LICENSE-2.0 * Licensed under the Apache License version 2.0, available at http://www.apache.org/licenses/LICENSE-2.0
*/ */
package org.mapstruct.ap.test.bugs._1561.java8; package org.mapstruct.ap.test.bugs._1561;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
@ -12,7 +12,7 @@ import java.util.stream.Stream;
/** /**
* @author Sebastian Haberey * @author Sebastian Haberey
*/ */
public class Target { public class NestedTarget {
private List<String> properties = new ArrayList<String>(); private List<String> properties = new ArrayList<String>();

View File

@ -3,7 +3,7 @@
* *
* Licensed under the Apache License version 2.0, available at http://www.apache.org/licenses/LICENSE-2.0 * Licensed under the Apache License version 2.0, available at http://www.apache.org/licenses/LICENSE-2.0
*/ */
package org.mapstruct.ap.test.bugs._1561.java8; package org.mapstruct.ap.test.bugs._1561;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;

View File

@ -0,0 +1,19 @@
/*
* Copyright MapStruct Authors.
*
* Licensed under the Apache License version 2.0, available at http://www.apache.org/licenses/LICENSE-2.0
*/
package org.mapstruct.ap.test.bugs._1561;
public class Target {
private NestedTarget nestedTarget;
public NestedTarget getNestedTarget() {
return nestedTarget;
}
public void setNestedTarget(NestedTarget nestedTarget) {
this.nestedTarget = nestedTarget;
}
}

View File

@ -0,0 +1,77 @@
/*
* Copyright MapStruct Authors.
*
* Licensed under the Apache License version 2.0, available at http://www.apache.org/licenses/LICENSE-2.0
*/
package org.mapstruct.ap.test.bugs._1561;
import java.util.stream.Stream;
import javax.annotation.Generated;
@Generated(
value = "org.mapstruct.ap.MappingProcessor",
date = "2019-01-29T19:40:52+0100",
comments = "version: , compiler: javac, environment: Java 1.8.0_181 (Oracle Corporation)"
)
public class Issue1561MapperImpl implements Issue1561Mapper {
@Override
public Target map(Source source) {
if ( source == null ) {
return null;
}
Target target = new Target();
target.setNestedTarget( sourceToNestedTarget( source ) );
return target;
}
@Override
public Source map(Target target) {
if ( target == null ) {
return null;
}
Source source = new Source();
Stream<String> nestedTargetProperty = targetNestedTargetProperties( target );
if ( nestedTargetProperty != null ) {
nestedTargetProperty.forEach( source::addProperty );
}
return source;
}
protected NestedTarget sourceToNestedTarget(Source source) {
if ( source == null ) {
return null;
}
NestedTarget nestedTarget = new NestedTarget();
if ( source.getProperties() != null ) {
for ( String property : source.getProperties() ) {
nestedTarget.addProperty( property );
}
}
return nestedTarget;
}
private Stream<String> targetNestedTargetProperties(Target target) {
if ( target == null ) {
return null;
}
NestedTarget nestedTarget = target.getNestedTarget();
if ( nestedTarget == null ) {
return null;
}
Stream<String> properties = nestedTarget.getProperties();
if ( properties == null ) {
return null;
}
return properties;
}
}

View File

@ -12,8 +12,8 @@ import javax.annotation.Generated;
@Generated( @Generated(
value = "org.mapstruct.ap.MappingProcessor", value = "org.mapstruct.ap.MappingProcessor",
date = "2019-01-28T21:17:39+0100", date = "2019-01-27T12:40:32+0100",
comments = "version: , compiler: javac, environment: Java 1.8.0_181 (Oracle Corporation)" comments = "version: , compiler: Eclipse JDT (Batch) 1.2.100.v20160418-1457, environment: Java 1.8.0_181 (Oracle Corporation)"
) )
public class UserMapperImpl implements UserMapper { public class UserMapperImpl implements UserMapper {
@ -44,8 +44,9 @@ public class UserMapperImpl implements UserMapper {
else { else {
user.setSettings( null ); user.setSettings( null );
} }
if ( userDTOContactDataDTOPreferences( userDTO ) != null ) { List<String> preferences = userDTOContactDataDTOPreferences( userDTO );
for ( String contactDataDTOPreference : userDTOContactDataDTOPreferences( userDTO ) ) { if ( preferences != null ) {
for ( String contactDataDTOPreference : preferences ) {
user.addPreference( contactDataDTOPreference ); user.addPreference( contactDataDTOPreference );
} }
} }
@ -71,8 +72,9 @@ public class UserMapperImpl implements UserMapper {
if ( settings1 != null ) { if ( settings1 != null ) {
user.setSettings( Arrays.copyOf( settings1, settings1.length ) ); user.setSettings( Arrays.copyOf( settings1, settings1.length ) );
} }
if ( userDTOContactDataDTOPreferences( userDTO ) != null ) { List<String> preferences = userDTOContactDataDTOPreferences( userDTO );
for ( String contactDataDTOPreference : userDTOContactDataDTOPreferences( userDTO ) ) { if ( preferences != null ) {
for ( String contactDataDTOPreference : preferences ) {
user.addPreference( contactDataDTOPreference ); user.addPreference( contactDataDTOPreference );
} }
} }
@ -106,8 +108,9 @@ public class UserMapperImpl implements UserMapper {
else { else {
user.setSettings( new String[0] ); user.setSettings( new String[0] );
} }
if ( userDTOContactDataDTOPreferences( userDTO ) != null ) { List<String> preferences = userDTOContactDataDTOPreferences( userDTO );
for ( String contactDataDTOPreference : userDTOContactDataDTOPreferences( userDTO ) ) { if ( preferences != null ) {
for ( String contactDataDTOPreference : preferences ) {
user.addPreference( contactDataDTOPreference ); user.addPreference( contactDataDTOPreference );
} }
} }