Mapping beans that refer another bean as its properties

In all my previous posts under MapStruct, whenever I gave an example of MapStruct, I used a bean having only primitive data types and not user defined types.

In this post, I will show with example how to do mapping of a bean which refers to another bean as its property.

For our example I will use two pojo classes “Person” and “Address” as shown below

Address

package package28;

public class Address {
    private String addressLine1;
    private String addressLine2;

    //Removed getter and setter for brevity
}

Person

package package28;

public class Person {
    private int id;
    private String name;
    private Address address;

    //Removed getter and setter for brevity
}

As you can see in the above class structure, “Person” class has a property named “address” which is of type “Address” class.

Now in our example we will map “Person” class object data to “PersonDTO” class object.

The class structure of “PersonDTO” is similar to “Person”. The “PersonDTO” class has a property named “addressDTO” of type “AddressDTO”.

“AddressDTO” class structure is same as “Address” class. Only class names are different.

Now the mapper interface will be

PersonMapper

package package28;

import org.mapstruct.Mapper;
import org.mapstruct.Mapping;

@Mapper
public interface PersonMapper {
    @Mapping(target = "addressDTO", source = "address")
    PersonDTO personToPersonDTO(Person person);
}

In “PersonDTO” class structure, the property names are same as in “Person” class, except for “AddressDTO”.

In “Person” class the property name is “address” and it is of type “Address”, whereas in “PersonDTO” class the property name is “addressDTO” and it is of type “AddressDTO”.

For this reason I have added a “@Mapping” annotation informing MapStruct about the change in property name.

Internally MapStruct will generate a class “PersonMapperImpl” that implements the “PersonMapper” interface as shown below

PersonMapperImpl

package package28;

/*
@Generated(
    value = "org.mapstruct.ap.MappingProcessor",
    date = "2025-08-23T12:10:49+0530",
    comments = "version: 1.5.5.Final, compiler: IncrementalProcessingEnvironment from gradle-language-java-8.5.jar, environment: Java 21.0.4 (Amazon.com Inc.)"
)
*/
public class PersonMapperImpl implements PersonMapper {

    @Override
    public PersonDTO personToPersonDTO(Person person) {
        if ( person == null ) {
            return null;
        }

        PersonDTO personDTO = new PersonDTO();

        personDTO.setAddressDTO( addressToAddressDTO( person.getAddress() ) );
        personDTO.setId( person.getId() );
        personDTO.setName( person.getName() );

        return personDTO;
    }

    protected AddressDTO addressToAddressDTO(Address address) {
        if ( address == null ) {
            return null;
        }

        AddressDTO addressDTO = new AddressDTO();

        addressDTO.setAddressLine1( address.getAddressLine1() );
        addressDTO.setAddressLine2( address.getAddressLine2() );

        return addressDTO;
    }
}

Since “Address” and “AddressDTO” are user defined type, MapStruct automatically add a new “addressToAddressDTO” method and populated it with code that will be used to create and return an instance of
“AddressDTO” with data from source “address” object. Refer to line from 27 to 38.

This method is called in “personToPersonDTO” at line 20.

In this way, MapStruct map beans having a reference to another bean as property.

I have added code for main class, “PersonDTO” and “AddressDTO” class for your reference.

Main class

package package28;

import org.mapstruct.factory.Mappers;

public class Example28 {
    public static void main(String [] args) throws Exception {
        PersonMapper personMapper = Mappers.getMapper(PersonMapper.class);

        Address address = new Address();
        address.setAddressLine1("addressLine1");
        address.setAddressLine2("addressLine2");

        Person person = new Person();
        person.setId(1);
        person.setName("John Doe");
        person.setAddress(address);

        PersonDTO personDTO = personMapper.personToPersonDTO(person);

        System.out.println(personDTO);
    }
}

AddressDTO

package package28;

public class AddressDTO {
    private String addressLine1;
    private String addressLine2;

    //Removed getter and setter for brevity
}

PersonDTO

package package28;

public class PersonDTO {
    private int id;
    private String name;
    private AddressDTO addressDTO;

    //Removed getter and setter for brevity
}

Leave a comment