I'm attempting to use modelmapper to map a Person and Address class to a PersonDTO. ModelMapper throws a NullPointerException when I try to map Person.Id to PersonDTO.Id AND deep mapping of Person.Address.Id to PersonDTO.addressId. These two properties are different but have similar names.

I'm using ModelMapper 2.3.0 and Java 12.

I receive the following error:

Exception in thread "main" java.lang.NullPointerException
    at org.modelmapper.internal.ReferenceMapExpressionImpl.map(ReferenceMapExpressionImpl.java:68)
    at org.modelmapper.internal.ConfigurableMapExpressionImpl.map(ConfigurableMapExpressionImpl.java:68)
    at org.thegeekfactory.App.lambda$main$4(App.java:22)
    at org.modelmapper.internal.TypeMapImpl.addMappings(TypeMapImpl.java:266)
    at org.thegeekfactory.App.main(App.java:21)

The NULLPointerException is avoided when I comment out the deep mapping of Person.Address.Id and change Matching Strategy to LOOSE but the two properties shared the same value (which should be different).

Main.java

public class App 
{
    public static void main( String[] args )
    {
        ModelMapper modelMapper = new ModelMapper();
        modelMapper.getConfiguration().setMatchingStrategy(MatchingStrategies.STRICT);
        modelMapper.createTypeMap(Person.class, PersonDTO.class);
        TypeMap<Person, PersonDTO> personDTOTypeMap = modelMapper.getTypeMap(Person.class, PersonDTO.class);
        personDTOTypeMap.addMappings(mapper -> {
            mapper.map(src -> src.getAddress().getId(), PersonDTO::setAddressId);
            mapper.map(src -> src.getAddress().getStreet(), PersonDTO::setStreet);
            mapper.map(src -> src.getAddress().getCity(), PersonDTO::setCity);
            mapper.map(src -> src.getAddress().getState(), PersonDTO::setState);
        });

        Person owner = new Person("John", "Doe", "12345");
        Address ownerAddress = new Address("First Street", "Los Angeles", "California");
        owner.setAddress(ownerAddress);

        PersonDTO returnOwner = modelMapper.map(owner, PersonDTO.class);
        modelMapper.validate();

        System.out.println(returnOwner.getId());
        System.out.println(returnOwner.getAddressId());
        System.out.println(returnOwner.getFirstName());
        System.out.println(returnOwner.getLastName());
        System.out.println(returnOwner.getStreet());
        System.out.println(returnOwner.getCity());
        System.out.println(returnOwner.getState());

        List<Mapping> maps = personDTOTypeMap.getMappings();
        for (Mapping map : maps) {
            System.out.println(map);
        }
    }
}

PersonDTO.java

public class PersonDTO {
    private int id;
    private int addressId;
    private String firstName;
    private String lastName;
    private String street;
    private String city;
    private String state;

    public int getId() { return id; }

    public void setId(int id) { this.id = id; }

    public int getAddressId() {
        return addressId;
    }

    public void setAddressId(int addressId) {
        this.addressId = addressId;
    }

    public String getFirstName() {
        return firstName;
    }

    public void setFirstName(String firstName) {
        this.firstName = firstName;
    }

    public String getLastName() {
        return lastName;
    }

    public void setLastName(String lastName) {
        this.lastName = lastName;
    }

    public String getStreet() {
        return street;
    }

    public void setStreet(String street) {
        this.street = street;
    }

    public String getCity() {
        return city;
    }

    public void setCity(String city) {
        this.city = city;
    }

    public String getState() {
        return state;
    }

    public void setState(String state) {
        this.state = state;
    }
}

Person.java

public class Person {
    private int id;
    private String firstName;
    private String lastName;
    private String password;
    private Address address;

    public Person(String firstName, String lastName, String password) {
        this.id = new Random().nextInt(100);
        this.firstName = firstName;
        this.lastName = lastName;
        this.password = password;
    }

    public int getId() { return id; }

    public void setId(int id) { this.id = id; }

    public String getFirstName() {
        return firstName;
    }

    public void setFirstName(String firstName) {
        this.firstName = firstName;
    }

    public String getLastName() {
        return lastName;
    }

    public void setLastName(String lastName) {
        this.lastName = lastName;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    public Address getAddress() { return address; }

    public void setAddress(Address address) { this.address = address; }

Address.java

public class Address {
    private int id;
    private String street;
    private String city;
    private String state;

    public Address(String street, String city, String state) {
        this.id = new Random().nextInt(100);
        this.street = street;
        this.city = city;
        this.state = state;
    }

    public int getId() { return id; }

    public void setId(int id) { this.id = id; }

    public String getStreet() {
        return street;
    }

    public void setStreet(String street) {
        this.street = street;
    }

    public String getCity() {
        return city;
    }

    public void setCity(String city) {
        this.city = city;
    }

    public String getState() {
        return state;
    }

    public void setState(String state) {
        this.state = state;
    }
}

I expect this code to implicitly map Person.Id to PersonDTO.Id AND explicitly deep map Person.Address.Id to PersonDTO.addressId.

Any help anyone can provide would be much appreciated as I spent an embarrassing amount of days debugging this problem to no solution.

0 Answers