Expected behavior
If I have a method annotated with @Condition that serves as a presence check for Java Optionals, and I have a separate mapping method that unboxes an Optional, the Condition method should not be treated as a valid mapper method.
Actual behavior
Conditional method, which needs to return boolean, clashes with mapping methods that return Boolean and whose input argument type is the same, e.g.
@Condition
boolean conditionalMethod(TypeA typeAObject) { }
clashes with
@Mapper
interface MyMapper {
boolean mappingMethod(TypeA typeAObject);
}
Specifically, this is true when attempting to use a Conditional method to check the if the Boolean wrapped in an Optional isPresent, because it will return a boolean, while the mapping method that unwraps the Boolean also does this.
Steps to reproduce the problem
MapStruct 1.5.3, Spring Boot 3.1.6
import org.mapstruct.*;
import java.util.Optional;
@Mapper
interface MyMapper {
default <T> T mapFromOptional(Optional<T> value) { return value.orElse((Object) null); }
@Condition
default boolean isOptionalPresent(Optional value) { return value.isPresent(); }
MyTargetDTO map(MySourceDTO sourceDto);
}
class MySourceDTO {
private Boolean isCondition;
public Optional<Boolean> getIsCondition() { return Optional.ofNullable(this.isCondition); }
}
class MyTargetDTO {
private String isCondition;
public Optional<String> getIsCondition() { return Optional.ofNullable(this.isCondition); }
public void setIsCondition(String isCondition) { this.isCondition = isCondition; }
}
Result:
Ambiguous 2step methods found, mapping Optional sourceDto to String. Found conversionY( methodX ( parameter ) ): conversionY: Boolean -->String, method(s)X: T mapFromOptional(Optional value); conversionY: boolean-->String, method(s)X: T mapFromOptional(Optional value);
It seems to me like MapStruct is taking the @Condition method, and using it as a valid mapping method, instead of using it only for Conditional Mapping presence checking.
If I understand correctly, the mapping steps would be:
- Call the @Mapper's map, to convert the
MySourceDTO to MyTargetDTO.
- Since the getter returns an
Optional<Boolean>, it needs to call the @Mapper's mapFromOptional, for the sourceDto.isCondition property.
This will resolve the mapping as default Boolean mapFromOptional(Optional<Boolean> value), which has a similar signature as default boolean isOptionalPresent(Optional value), so that must look ambiguous to MapStruct. However, the latter method is NOT a mapping method, merely a condition.
Methods annotated with @Condition should NOT be considered for mappings.
MapStruct Version
MapStruct 1.5.3
Expected behavior
If I have a method annotated with
@Conditionthat serves as a presence check for Java Optionals, and I have a separate mapping method that unboxes anOptional, the Condition method should not be treated as a valid mapper method.Actual behavior
Conditional method, which needs to return boolean, clashes with mapping methods that return Boolean and whose input argument type is the same, e.g.
clashes with
Specifically, this is true when attempting to use a Conditional method to check the if the Boolean wrapped in an
OptionalisPresent, because it will return a boolean, while the mapping method that unwraps the Boolean also does this.Steps to reproduce the problem
MapStruct 1.5.3, Spring Boot 3.1.6
Result:
It seems to me like MapStruct is taking the
@Conditionmethod, and using it as a valid mapping method, instead of using it only for Conditional Mapping presence checking.If I understand correctly, the mapping steps would be:
MySourceDTOtoMyTargetDTO.Optional<Boolean>, it needs to call the@Mapper'smapFromOptional, for thesourceDto.isConditionproperty.This will resolve the mapping as
default Boolean mapFromOptional(Optional<Boolean> value), which has a similar signature asdefault boolean isOptionalPresent(Optional value), so that must look ambiguous to MapStruct. However, the latter method is NOT a mapping method, merely a condition.Methods annotated with
@Conditionshould NOT be considered for mappings.MapStruct Version
MapStruct 1.5.3