0
votes

I need some community help to point me out where I'm wrong in my code... :)

I try to use mapstruct to map fields between 2 entities with the help of an @ObjectFactory.

Entity 1:

public class ScimUser   {

    @JsonProperty("addresses")
    @Valid
    private List<UserAddress> addresses = null;

}

Entity 2:

public class User   {

    @JsonProperty("postalAddress")
    private PostalAddress postalAddress = null;

}

Mapper:

@Mapper(componentModel = "spring", uses = { AddressFactory.class })
public interface ScimUserMapper {

    @Mapping(target = "postalAddress", source = "scimUser.addresses")
    User toUser(ScimUser scimUser);

    @Mapping(target = "addresses", source = "user.postalAddress")
    ScimUser toScimUser(User user);

}

ObjectFactory:

@Component
public class AddressFactory {

    @Autowired
    private CountryMapper countryMapper;

    @Autowired
    private CountryRepository countryRepository;

    @ObjectFactory
    public PostalAddress toPostalAddress(List<UserAddress> addresses, @TargetType Class<PostalAddress> type) {
        PostalAddress postalAddress = new PostalAddress();
        if (addresses != null && !addresses.isEmpty()) {
            UserAddress userAddress = addresses.stream().filter(UserAddress::isPrimary).findFirst().orElse(null);
            if (userAddress == null) {
                userAddress = addresses.get(0);
            }
            postalAddress.setAddressLine1(userAddress.getStreetAddress());
            postalAddress.setPostCode(userAddress.getPostalCode());
            postalAddress.setState(userAddress.getRegion());
            postalAddress.setCity(userAddress.getLocality());
            CountryJpa countryJpa = countryRepository.getCountryByIso2Code(userAddress.getCountry());
            if (countryJpa != null) {
                Country country = countryMapper.fromJPA(countryJpa);
                postalAddress.setCountry(country);
            }
        }
        return postalAddress;
    }

    @ObjectFactory
    public List<UserAddress> toUserAddressList(PostalAddress address, @TargetType Class<List<UserAddress>> type) {
        UserAddress userAddress = new UserAddress();
        userAddress.setCountry(address.getCountry().getIso2());
        userAddress.setFormatted("?");
        userAddress.setLocality(address.getCity());
        userAddress.setPostalCode(address.getPostCode());
        userAddress.setPrimary(true);
        userAddress.setRegion(address.getState());
        userAddress.setStreetAddress(address.getAddressLine1());
        userAddress.setType("?");

        return Collections.singletonList(userAddress);
    }

}

The code above gets me this error during source code generation:

Can't map property "java.util.List addresses" to "PostalAddress postalAddress". Consider to declare/implement a mapping method: "PostalAddress map(java.util.List value)". Can't map property "PostalAddress postalAddress" to "java.util.List addresses". Consider to declare/implement a mapping method: "java.util.List map(PostalAddress value)".

It's not the first time that I struggle with using these object factories and I really don't get what I am doing wrong.

So if someone has an idea, I'd be glad to read it. :)

1

1 Answers

1
votes

You are using the @ObjectFactory wrong. What you want to achieve is a custom mapping method.

@ObjectFactory needs to be used to create the target instance object. In your case if you just remove @ObjectFactory and @TargetType from your method then it should work correctly.

I have to stress out that you are doing quite some manual mapping there. You can easily provide methods for mapping between a single UserAddress and PostalAddress and just add wrappers for the collections.