Refactor presence checks to object in order to simplify the conditional mapping

This commit is contained in:
Filip Hrisafov 2021-03-27 18:38:41 +01:00
parent 1c8fff1475
commit a2e1404b93
16 changed files with 309 additions and 29 deletions

View File

@ -19,6 +19,7 @@ import org.mapstruct.ap.internal.model.common.ConversionContext;
import org.mapstruct.ap.internal.model.common.ModelElement; import org.mapstruct.ap.internal.model.common.ModelElement;
import org.mapstruct.ap.internal.model.common.Parameter; import org.mapstruct.ap.internal.model.common.Parameter;
import org.mapstruct.ap.internal.model.common.ParameterBinding; import org.mapstruct.ap.internal.model.common.ParameterBinding;
import org.mapstruct.ap.internal.model.common.PresenceCheck;
import org.mapstruct.ap.internal.model.common.Type; import org.mapstruct.ap.internal.model.common.Type;
import org.mapstruct.ap.internal.model.source.Method; import org.mapstruct.ap.internal.model.source.Method;
import org.mapstruct.ap.internal.model.source.builtin.BuiltInMethod; import org.mapstruct.ap.internal.model.source.builtin.BuiltInMethod;
@ -197,7 +198,7 @@ public class MethodReference extends ModelElement implements Assignment {
} }
@Override @Override
public String getSourcePresenceCheckerReference() { public PresenceCheck getSourcePresenceCheckerReference() {
return assignment.getSourcePresenceCheckerReference(); return assignment.getSourcePresenceCheckerReference();
} }

View File

@ -11,8 +11,10 @@ import java.util.Objects;
import java.util.Set; import java.util.Set;
import org.mapstruct.ap.internal.model.common.Parameter; import org.mapstruct.ap.internal.model.common.Parameter;
import org.mapstruct.ap.internal.model.common.PresenceCheck;
import org.mapstruct.ap.internal.model.common.Type; import org.mapstruct.ap.internal.model.common.Type;
import org.mapstruct.ap.internal.model.beanmapping.PropertyEntry; import org.mapstruct.ap.internal.model.beanmapping.PropertyEntry;
import org.mapstruct.ap.internal.model.presence.SourceReferenceMethodPresenceCheck;
import org.mapstruct.ap.internal.util.Strings; import org.mapstruct.ap.internal.util.Strings;
import org.mapstruct.ap.internal.util.ValueProvider; import org.mapstruct.ap.internal.util.ValueProvider;
@ -52,17 +54,27 @@ public class NestedPropertyMappingMethod extends MappingMethod {
public NestedPropertyMappingMethod build() { public NestedPropertyMappingMethod build() {
List<String> existingVariableNames = new ArrayList<>(); List<String> existingVariableNames = new ArrayList<>();
Parameter sourceParameter = null;
for ( Parameter parameter : method.getSourceParameters() ) { for ( Parameter parameter : method.getSourceParameters() ) {
existingVariableNames.add( parameter.getName() ); existingVariableNames.add( parameter.getName() );
if ( sourceParameter == null && !parameter.isMappingTarget() && !parameter.isMappingContext() ) {
sourceParameter = parameter;
}
} }
final List<Type> thrownTypes = new ArrayList<>(); final List<Type> thrownTypes = new ArrayList<>();
List<SafePropertyEntry> safePropertyEntries = new ArrayList<>(); List<SafePropertyEntry> safePropertyEntries = new ArrayList<>();
if ( sourceParameter == null ) {
throw new IllegalStateException( "Method " + method + " has no source parameter." );
}
String previousPropertyName = sourceParameter.getName();
for ( PropertyEntry propertyEntry : propertyEntries ) { for ( PropertyEntry propertyEntry : propertyEntries ) {
String safeName = Strings.getSafeVariableName( propertyEntry.getName(), existingVariableNames ); String safeName = Strings.getSafeVariableName( propertyEntry.getName(), existingVariableNames );
safePropertyEntries.add( new SafePropertyEntry( propertyEntry, safeName ) ); safePropertyEntries.add( new SafePropertyEntry( propertyEntry, safeName, previousPropertyName ) );
existingVariableNames.add( safeName ); existingVariableNames.add( safeName );
thrownTypes.addAll( ctx.getTypeFactory().getThrownTypes( thrownTypes.addAll( ctx.getTypeFactory().getThrownTypes(
propertyEntry.getReadAccessor() ) ); propertyEntry.getReadAccessor() ) );
previousPropertyName = safeName;
} }
method.addThrownTypes( thrownTypes ); method.addThrownTypes( thrownTypes );
return new NestedPropertyMappingMethod( method, safePropertyEntries ); return new NestedPropertyMappingMethod( method, safePropertyEntries );
@ -92,6 +104,9 @@ public class NestedPropertyMappingMethod extends MappingMethod {
Set<Type> types = super.getImportTypes(); Set<Type> types = super.getImportTypes();
for ( SafePropertyEntry propertyEntry : safePropertyEntries) { for ( SafePropertyEntry propertyEntry : safePropertyEntries) {
types.add( propertyEntry.getType() ); types.add( propertyEntry.getType() );
if ( propertyEntry.getPresenceChecker() != null ) {
types.addAll( propertyEntry.getPresenceChecker().getImportTypes() );
}
} }
return types; return types;
} }
@ -143,18 +158,23 @@ public class NestedPropertyMappingMethod extends MappingMethod {
private final String safeName; private final String safeName;
private final String readAccessorName; private final String readAccessorName;
private final String presenceCheckerName; private final PresenceCheck presenceChecker;
private final String previousPropertyName;
private final Type type; private final Type type;
public SafePropertyEntry(PropertyEntry entry, String safeName) { public SafePropertyEntry(PropertyEntry entry, String safeName, String previousPropertyName) {
this.safeName = safeName; this.safeName = safeName;
this.readAccessorName = ValueProvider.of( entry.getReadAccessor() ).getValue(); this.readAccessorName = ValueProvider.of( entry.getReadAccessor() ).getValue();
if ( entry.getPresenceChecker() != null ) { if ( entry.getPresenceChecker() != null ) {
this.presenceCheckerName = entry.getPresenceChecker().getSimpleName(); this.presenceChecker = new SourceReferenceMethodPresenceCheck(
previousPropertyName,
entry.getPresenceChecker().getSimpleName()
);
} }
else { else {
this.presenceCheckerName = null; this.presenceChecker = null;
} }
this.previousPropertyName = previousPropertyName;
this.type = entry.getType(); this.type = entry.getType();
} }
@ -166,8 +186,12 @@ public class NestedPropertyMappingMethod extends MappingMethod {
return readAccessorName; return readAccessorName;
} }
public String getPresenceCheckerName() { public PresenceCheck getPresenceChecker() {
return presenceCheckerName; return presenceChecker;
}
public String getPreviousPropertyName() {
return previousPropertyName;
} }
public Type getType() { public Type getType() {
@ -189,7 +213,11 @@ public class NestedPropertyMappingMethod extends MappingMethod {
return false; return false;
} }
if ( !Objects.equals( presenceCheckerName, that.presenceCheckerName ) ) { if ( !Objects.equals( presenceChecker, that.presenceChecker ) ) {
return false;
}
if ( !Objects.equals( previousPropertyName, that.previousPropertyName ) ) {
return false; return false;
} }
@ -203,7 +231,7 @@ public class NestedPropertyMappingMethod extends MappingMethod {
@Override @Override
public int hashCode() { public int hashCode() {
int result = readAccessorName != null ? readAccessorName.hashCode() : 0; int result = readAccessorName != null ? readAccessorName.hashCode() : 0;
result = 31 * result + ( presenceCheckerName != null ? presenceCheckerName.hashCode() : 0 ); result = 31 * result + ( presenceChecker != null ? presenceChecker.hashCode() : 0 );
result = 31 * result + ( type != null ? type.hashCode() : 0 ); result = 31 * result + ( type != null ? type.hashCode() : 0 );
return result; return result;
} }

View File

@ -28,8 +28,12 @@ import org.mapstruct.ap.internal.model.common.BuilderType;
import org.mapstruct.ap.internal.model.common.FormattingParameters; import org.mapstruct.ap.internal.model.common.FormattingParameters;
import org.mapstruct.ap.internal.model.common.ModelElement; import org.mapstruct.ap.internal.model.common.ModelElement;
import org.mapstruct.ap.internal.model.common.Parameter; import org.mapstruct.ap.internal.model.common.Parameter;
import org.mapstruct.ap.internal.model.common.PresenceCheck;
import org.mapstruct.ap.internal.model.common.SourceRHS; import org.mapstruct.ap.internal.model.common.SourceRHS;
import org.mapstruct.ap.internal.model.common.Type; import org.mapstruct.ap.internal.model.common.Type;
import org.mapstruct.ap.internal.model.presence.AllPresenceChecksPresenceCheck;
import org.mapstruct.ap.internal.model.presence.NullPresenceCheck;
import org.mapstruct.ap.internal.model.presence.SourceReferenceMethodPresenceCheck;
import org.mapstruct.ap.internal.model.source.DelegatingOptions; import org.mapstruct.ap.internal.model.source.DelegatingOptions;
import org.mapstruct.ap.internal.model.source.MappingControl; import org.mapstruct.ap.internal.model.source.MappingControl;
import org.mapstruct.ap.internal.model.source.MappingOptions; import org.mapstruct.ap.internal.model.source.MappingOptions;
@ -609,30 +613,43 @@ public class PropertyMapping extends ModelElement {
} }
} }
private String getSourcePresenceCheckerRef( SourceReference sourceReference ) { private PresenceCheck getSourcePresenceCheckerRef(SourceReference sourceReference ) {
String sourcePresenceChecker = null; PresenceCheck sourcePresenceChecker = null;
if ( !sourceReference.getPropertyEntries().isEmpty() ) { if ( !sourceReference.getPropertyEntries().isEmpty() ) {
Parameter sourceParam = sourceReference.getParameter(); Parameter sourceParam = sourceReference.getParameter();
// TODO is first correct here?? shouldn't it be last since the remainer is checked // TODO is first correct here?? shouldn't it be last since the remainer is checked
// in the forged method? // in the forged method?
PropertyEntry propertyEntry = sourceReference.getShallowestProperty(); PropertyEntry propertyEntry = sourceReference.getShallowestProperty();
if ( propertyEntry.getPresenceChecker() != null ) { if ( propertyEntry.getPresenceChecker() != null ) {
sourcePresenceChecker = sourceParam.getName() List<PresenceCheck> presenceChecks = new ArrayList<>();
+ "." + propertyEntry.getPresenceChecker().getSimpleName() + "()"; presenceChecks.add( new SourceReferenceMethodPresenceCheck(
sourceParam.getName(),
propertyEntry.getPresenceChecker().getSimpleName()
) );
String variableName = sourceParam.getName() + "." String variableName = sourceParam.getName() + "."
+ propertyEntry.getReadAccessor().getSimpleName() + "()"; + propertyEntry.getReadAccessor().getSimpleName() + "()";
for (int i = 1; i < sourceReference.getPropertyEntries().size(); i++) { for (int i = 1; i < sourceReference.getPropertyEntries().size(); i++) {
PropertyEntry entry = sourceReference.getPropertyEntries().get( i ); PropertyEntry entry = sourceReference.getPropertyEntries().get( i );
if (entry.getPresenceChecker() != null && entry.getReadAccessor() != null) { if (entry.getPresenceChecker() != null && entry.getReadAccessor() != null) {
sourcePresenceChecker += " && " + variableName + " != null && " presenceChecks.add( new NullPresenceCheck( variableName ) );
+ variableName + "." + entry.getPresenceChecker().getSimpleName() + "()"; presenceChecks.add( new SourceReferenceMethodPresenceCheck(
variableName,
entry.getPresenceChecker().getSimpleName()
) );
variableName = variableName + "." + entry.getReadAccessor().getSimpleName() + "()"; variableName = variableName + "." + entry.getReadAccessor().getSimpleName() + "()";
} }
else { else {
break; break;
} }
} }
if ( presenceChecks.size() == 1 ) {
sourcePresenceChecker = presenceChecks.get( 0 );
}
else {
sourcePresenceChecker = new AllPresenceChecksPresenceCheck( presenceChecks );
}
} }
} }
return sourcePresenceChecker; return sourcePresenceChecker;

View File

@ -11,6 +11,7 @@ import java.util.Set;
import org.mapstruct.ap.internal.model.common.Assignment; import org.mapstruct.ap.internal.model.common.Assignment;
import org.mapstruct.ap.internal.model.common.ModelElement; import org.mapstruct.ap.internal.model.common.ModelElement;
import org.mapstruct.ap.internal.model.common.PresenceCheck;
import org.mapstruct.ap.internal.model.common.Type; import org.mapstruct.ap.internal.model.common.Type;
/** /**
@ -79,7 +80,7 @@ public class TypeConversion extends ModelElement implements Assignment {
} }
@Override @Override
public String getSourcePresenceCheckerReference() { public PresenceCheck getSourcePresenceCheckerReference() {
return assignment.getSourcePresenceCheckerReference(); return assignment.getSourcePresenceCheckerReference();
} }

View File

@ -10,6 +10,7 @@ import java.util.Set;
import org.mapstruct.ap.internal.model.common.Assignment; import org.mapstruct.ap.internal.model.common.Assignment;
import org.mapstruct.ap.internal.model.common.ModelElement; import org.mapstruct.ap.internal.model.common.ModelElement;
import org.mapstruct.ap.internal.model.common.PresenceCheck;
import org.mapstruct.ap.internal.model.common.Type; import org.mapstruct.ap.internal.model.common.Type;
/** /**
@ -57,7 +58,7 @@ public abstract class AssignmentWrapper extends ModelElement implements Assignme
} }
@Override @Override
public String getSourcePresenceCheckerReference() { public PresenceCheck getSourcePresenceCheckerReference() {
return decoratedAssignment.getSourcePresenceCheckerReference(); return decoratedAssignment.getSourcePresenceCheckerReference();
} }

View File

@ -90,7 +90,7 @@ public interface Assignment {
* *
* @return source reference * @return source reference
*/ */
String getSourcePresenceCheckerReference(); PresenceCheck getSourcePresenceCheckerReference();
/** /**
* the source type used in the matching process * the source type used in the matching process

View File

@ -0,0 +1,24 @@
/*
* 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.internal.model.common;
import java.util.Set;
/**
* Marker interface for presence checks.
*
* @author Filip Hrisafov
*/
public interface PresenceCheck {
/**
* returns all types required as import by the presence check.
*
* @return imported types
*/
Set<Type> getImportTypes();
}

View File

@ -7,6 +7,7 @@ package org.mapstruct.ap.internal.model.common;
import java.util.Collection; import java.util.Collection;
import java.util.Collections; import java.util.Collections;
import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.Set; import java.util.Set;
import java.util.stream.Stream; import java.util.stream.Stream;
@ -30,7 +31,7 @@ public class SourceRHS extends ModelElement implements Assignment {
private String sourceLoopVarName; 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 PresenceCheck sourcePresenceCheckerReference;
private boolean useElementAsSourceTypeForMatching = false; private boolean useElementAsSourceTypeForMatching = false;
private final String sourceParameterName; private final String sourceParameterName;
@ -39,7 +40,7 @@ public class SourceRHS extends ModelElement implements Assignment {
this( sourceReference, sourceReference, null, sourceType, existingVariableNames, sourceErrorMessagePart ); this( sourceReference, sourceReference, null, sourceType, existingVariableNames, sourceErrorMessagePart );
} }
public SourceRHS(String sourceParameterName, String sourceReference, String sourcePresenceCheckerReference, public SourceRHS(String sourceParameterName, String sourceReference, PresenceCheck sourcePresenceCheckerReference,
Type sourceType, Set<String> existingVariableNames, String sourceErrorMessagePart ) { Type sourceType, Set<String> existingVariableNames, String sourceErrorMessagePart ) {
this.sourceReference = sourceReference; this.sourceReference = sourceReference;
this.sourceType = sourceType; this.sourceType = sourceType;
@ -60,7 +61,7 @@ public class SourceRHS extends ModelElement implements Assignment {
} }
@Override @Override
public String getSourcePresenceCheckerReference() { public PresenceCheck getSourcePresenceCheckerReference() {
return sourcePresenceCheckerReference; return sourcePresenceCheckerReference;
} }
@ -96,6 +97,10 @@ public class SourceRHS extends ModelElement implements Assignment {
@Override @Override
public Set<Type> getImportTypes() { public Set<Type> getImportTypes() {
if ( sourcePresenceCheckerReference != null ) {
return sourcePresenceCheckerReference.getImportTypes();
}
return Collections.emptySet(); return Collections.emptySet();
} }

View File

@ -0,0 +1,59 @@
/*
* 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.internal.model.presence;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.Objects;
import java.util.Set;
import org.mapstruct.ap.internal.model.common.ModelElement;
import org.mapstruct.ap.internal.model.common.PresenceCheck;
import org.mapstruct.ap.internal.model.common.Type;
/**
* @author Filip Hrisafov
*/
public class AllPresenceChecksPresenceCheck extends ModelElement implements PresenceCheck {
private final Collection<PresenceCheck> presenceChecks;
public AllPresenceChecksPresenceCheck(Collection<PresenceCheck> presenceChecks) {
this.presenceChecks = presenceChecks;
}
public Collection<PresenceCheck> getPresenceChecks() {
return presenceChecks;
}
@Override
public Set<Type> getImportTypes() {
Set<Type> importTypes = new HashSet<>();
for ( PresenceCheck presenceCheck : presenceChecks ) {
importTypes.addAll( presenceCheck.getImportTypes() );
}
return importTypes;
}
@Override
public boolean equals(Object o) {
if ( this == o ) {
return true;
}
if ( o == null || getClass() != o.getClass() ) {
return false;
}
AllPresenceChecksPresenceCheck that = (AllPresenceChecksPresenceCheck) o;
return Objects.equals( presenceChecks, that.presenceChecks );
}
@Override
public int hashCode() {
return Objects.hash( presenceChecks );
}
}

View File

@ -0,0 +1,52 @@
/*
* 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.internal.model.presence;
import java.util.Collections;
import java.util.Objects;
import java.util.Set;
import org.mapstruct.ap.internal.model.common.ModelElement;
import org.mapstruct.ap.internal.model.common.PresenceCheck;
import org.mapstruct.ap.internal.model.common.Type;
/**
* @author Filip Hrisafov
*/
public class NullPresenceCheck extends ModelElement implements PresenceCheck {
private final String sourceReference;
public NullPresenceCheck(String sourceReference) {
this.sourceReference = sourceReference;
}
public String getSourceReference() {
return sourceReference;
}
@Override
public Set<Type> getImportTypes() {
return Collections.emptySet();
}
@Override
public boolean equals(Object o) {
if ( this == o ) {
return true;
}
if ( o == null || getClass() != o.getClass() ) {
return false;
}
NullPresenceCheck that = (NullPresenceCheck) o;
return Objects.equals( sourceReference, that.sourceReference );
}
@Override
public int hashCode() {
return Objects.hash( sourceReference );
}
}

View File

@ -0,0 +1,59 @@
/*
* 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.internal.model.presence;
import java.util.Collections;
import java.util.Objects;
import java.util.Set;
import org.mapstruct.ap.internal.model.common.ModelElement;
import org.mapstruct.ap.internal.model.common.PresenceCheck;
import org.mapstruct.ap.internal.model.common.Type;
/**
* @author Filip Hrisafov
*/
public class SourceReferenceMethodPresenceCheck extends ModelElement implements PresenceCheck {
private final String sourceReference;
private final String methodName;
public SourceReferenceMethodPresenceCheck(String sourceReference, String methodName) {
this.sourceReference = sourceReference;
this.methodName = methodName;
}
public String getSourceReference() {
return sourceReference;
}
public String getMethodName() {
return methodName;
}
@Override
public Set<Type> getImportTypes() {
return Collections.emptySet();
}
@Override
public boolean equals(Object o) {
if ( this == o ) {
return true;
}
if ( o == null || getClass() != o.getClass() ) {
return false;
}
SourceReferenceMethodPresenceCheck that = (SourceReferenceMethodPresenceCheck) o;
return Objects.equals( sourceReference, that.sourceReference ) &&
Objects.equals( methodName, that.methodName );
}
@Override
public int hashCode() {
return Objects.hash( sourceReference, methodName );
}
}

View File

@ -11,13 +11,13 @@
return ${returnType.null}; return ${returnType.null};
} }
<#list propertyEntries as entry> <#list propertyEntries as entry>
<#if entry.presenceCheckerName?? > <#if entry.presenceChecker?? >
if ( <#if entry_index != 0><@localVarName index=entry_index/> == null || </#if>!<@localVarName index=entry_index/>.${entry.presenceCheckerName}() ) { if ( <#if entry_index != 0>${entry.previousPropertyName} == null || </#if>!<@includeModel object=entry.presenceChecker /> ) {
return ${returnType.null}; return ${returnType.null};
} }
</#if> </#if>
<@includeModel object=entry.type.typeBound/> ${entry.name} = <@localVarName index=entry_index/>.${entry.accessorName}; <@includeModel object=entry.type.typeBound/> ${entry.name} = ${entry.previousPropertyName}.${entry.accessorName};
<#if !entry.presenceCheckerName?? > <#if !entry.presenceChecker?? >
<#if !entry.type.primitive> <#if !entry.type.primitive>
if ( ${entry.name} == null ) { if ( ${entry.name} == null ) {
return ${returnType.null}; return ${returnType.null};
@ -29,7 +29,6 @@
</#if> </#if>
</#list> </#list>
} }
<#macro localVarName index><#if index == 0>${sourceParameter.name}<#else>${propertyEntries[index-1].name}</#if></#macro>
<#macro throws> <#macro throws>
<#if (thrownTypes?size > 0)><#lt> throws </#if><@compress single_line=true> <#if (thrownTypes?size > 0)><#lt> throws </#if><@compress single_line=true>
<#list thrownTypes as exceptionType> <#list thrownTypes as exceptionType>

View File

@ -15,7 +15,7 @@
--> -->
<#macro handleSourceReferenceNullCheck> <#macro handleSourceReferenceNullCheck>
<#if sourcePresenceCheckerReference??> <#if sourcePresenceCheckerReference??>
if ( ${sourcePresenceCheckerReference} ) { if ( <@includeModel object=sourcePresenceCheckerReference /> ) {
<#nested> <#nested>
} }
<@elseDefaultAssignment/> <@elseDefaultAssignment/>
@ -57,7 +57,7 @@
--> -->
<#macro handleLocalVarNullCheck needs_explicit_local_var> <#macro handleLocalVarNullCheck needs_explicit_local_var>
<#if sourcePresenceCheckerReference??> <#if sourcePresenceCheckerReference??>
if ( ${sourcePresenceCheckerReference} ) { if ( <@includeModel object=sourcePresenceCheckerReference /> ) {
<#if needs_explicit_local_var> <#if needs_explicit_local_var>
<@includeModel object=nullCheckLocalVarType/> ${nullCheckLocalVarName} = <@lib.handleAssignment/>; <@includeModel object=nullCheckLocalVarType/> ${nullCheckLocalVarName} = <@lib.handleAssignment/>;
<#nested> <#nested>

View File

@ -0,0 +1,16 @@
<#--
Copyright MapStruct Authors.
Licensed under the Apache License version 2.0, available at http://www.apache.org/licenses/LICENSE-2.0
-->
<#-- @ftlvariable name="" type="org.mapstruct.ap.internal.model.presence.AllPresenceChecksPresenceCheck" -->
<@compress single_line=true>
<#list presenceChecks as presenceCheck>
<#if presenceCheck_index != 0>
&&
</#if>
<@includeModel object=presenceCheck />
</#list>
</@compress>

View File

@ -0,0 +1,9 @@
<#--
Copyright MapStruct Authors.
Licensed under the Apache License version 2.0, available at http://www.apache.org/licenses/LICENSE-2.0
-->
<#-- @ftlvariable name="" type="org.mapstruct.ap.internal.model.presence.NullPresenceCheck" -->
${sourceReference} != null

View File

@ -0,0 +1,9 @@
<#--
Copyright MapStruct Authors.
Licensed under the Apache License version 2.0, available at http://www.apache.org/licenses/LICENSE-2.0
-->
<#-- @ftlvariable name="" type="org.mapstruct.ap.internal.model.presence.SourceReferenceMethodPresenceCheck" -->
${sourceReference}.${methodName}()