在我们公司,我们发现Dozer在将字段从休眠实体复制到带有字段的简单DTO(简单的POJO)时遇到了问题,这些字段是其他实体的映射。 这是它的外观:
class MyJPAEntity{
@JPAMappings(FetchType.EAGER)
Map<Integer, EmbeddableJPAEntity> map;
}
class MyDto{
Map<Integer, MyOtherDto> map;
}
尝试将字段从实体复制到DTO时,Dozer尝试以某种方式复制代理而不是其内容,从而引发LazyInitializationException(即使获取类型为EAGER)。我们发现,我们可以创建一个包装器和一个处理这种情况的自定义转换器:
public class MaybePersistentMapToHashMapConverter extends
DozerConverter<Map, Map> implements MapperAware {
public static class Wrapper {
private Map map;
public Wrapper() {
}
public Wrapper(Map map) {
this.map = map;
}
public Map getMap() {
return map;
}
public void setMap(Map map) {
this.map = map;
}
}
private Mapper mapper;
public MaybePersistentMapToHashMapConverter() {
super(Map.class, Map.class);
}
@Override
public void setMapper(Mapper mapper) {
this.mapper = mapper;
}
@Override
public Map convertTo(Map source, Map destination) {
return map(source, destination);
}
@Override
public Map convertFrom(Map source, Map destination) {
return map(source, destination);
}
private Map map(Map source, Map destination) {
Wrapper wrapper;
if (source instanceof PersistentMap) {
wrapper = new Wrapper(new HashMap<>(source));
} else {
wrapper = new Wrapper(source);
}
if (destination == null) {
Wrapper map = mapper.map(wrapper, Wrapper.class);
return map.map;
} else {
throw new UnsupportedOperationException();
}
}
}
所以这个东西,只是包装地图,以便推土机不复制proxyMap。我只是在代码中配置映射:
mapping(fromType, toType, oneWay())
.fields("map", "map", FieldsMappingOptions.customConverter(MaybePersistentMapToHashMapConverter.class)
到目前为止一切顺利。 那么问题是什么?问题在于其他方式的映射 - 从DTO到实体。而不是从MyDto复制到MyJPAEntity条目到Entity(将内部DTO映射到内部实体,它实际上将一个带有条目的地图复制到MyJPAEntity中 - 可能它无法猜测目标类型是什么,而不是映射对象,它只是复制它们。
所以我也可以通过指定地图类型的提示来解决问题:
fields("map", "map", FieldsMappingOptions.hintA(MyOtherDto.class), FieldsMappingOptions.hintB(EmbeddableJPAEntity.class) )
我可能已经帮助了一些人;)很高兴我解决了我的问题。
UNTIL我必须使用doser 将值从实体复制到另一个实体。现在,如果我使用提示,我会得到LazyInitException,如果我使用上面的包装转换器,则映射器会忽略提示。 Dozer的sourceforge文档现在无法访问。 有没有人知道如何使用映射器并强制它使用我的提示?或者如何通过映射构建器正确配置它?
我会说,MaybePersistentMapToHashMapConverter中使用的映射器实际上并不知道它应该使用提示,因为它不知道它实际上是映射了一个名称字段&#34; map&#34;
答案 0 :(得分:1)
在我们的项目中,我们解决了这个问题并严重影响了与您解决的问题完全相同的问题;)。
你的LazyInitializationException可能是在dozer的map方法中调用.class。 这是因为推土机将实例化新的实体并填充它,并且该实体不在当前会话中。 我们通过以下方式更改我们的推土机地图方法:
A_Entity newEntity = dozer.map(dto,A_Entity.class);
为:
A_Entity newEntity = new A_Entity();
dozer.map(A_dto,newEntity);
以其他方式:
A_dto dto = dozer.map(entity,A_DTO.class);
为:
A_dto dto = Spring.context.getBean("a_dto");
dozer.map(entity,dto);
我希望这会有用。