Search code examples
javaspringhibernateorika

How to deep copy an entity excluding id's of it's relations?


I'm using Spring with Spring Data JPA, I've encountered a problem with deep copying a complex entity. The entity A has 10 one-to-many relationships (only one is shown here for brevity), I want to deep copy this entity without the id fields of the nested objects B.

I want to avoid using reflection due to performance penalty. Using Orika I've manged to exclude the id of A but failed to exclude the id's of the nested objects.

@Entity
public class A {

    @Id
    @GeneratedValue
    private Long id;
    //...

    @OneToMany()
    @JoinColumn(name = "a_id")
    private Set<B> items;

    // getters and setters
}

@Entity
public class B {

    @Id
    @GeneratedValue
    private Long id;
    //...

    public B() {}

    // getters and setters
}

As you can see I've tried to exclude the id of B by registering a custom MapperFactory but it doesn't work as expected. Only the id of A is excluded but the elements of collection items still have their id's.

A source = fetchFromDb();
MapperFactory mapperFactory = new DefaultMapperFactory.Builder().build();
        mapperFactory.classMap(A.class, A.class)
                .mapNulls(true)
                .exclude("id")
                .exclude("items['id']")
                .byDefault()
                .register();
        MapperFacade mapperFacade = mapperFactory.getMapperFacade();

        A dest = mapperFacade.map(source, A.class);

How to achieve my goal? note - I'm not locked to Orika, any other solution is welcome.


Solution

  • I've managed to solve the issue by implementing a custom ClassMapBuilder for Orika mapper and overriding it's byDefault() method. Now When the mapper is used to copy the container class, every field which has the Id annotation is excluded - it effects all nested single and multi-occurance elements.

    To make the mapper use a custom ClassMapBuilder:

      MapperFactory mapperFactory = new DefaultMapperFactory
                .Builder()
                .classMapBuilderFactory(new IdExclusionClassMapBuilder.Factory())
                .build();