所以我遇到一个问题,这里有人可以帮我解决Dozer。
背景:我已将Dozer设置为将我的持久性实体映射到其DTO类。这很简单,我只是创建一个我的实体类的精确复制品作为POJO并允许推土机外卡看到该字段的名称与sources字段匹配。我正在使用自定义映射器处理hibernates延迟加载问题here。我告诉Dozer如何通过一个类来映射每个类,该类扫描实体中名为@EntityMapping(DTOxxx.class)的注释。然后将它添加到mapper addMapping(builder)
问题:(最后阅读研究,了解最新信息,但这也有助于通过阅读所有内容来获取背景信息) 问题是Dozer没有在SOME实例中正确映射我的集合。例如,在我的CategoryEntity类中,我有一组Dozer需要映射的其他实体。发生的事情是,推土机在这种情况下找到了2个项目的集合,并且只在新的DTO类集合中映射了1个项目。
正如你在toDomain调用之后在图像中看到的那样(这里有mapper.map(源,desination)推土机调用)DTO只有它应该从实体映射到它的2个对象中的1个。这是你想看到它的toDomain方法:
@Transactional(readOnly=true)
public <T extends DomainObject> T toDomain(Class<T> clazz, Entity entity) {
if (entity == null) {
return null;
}
T domain = getCachedDomainObjects(clazz, entity.getId());
if (domain == null) {
domain = dozerMapper.map(entity, clazz);
cacheDomainObject(domain);
}
return domain;
}
如果您正在考虑的话,我已经确定它不会抓取缓存的实体。
所以我有点难以理解为什么在某些情况下会发生这种情况,而不是在其他情况下。在它工作的场合和不起作用的场合,我看不出任何明显的差异。如果有人之前遇到过这样的问题,并认为他们能够帮助我,那就太棒了!以下是问题示例中的类:
CategoryEntity.java:
@EntityMapping(Category.class)
@javax.persistence.Entity(name = "categories")
public class CategoryEntity implements Entity, PureTable {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(unique = true, nullable = false)
private int id = Entity.UNSAVED_ID;
@OneToMany(mappedBy = "pk.category", fetch = FetchType.LAZY)
@Cascade({CascadeType.SAVE_UPDATE})
private Set<IncidentJoinCategoryEntity> incidentJoinCategories =
new HashSet<IncidentJoinCategoryEntity>();
@Override
public int getId() {
return this.id;
}
public void setId(int id) {
this.id = id;
}
public Set<IncidentJoinCategoryEntity> getIncidentJoinCategories() {
return incidentJoinCategories;
}
public void setIncidentJoinCategories(Set<IncidentJoinCategoryEntity>
incidentJoinCategories) {
this.incidentJoinCategories = incidentJoinCategories;
}
}
此类有一个完全匹配其值的DTO类:
Category.java:
public class Category {
int id;
Set<IncidentJoinCategory> incidentJoinCategories=
new HashSet<IncidentJoinCategory>();
@Override
public int getId() {
return id;
}
@Override
public void setId(int id) {
this.id = id;
}
public Set<IncidentJoinCategory> getIncidentJoinCategories() {
return incidentJoinCategories;
}
public void setIncidentJoinCategories(Set<IncidentJoinCategory>
incidentJoinCategories) {
this.incidentJoinCategories = incidentJoinCategories;
}
}
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!研究!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
编辑#1:
好!所以我花了几个小时调试这个问题,以了解这里发生了什么。事实证明问题出在MappingProcessor类749行(Dozer 5.4.0)或766行的最新来源(但我还没有检查这是否仍然是最新来源中的一个问题,但是怀疑它是否已修复)。
此行
((Set) field).addAll(result);
这里想要映射的是
HashSet<IncidentJoinCategoryEntity>
addAll(result)只向((Set)字段)集合添加1个项目。其中包含2个项目的结果(在调试期间它也是大小2我将提供变量的快照)只是向((Set)字段)强制转换添加1个值。
result LinkedHashSet<E> (id=220)
map LinkedHashMap<K,V> (id=248)
accessOrder false
entrySet HashMap$EntrySet (id=251)
hashSeed -1187793029
header LinkedHashMap$Entry<K,V> (id=253)
keySet HashMap$KeySet (id=5829)
loadFactor 0.75
modCount 2
size 2
table HashMap$Entry<K,V>[16] (id=258)
threshold 12
useAltHashing false
values null
field HashSet<E> (id=221)
map HashMap<K,V> (id=247)
entrySet HashMap$EntrySet (id=5856)
hashSeed 1372273954
keySet HashMap$KeySet (id=5821)
loadFactor 0.75
modCount 2
size 1
table HashMap$Entry<K,V>[16] (id=5822)
threshold 12
useAltHashing false
values null
编辑#2:
下载源代码以进行更多调试:
if (field == null) {
Class<? extends Set<?>> destSetType = (Class<? extends Set<?>>) fieldMap.getDestFieldType(destObj.getClass());
return CollectionUtils.createNewSet(destSetType, result);
} else {
System.out.println("----IN----");
// Bug #1822421 - Clear first so we don't end up with the removed orphans again
Set ret = (Set) field;
ret.clear();
//((Set) field).addAll(result);
for(Object res : result) {
System.out.println("FOUND " + res.toString());
ret.add(res);
}
System.out.println("END SIZE " + ret.size());
System.out.println("----OUT----");
return ret;
}
此案例的输出:
----IN----
FOUND nz.co.doltech.ims.project.shared.domains.joins.IncidentJoinCategory@3e2
FOUND nz.co.doltech.ims.project.shared.domains.joins.IncidentJoinCategory@3e2
END SIZE 1
----OUT----
它的输出是2项,但是你可以看到@ 3e2由于某种原因它们是同一个项目。因此,当您调用addAll时,它会删除重复内容,只留下1个项目。为什么Dozer意外地映射了2个相同的值?我检查以确保源对象集合没有相同的项目加倍,并且肯定不是。确实很奇怪。
编辑#3:
我做了进一步的测试,运气不大。这确实是一个问题,Dozer映射2具有相同的值,并且addAll将副本关闭,使其成为列表中的一个项目。遗憾的是,我无法轻松调试addToSet中的递归方法,以确定原因。
如果我想出其他任何事情,我会更新,否则我对这一点没有想法哈哈。
答案 0 :(得分:1)
事实证明这实际上并不是一个Dozer bug。调试表明Dozer是罪魁祸首,但我认为不是这样。原因我认为这是因为我转换到另一个具有相同问题的映射器,所以除非这个新映射器具有相同的问题(lol),否则它不是Dozer。如果有人知道为什么会发生这种情况,我会很感激你的帮助。
我现在的猜测是我用来处理延迟加载敏感集合的hibernate自定义字段映射器。我首先忽视这一点的唯一原因是因为当我开始调试Dozer时,似乎Dozer在从addToSet返回之前映射了字段,所以我错误地认为它已经应用了自定义字段映射。