Reputation: 342
The problem I am facing is that I have a Spring Boot application with a custom DozerConverter
that gets called by a DozerBeanMapper
only in a @SpringBootTest
class, and not in a service class.
The DozerBeanMapper is defined in a configuration class like so:
@Configuration
public class Config {
@Bean
public Mapper getMapper() {
DozerBeanMapper mapper = new DozerBeanMapper();
mapper.setMappingFiles(Collections.singletonList("mappings.xml"));
return mapper;
}
}
This is mappings.xml
:
<?xml version="1.0" encoding="UTF-8"?>
<mappings xmlns="http://dozer.sourceforge.net"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://dozer.sourceforge.net
http://dozer.sourceforge.net/schema/beanmapping.xsd">
<configuration>
<custom-converters>
<converter type="com.app.util.converter.EntityToDtoDozerConverter">
<class-a>com.app.model.entity.Entity</class-a>
<class-b>com.app.model.dto.Dto</class-b>
</converter>
<custom-converters>
</configuration>
</mappings>
And this is the custom DozerConverter
:
@Component
public class EntityToDtoDozerConverter extends DozerConverter<Entity, Dto> {
private AnotherService myService;
public EntityToDtoDozerConverter() {
super(Entity.class, Dto.class);
}
public EntityToDtoDozerConverter(AnotherService myService) {
this();
this.myService = myService;
}
@Override
public Dto convertTo(Entity entity, Dto dto) {
if (dto == null)
dto = new Dto();
dto.setId(entity.getId());
dto.setSubEntity(myService.findById(entity.getSubEntityId()));
return dto;
}
@Override
public Entity convertFrom(Dto dto, Entity entity) {
if (entity == null)
entity = new Entity();
entity.setId(dto.getId());
entity.setSubEntityId(dto.getSubEntity().getId());
return entity;
}
}
Here mapper.map()
calls the custom converter as I would expect.
@SpringBootTest
public class DozerTests {
@Autowired
Mapper mapper;
@Test
void myTest() {
Entity entity = new Entity(1, 2);
Dto dto = mapper.map(entity, Dto.class); // -----> Here the dto is correct
...
}
}
Here mapper.map()
does not call my custom converter, so SubEntity results in null value.
@Service
public class Service implements IService {
private final Mapper mapper;
private final EntityManager em;
...
public Service(Mapper mapper, EntityManager em) {
this.mapper = mapper;
this.em = em;
}
@Override
public Dto findById(int id) {
Entity entity = repository.findById(id).orElseThrow(() -> new EntityNotFoundException("not found"));
Dto dto = mapper.map(entity, Dto.class); // ------> Here the dto is incorrect (null value for SubEntity)
return dto;
}
}
Update: debugging each case more deeply, I found out that what's causing the different behavior is the internal caching mechanism of Dozer. Specifically, when trying to map in the "service class" case, I can see that the mapper has internally some cached mappings that prevent him to load the custom converter. This is not the case when mapping in the test class.
Upvotes: 1
Views: 485
Reputation: 2357
looks like an old unresolved bug... Injected Custom Converters are not used
Adding the custom converter to mapping.xml seems to use a (default) constructed instance Custom converter with Spring dependency injection
But then you should see an error because of missing AnotherService
in your converter.
But no idea why it works in your test class.
Upvotes: 1
Reputation: 1869
looks like your service doesn't find the subEntity
:dto.setSubEntity(myService.findById(entity.getSubEntityId()));
Upvotes: 0