-
-
Notifications
You must be signed in to change notification settings - Fork 1k
Open
Description
Expected behavior
MapStruct should correctly generate the mapper implementation for converting UserEntity to UserModel, including mapping nested lists, without invoking methods intended for Optional types. The generated code should compile successfully, as it did in version 1.5.5.
Actual behavior
Starting from MapStruct version 1.6.0 (tested up to 1.6.2), the generated mapper implementation incorrectly uses the OptionalMapper.map methods when mapping List to List. This leads to compilation errors due to inappropriate method selection and type inference issues. Specifically, the generated code attempts to map a List using methods intended for Optional types, resulting in the following compilation error
error: no suitable method found for map(List<UserEntity.AddressEntity>,Class<Optional>)
userModel.setAddresses( OptionalMapper.map( OptionalMapper.map( source.getAddresses(), Optional.class ) ) );
^
method OptionalMapper.<T>map(Optional<T>) is not applicable
(cannot infer type-variable(s) T
(argument mismatch; no instance(s) of type variable(s) exist so that Optional<T> conforms to Object))
method OptionalMapper.<T>map(Object,Class<Optional<T>>) is not applicable
(cannot infer type-variable(s) T
(argument mismatch; Class<Optional> cannot be converted to Class<Optional<T>>))
Steps to reproduce the problem
import org.mapstruct.InjectionStrategy;
import org.mapstruct.Mapper;
import org.mapstruct.ReportingPolicy;
import org.mapstruct.TargetType;
import java.util.List;
import java.util.Optional;
@Mapper(
unmappedTargetPolicy = ReportingPolicy.ERROR,
uses = OptionalMapper.class,
injectionStrategy = InjectionStrategy.CONSTRUCTOR
)
public interface MainMapper {
UserModel map(UserEntity source);
}
class UserEntity {
List<AddressEntity> addresses;
public List<AddressEntity> getAddresses() {
return addresses;
}
public void setAddresses(List<AddressEntity> addresses) {
this.addresses = addresses;
}
static class AddressEntity {
List<String> addressLines;
public List<String> getAddressLines() {
return addressLines;
}
public void setAddressLines(List<String> addressLines) {
this.addressLines = addressLines;
}
}
}
class UserModel {
List<AddressModel> addresses;
public List<AddressModel> getAddresses() {
return addresses;
}
public void setAddresses(List<AddressModel> addresses) {
this.addresses = addresses;
}
static class AddressModel {
List<String> addressLines;
public List<String> getAddressLines() {
return addressLines;
}
public void setAddressLines(List<String> addressLines) {
this.addressLines = addressLines;
}
}
}
interface OptionalMapper {
static <T> T map(Optional<T> source) {
return null;
}
static <T> Optional<T> map(Object source, @TargetType Class<Optional<T>> targetType) {
return null;
}
}results with
public class MainMapperImpl implements MainMapper {
@Override
public UserModel map(UserEntity source) {
if ( source == null ) {
return null;
}
UserModel userModel = new UserModel();
userModel.setAddresses( OptionalMapper.map( OptionalMapper.map( source.getAddresses(), Optional.class ) ) );
return userModel;
}
}MapStruct Version
1.6.0-1.6.2
Reactions are currently unavailable