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 @@ -46,11 +46,13 @@
import org.mapstruct.ap.internal.model.common.FormattingParameters;
import org.mapstruct.ap.internal.model.common.Parameter;
import org.mapstruct.ap.internal.model.common.ParameterBinding;
import org.mapstruct.ap.internal.model.common.PresenceCheck;
import org.mapstruct.ap.internal.model.common.SourceRHS;
import org.mapstruct.ap.internal.model.common.Type;
import org.mapstruct.ap.internal.model.common.TypeFactory;
import org.mapstruct.ap.internal.model.dependency.GraphAnalyzer;
import org.mapstruct.ap.internal.model.dependency.GraphAnalyzer.GraphAnalyzerBuilder;
import org.mapstruct.ap.internal.model.presence.NullPresenceCheck;
import org.mapstruct.ap.internal.model.source.BeanMappingOptions;
import org.mapstruct.ap.internal.model.source.MappingOptions;
import org.mapstruct.ap.internal.model.source.Method;
Expand Down Expand Up @@ -88,6 +90,7 @@ public class BeanMappingMethod extends NormalTypeMappingMethod {
private final List<PropertyMapping> propertyMappings;
private final Map<String, List<PropertyMapping>> mappingsByParameter;
private final Map<String, List<PropertyMapping>> constructorMappingsByParameter;
private final Map<String, PresenceCheck> presenceChecksByParameter;
private final List<PropertyMapping> constantMappings;
private final List<PropertyMapping> constructorConstantMappings;
private final List<SubclassMapping> subclassMappings;
Expand Down Expand Up @@ -1871,11 +1874,19 @@ private BeanMappingMethod(Method method,
// parameter mapping.
this.mappingsByParameter = new HashMap<>();
this.constantMappings = new ArrayList<>( propertyMappings.size() );
this.presenceChecksByParameter = new LinkedHashMap<>();
this.constructorMappingsByParameter = new LinkedHashMap<>();
this.constructorConstantMappings = new ArrayList<>();
Set<String> sourceParameterNames = getSourceParameters().stream()
.map( Parameter::getName )
.collect( Collectors.toSet() );
Set<String> sourceParameterNames = new HashSet<>();
for ( Parameter sourceParameter : getSourceParameters() ) {
sourceParameterNames.add( sourceParameter.getName() );
if ( !sourceParameter.getType().isPrimitive() ) {
presenceChecksByParameter.put(
sourceParameter.getName(),
new NullPresenceCheck( sourceParameter.getName() )
);
}
}
for ( PropertyMapping mapping : propertyMappings ) {
if ( mapping.isConstructorMapping() ) {
if ( sourceParameterNames.contains( mapping.getSourceBeanName() ) ) {
Expand Down Expand Up @@ -1986,44 +1997,50 @@ public Set<Type> getImportTypes() {
return types;
}

public List<Parameter> getSourceParametersExcludingPrimitives() {
return getSourceParameters().stream()
.filter( parameter -> !parameter.getType().isPrimitive() )
.collect( Collectors.toList() );
public Collection<PresenceCheck> getSourcePresenceChecks() {
return presenceChecksByParameter.values();
}

public Map<String, PresenceCheck> getPresenceChecksByParameter() {
return presenceChecksByParameter;
}

public PresenceCheck getPresenceCheckByParameter(Parameter parameter) {
return presenceChecksByParameter.get( parameter.getName() );
}

public List<Parameter> getSourceParametersNeedingNullCheck() {
public List<Parameter> getSourceParametersNeedingPresenceCheck() {
return getSourceParameters().stream()
.filter( this::needsNullCheck )
.filter( this::needsPresenceCheck )
.collect( Collectors.toList() );
}

public List<Parameter> getSourceParametersNotNeedingNullCheck() {
public List<Parameter> getSourceParametersNotNeedingPresenceCheck() {
return getSourceParameters().stream()
.filter( parameter -> !needsNullCheck( parameter ) )
.filter( parameter -> !needsPresenceCheck( parameter ) )
.collect( Collectors.toList() );
}

private boolean needsNullCheck(Parameter parameter) {
if ( parameter.getType().isPrimitive() ) {
private boolean needsPresenceCheck(Parameter parameter) {
if ( !presenceChecksByParameter.containsKey( parameter.getName() ) ) {
return false;
}

List<PropertyMapping> mappings = propertyMappingsByParameter( parameter );
if ( mappings.size() == 1 && doesNotNeedNullCheckForSourceParameter( mappings.get( 0 ) ) ) {
if ( mappings.size() == 1 && doesNotNeedPresenceCheckForSourceParameter( mappings.get( 0 ) ) ) {
return false;
}

mappings = constructorPropertyMappingsByParameter( parameter );

if ( mappings.size() == 1 && doesNotNeedNullCheckForSourceParameter( mappings.get( 0 ) ) ) {
if ( mappings.size() == 1 && doesNotNeedPresenceCheckForSourceParameter( mappings.get( 0 ) ) ) {
return false;
}

return true;
}

private boolean doesNotNeedNullCheckForSourceParameter(PropertyMapping mapping) {
private boolean doesNotNeedPresenceCheckForSourceParameter(PropertyMapping mapping) {
if ( mapping.getAssignment().isCallingUpdateMethod() ) {
// If the mapping assignment is calling an update method then we should do a null check
// in the bean mapping
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,9 @@

import org.mapstruct.ap.internal.model.common.Assignment;
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.presence.NullPresenceCheck;
import org.mapstruct.ap.internal.model.source.Method;
import org.mapstruct.ap.internal.model.source.SelectionParameters;
import org.mapstruct.ap.internal.util.Strings;
Expand All @@ -30,6 +32,8 @@ public abstract class ContainerMappingMethod extends NormalTypeMappingMethod {
private final SelectionParameters selectionParameters;
private final String index1Name;
private final String index2Name;
private final Parameter sourceParameter;
private final PresenceCheck sourceParameterPresenceCheck;
private IterableCreation iterableCreation;

ContainerMappingMethod(Method method, List<Annotation> annotations,
Expand All @@ -45,16 +49,30 @@ public abstract class ContainerMappingMethod extends NormalTypeMappingMethod {
this.selectionParameters = selectionParameters;
this.index1Name = Strings.getSafeVariableName( "i", existingVariables );
this.index2Name = Strings.getSafeVariableName( "j", existingVariables );
}

public Parameter getSourceParameter() {
Parameter sourceParameter = null;
for ( Parameter parameter : getParameters() ) {
if ( !parameter.isMappingTarget() && !parameter.isMappingContext() ) {
return parameter;
sourceParameter = parameter;
break;
}
}

throw new IllegalStateException( "Method " + this + " has no source parameter." );
if ( sourceParameter == null ) {
throw new IllegalStateException( "Method " + this + " has no source parameter." );
}

this.sourceParameter = sourceParameter;
this.sourceParameterPresenceCheck = new NullPresenceCheck( this.sourceParameter.getName() );

}

public Parameter getSourceParameter() {
return sourceParameter;
}

public PresenceCheck getSourceParameterPresenceCheck() {
return sourceParameterPresenceCheck;
}

public IterableCreation getIterableCreation() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,10 @@
import org.mapstruct.ap.internal.model.common.Assignment;
import org.mapstruct.ap.internal.model.common.FormattingParameters;
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.Type;
import org.mapstruct.ap.internal.model.presence.NullPresenceCheck;
import org.mapstruct.ap.internal.model.source.Method;
import org.mapstruct.ap.internal.model.source.SelectionParameters;
import org.mapstruct.ap.internal.model.source.selector.SelectionCriteria;
Expand All @@ -35,6 +37,8 @@ public class MapMappingMethod extends NormalTypeMappingMethod {

private final Assignment keyAssignment;
private final Assignment valueAssignment;
private final Parameter sourceParameter;
private final PresenceCheck sourceParameterPresenceCheck;
private IterableCreation iterableCreation;

public static class Builder extends AbstractMappingMethodBuilder<Builder, MapMappingMethod> {
Expand Down Expand Up @@ -235,16 +239,28 @@ private MapMappingMethod(Method method, List<Annotation> annotations,

this.keyAssignment = keyAssignment;
this.valueAssignment = valueAssignment;
}

public Parameter getSourceParameter() {
Parameter sourceParameter = null;
for ( Parameter parameter : getParameters() ) {
if ( !parameter.isMappingTarget() && !parameter.isMappingContext() ) {
return parameter;
sourceParameter = parameter;
break;
}
}

throw new IllegalStateException( "Method " + this + " has no source parameter." );
if ( sourceParameter == null ) {
throw new IllegalStateException( "Method " + this + " has no source parameter." );
}

this.sourceParameter = sourceParameter;
this.sourceParameterPresenceCheck = new NullPresenceCheck( this.sourceParameter.getName() );
}

public Parameter getSourceParameter() {
return sourceParameter;
}

public PresenceCheck getSourceParameterPresenceCheck() {
return sourceParameterPresenceCheck;
}

public List<Type> getSourceElementTypes() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,15 @@
public class MethodReferencePresenceCheck extends ModelElement implements PresenceCheck {

protected final MethodReference methodReference;
protected final boolean negate;

public MethodReferencePresenceCheck(MethodReference methodReference) {
this( methodReference, false );
}

public MethodReferencePresenceCheck(MethodReference methodReference, boolean negate) {
this.methodReference = methodReference;
this.negate = negate;
}

@Override
Expand All @@ -32,6 +38,15 @@ public MethodReference getMethodReference() {
return methodReference;
}

public boolean isNegate() {
return negate;
}

@Override
public PresenceCheck negate() {
return new MethodReferencePresenceCheck( methodReference, true );
}

@Override
public boolean equals(Object o) {
if ( this == o ) {
Expand Down
Original file line number Diff line number Diff line change
@@ -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.common;

import java.util.Objects;
import java.util.Set;

/**
* @author Filip Hrisafov
*/
public class NegatePresenceCheck extends ModelElement implements PresenceCheck {

private final PresenceCheck presenceCheck;

public NegatePresenceCheck(PresenceCheck presenceCheck) {
this.presenceCheck = presenceCheck;
}

public PresenceCheck getPresenceCheck() {
return presenceCheck;
}

@Override
public Set<Type> getImportTypes() {
return presenceCheck.getImportTypes();
}

@Override
public PresenceCheck negate() {
return presenceCheck;
}

@Override
public boolean equals(Object o) {
if ( this == o ) {
return true;
}
if ( o == null || getClass() != o.getClass() ) {
return false;
}
NegatePresenceCheck that = (NegatePresenceCheck) o;
return Objects.equals( presenceCheck, that.presenceCheck );
}

@Override
public int hashCode() {
return Objects.hash( presenceCheck );
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -21,4 +21,6 @@ public interface PresenceCheck {
*/
Set<Type> getImportTypes();

PresenceCheck negate();

}
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
import java.util.Set;

import org.mapstruct.ap.internal.model.common.ModelElement;
import org.mapstruct.ap.internal.model.common.NegatePresenceCheck;
import org.mapstruct.ap.internal.model.common.PresenceCheck;
import org.mapstruct.ap.internal.model.common.Type;

Expand All @@ -29,6 +30,11 @@ public Collection<PresenceCheck> getPresenceChecks() {
return presenceChecks;
}

@Override
public PresenceCheck negate() {
return new NegatePresenceCheck( this );
}

@Override
public Set<Type> getImportTypes() {
Set<Type> importTypes = new HashSet<>();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
import java.util.Set;

import org.mapstruct.ap.internal.model.common.ModelElement;
import org.mapstruct.ap.internal.model.common.NegatePresenceCheck;
import org.mapstruct.ap.internal.model.common.PresenceCheck;
import org.mapstruct.ap.internal.model.common.Type;

Expand All @@ -28,6 +29,11 @@ public String getJavaExpression() {
return javaExpression;
}

@Override
public PresenceCheck negate() {
return new NegatePresenceCheck( this );
}

@Override
public Set<Type> getImportTypes() {
return Collections.emptySet();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,20 +19,36 @@
public class NullPresenceCheck extends ModelElement implements PresenceCheck {

private final String sourceReference;
private final boolean negate;

public NullPresenceCheck(String sourceReference) {
this.sourceReference = sourceReference;
this.negate = false;
}

public NullPresenceCheck(String sourceReference, boolean negate) {
this.sourceReference = sourceReference;
this.negate = negate;
}

public String getSourceReference() {
return sourceReference;
}

public boolean isNegate() {
return negate;
}

@Override
public Set<Type> getImportTypes() {
return Collections.emptySet();
}

@Override
public PresenceCheck negate() {
return new NullPresenceCheck( sourceReference, !negate );
}

@Override
public boolean equals(Object o) {
if ( this == o ) {
Expand Down
Loading