Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Orika Mapper - Cannot register converters after MapperFacade has been initialized

I have created a class to copy bean properties using Orika Mapper API in spring boot application as shown below:

public class ObjectMapper {

    private static MapperFactory mapperFactory = new DefaultMapperFactory.Builder().build();

    public static ClientEntity toClientEntity(ClientDTO clientDTO) {
        BoundMapperFacade<ClientDTO, ClientEntity> boundMapper = mapperFactory.getMapperFacade(ClientDTO.class, ClientEntity.class);
        return boundMapper.map(clientDTO);
    }   

    public static UserEntity toUserEntity(UserDTO userDTO) {
        mapperFactory.getConverterFactory().registerConverter(new PassThroughConverter(LocalDate.class));
        mapperFactory.getConverterFactory().registerConverter(new PassThroughConverter(LocalTime.class));
        BoundMapperFacade<UserDTO, UserEntity> boundMapper = mapperFactory.getMapperFacade(UserDTO.class, UserEntity.class);
        return boundMapper.map(userDTO);
    }
}

UserEntity & UserDTO POJO classes have JAVA 8 LocalDate and LocalTime properties so have registeredConverters for mapperFactory. This works fine for first time but on consecutive call it throws the below exception :

java.lang.IllegalStateException: Cannot register converters after MapperFacade has been initialized
    at ma.glasnost.orika.converter.DefaultConverterFactory.registerConverter(DefaultConverterFactory.java:192) ~[orika-core-1.4.6.jar:na]
    at ma.glasnost.orika.impl.DefaultMapperFactory$ConverterFactoryFacade.registerConverter(DefaultMapperFactory.java:1614) ~[orika-core-1.4.6.jar:na]

I understand this is because converters are being registered after MapperFacade is initialized. How to resolve this issue? How to register converters before initialization?

like image 958
JavaDeveloper Avatar asked Apr 09 '18 03:04

JavaDeveloper


1 Answers

In provided snippet you are trying to register converters every time toUserEntity() is called. So, the first call would work, but the second would fail because the MapperFacade would be already initialized during the first call.

You may move converters registration from mapping method to the static block like this:

private static MapperFactory mapperFactory = new DefaultMapperFactory.Builder().build();
static {
    mapperFactory.getConverterFactory().registerConverter(new PassThroughConverter(LocalDate.class));
    mapperFactory.getConverterFactory().registerConverter(new PassThroughConverter(LocalTime.class));
}

Also, you may prefer to move BoundMapperFacade's to the static fields to avoid unnecessary getMapperFacade calls, like this:

private static BoundMapperFacade<ClientDTO, ClientEntity> clientBoundMapper 
                     = mapperFactory.getMapperFacade(ClientDTO.class, ClientEntity.class);
private static BoundMapperFacade<UserDTO, UserEntity> userBoundMapper 
                     = mapperFactory.getMapperFacade(UserDTO.class, UserEntity.class);

So the mapping methods will turn into simple one-liners:

public static ClientEntity toClientEntity(ClientDTO clientDTO) {
    return clientBoundMapper.map(clientDTO);
}   

public static UserEntity toUserEntity(UserDTO userDTO) {
    return userBoundMapper.map(userDTO);
}
like image 134
Anatoly Shamov Avatar answered Sep 16 '22 14:09

Anatoly Shamov