javajpadomain-driven-designdtodomain-object

Domain object to persisting entity converting


I need to store domain object (DO) into DB.

The simplest approach is to add into DO definition some JPA annotations like @Entity, @SequenceGenerator, @Table etc. but I don't want to mix DO with another conception like persisting. So I use separate DTO object and put annotations here.

As I'm a great Domain Driven Design follower I don't interconnect with DB directly and use Repository pattern. If in the future I migrate from RDBMS to e.g. NoSQL all changes will be done only in Repository and my DO will be intact.

Thus the flow sequence is

DO -> Repository -converting-> DTO -> DB

As my DO has a lot of fields the conversion step is quite cumbersome and at the same time quite trivial: get fieldA from DO and put it into fieldA' in DTO (with simple transformations in some cases). Currently I do this manually in a separate Transformer.

What are other (better?) approaches to do this conversion step?

UPDATE

Good comparison of bean mapping frameworks Dozer vs Orika vs Manual field mapping approach


Solution

  • First of all, that's quite a great idea to separate your persistent entity from your domain objects. I used to deal with setups where both approaches have been mixed together and that lead us to a complete mess afterwards.

    The approach you're looking for is called 'Bean mapping'. There are a lot of such mappers around, Dozer seems to be the most widely used, but it's reflection-based and thus it's quite slow. Orika has good balance between performance and extensibility, but it also leads to some weird classloading issues in Java EE environment.

    Most of bean mappers perform automatic mapping for equally named fields, extra conversions may be defined for 'simple transformations' you have mentioned above. Here's the example of Orika configuration for particular Web-to-DB entity mapping (with workaround for the classloading issue mentioned above applied): https://bitbucket.org/__jtalk/jacra/src/default/JAcraEJB/src/main/java/me/jtalk/jacra/utils/mapper/MappersRegistration.java

    You can then use those mappers like:

    @Inject
    @UserMapper
    private BoundMapperFacade<UserEntity, UserWeb> userMapper;
    ...
    UserEntity entity = userMapper.mapReverse(userWeb);
    mapper.map(entity);