MapStruct 似乎创建了太多方法

MapStruct seems to create too many method

我正在使用 MapStruct v 1.4。1.Final 将 Hibernate 实体映射到相应的 DTO。我正在使用 Spring 启动,所以我的映射器的 classes 的 componentModel 等于 spring.

我有 2 个实体,PersonAddressPerson 包含一个 Address 实例:

public class Person {
    private String username;
    private String name;
    private Address address;
}
public class PersonDto {
    private String id;
    private String name;
    private AddressDto address;
    private String role;
}

地址

public class Address {
    private String addr;
    private String city;
}
public class AddressDto {
    private String houseAddress;
    private String city;
}

这是我写的映射器:

映射器

@Mapper(componentModel = "spring")
public interface AddressMapper {
    @Mapping(source="person.username", target="userName")
    @Mapping(source="address.addr", target="address")
    DeliveryAddressDto personAndAddressToDeliveryAddressDto(Person person, Address address);

    @Mapping(source="person.username", target="userName")
    @Mapping(source="person.address.addr", target="address")
    DeliveryAddressDto personToDeliveryAddressDto(Person person);

    @Mapping(source = "address.addr", target = "houseAddress")
    AddressDto addressToAddressDto(Address address);
    @InheritInverseConfiguration(name = "addressToAddressDto")
    Address addressDtoToAddress(AddressDto addressDto);
}
@Mapper(componentModel = "spring", uses = {AddressMapper.class})
public interface PersonMapper {

    @Mapping(source = "id", target = "username")
    @Mapping(source = "address.houseAddress", target = "address.addr")
    @Mapping(source = "role", target = "role.id")
    Person toPerson(PersonDto personDto);
    List<Person> toPeople(List<PersonDto> personDtos);

    @InheritInverseConfiguration(name = "toPerson")
    PersonDto toPersonDto(Person person);
    List<PersonDto> toPeopleDto(List<Person> people);

    /**
     * update an existing Person with Dto info.
     * Set infos on the existing object (Person), without creating a new one.
      */
    @Mapping(source = "role", target = "role.id")
    void updatePersonFromDto(PersonDto personDto, @MappingTarget Person person);

}

在那里你可以看到我对 PersonMapper 说要使用 AddressMapper 来使用它的实现。

然而,对于地址到地址 dto 的转换,我在 PersonMapper class 中找到了另一个实现(与逆映射相同):

AddressMapper 实现

@Generated(
    value = "org.mapstruct.ap.MappingProcessor",
    date = "2020-11-21T15:44:55+0100",
    comments = "version: 1.4.1.Final, compiler: javac, environment: Java 11 (Oracle Corporation)"
)
@Component
public class AddressMapperImpl implements AddressMapper {

    @Override
    public DeliveryAddressDto personAndAddressToDeliveryAddressDto(Person person, Address address) {
        if ( person == null && address == null ) {
            return null;
        }

        DeliveryAddressDto deliveryAddressDto = new DeliveryAddressDto();

        if ( person != null ) {
            deliveryAddressDto.setUserName( person.getUsername() );
        }
        if ( address != null ) {
            deliveryAddressDto.setAddress( address.getAddr() );
        }

        return deliveryAddressDto;
    }

    @Override
    public DeliveryAddressDto personToDeliveryAddressDto(Person person) {
        if ( person == null ) {
            return null;
        }

        DeliveryAddressDto deliveryAddressDto = new DeliveryAddressDto();

        deliveryAddressDto.setUserName( person.getUsername() );
        deliveryAddressDto.setAddress( personAddressAddr( person ) );

        return deliveryAddressDto;
    }

    @Override
    public AddressDto addressToAddressDto(Address address) {
        if ( address == null ) {
            return null;
        }

        AddressDto addressDto = new AddressDto();

        addressDto.setHouseAddress( address.getAddr() );
        addressDto.setCity( address.getCity() );

        return addressDto;
    }

    @Override
    public Address addressDtoToAddress(AddressDto addressDto) {
        if ( addressDto == null ) {
            return null;
        }

        Address address = new Address();

        address.setAddr( addressDto.getHouseAddress() );
        address.setCity( addressDto.getCity() );

        return address;
    }

    private String personAddressAddr(Person person) {
        if ( person == null ) {
            return null;
        }
        Address address = person.getAddress();
        if ( address == null ) {
            return null;
        }
        String addr = address.getAddr();
        if ( addr == null ) {
            return null;
        }
        return addr;
    }
}

PersonMapper 实现

@Generated(
    value = "org.mapstruct.ap.MappingProcessor",
    date = "2020-11-21T15:44:55+0100",
    comments = "version: 1.4.1.Final, compiler: javac, environment: Java 11 (Oracle Corporation)"
)
@Component
public class PersonMapperImpl implements PersonMapper {

    @Autowired
    private AddressMapper addressMapper;

    @Override
    public Person toPerson(PersonDto personDto) {
        if ( personDto == null ) {
            return null;
        }

        Person person = new Person();

        person.setAddress( addressDtoToAddress1( personDto.getAddress() ) );
        person.setRole( personDtoToRole( personDto ) );
        person.setUsername( personDto.getId() );
        person.setName( personDto.getName() );

        return person;
    }

    @Override
    public List<Person> toPeople(List<PersonDto> personDtos) {
        if ( personDtos == null ) {
            return null;
        }

        List<Person> list = new ArrayList<Person>( personDtos.size() );
        for ( PersonDto personDto : personDtos ) {
            list.add( toPerson( personDto ) );
        }

        return list;
    }

    @Override
    public PersonDto toPersonDto(Person person) {
        if ( person == null ) {
            return null;
        }

        PersonDto personDto = new PersonDto();

        personDto.setAddress( addressToAddressDto1( person.getAddress() ) );
        personDto.setId( person.getUsername() );
        personDto.setRole( personRoleId( person ) );
        personDto.setName( person.getName() );

        return personDto;
    }

    @Override
    public List<PersonDto> toPeopleDto(List<Person> people) {
        if ( people == null ) {
            return null;
        }

        List<PersonDto> list = new ArrayList<PersonDto>( people.size() );
        for ( Person person : people ) {
            list.add( toPersonDto( person ) );
        }

        return list;
    }

    @Override
    public void updatePersonFromDto(PersonDto personDto, Person person) {
        if ( personDto == null ) {
            return;
        }

        if ( person.getRole() == null ) {
            person.setRole( new Role() );
        }
        personDtoToRole1( personDto, person.getRole() );
        person.setName( personDto.getName() );
        person.setAddress( addressMapper.addressDtoToAddress( personDto.getAddress() ) );
    }

    protected Address addressDtoToAddress1(AddressDto addressDto) {
        if ( addressDto == null ) {
            return null;
        }

        Address address = new Address();

        address.setAddr( addressDto.getHouseAddress() );
        address.setCity( addressDto.getCity() );

        return address;
    }

    protected Role personDtoToRole(PersonDto personDto) {
        if ( personDto == null ) {
            return null;
        }

        Role role = new Role();

        role.setId( personDto.getRole() );

        return role;
    }

    protected AddressDto addressToAddressDto1(Address address) {
        if ( address == null ) {
            return null;
        }

        AddressDto addressDto = new AddressDto();

        addressDto.setHouseAddress( address.getAddr() );
        addressDto.setCity( address.getCity() );

        return addressDto;
    }

    private String personRoleId(Person person) {
        if ( person == null ) {
            return null;
        }
        Role role = person.getRole();
        if ( role == null ) {
            return null;
        }
        String id = role.getId();
        if ( id == null ) {
            return null;
        }
        return id;
    }

    protected void personDtoToRole1(PersonDto personDto, Role mappingTarget) {
        if ( personDto == null ) {
            return;
        }

        mappingTarget.setId( personDto.getRole() );
    }
}

在此实现中,为什么要创建方法 addressDtoToAddress1()?为什么不使用 AddressMapper 实现中提供的 addressDtoToAddress()?这些方法是相同的。

另请注意,AddressMapper 是在 PersonMapper 中注入的,AddressMapper 的方法 addressDtoToAddress() 是在方法 updatePersonFromDto() 中调用的。

您在 PersonMapper 中指定了两次地址映射。

@Mapping(source = "id", target = "username")
@Mapping(source = "address.houseAddress", target = "address.addr")
Person toPerson(PersonDto personDto);

您声明 PersonMapper 应该使用 AddressMapper,但您添加了另一个覆盖映射以手动映射字段。

您可以删除映射,它会自动找到正确的映射。

@Mapping(source = "id", target = "username")
Person toPerson(PersonDto personDto);

如果要添加显式映射,您需要选择源作为 PersonDto 的地址字段到目标 Person 的地址字段。下面将给出相同的结果。

@Mapping(source = "id", target = "username")
@Mapping(source = "address", target = "address")
Person toPerson(PersonDto personDto);

它在 updatePersonFromDto() 中工作正常,因为您没有添加它的覆盖并且它自己选择了 AddressMapper。如果向其添加相同的冗余映射,您会注意到相同的行为。