我正在尝试将A-DTO对象映射到A-DO对象,每个对象分别具有T-DTO和T-DO的集合(List)。我试图在REST API的上下文中这样做。这是一个单独的问题,这是一个正确的方法 - 我正在解决的问题是一个更新的案例。基本上,如果A-DTO中的一个T-DTO发生变化,我希望将该变化映射到A-DO内的相应T-DO。
我在Dozer文档中找到relationship-type="non-cumulative"
,以便更新集合中的对象(如果存在)。但我最终将Dozer在A-DO的系列中插入了新的T-DO!
注意:我确实实现了equals
!它目前仅基于主键。
有什么想法吗?
PS:而且,如果您认为处理一对多依赖实体的更新是一个坏主意,请随意指出...我不是100%肯定我喜欢这种方法,但我的REST foo不是很强大。
更新
equals
实施:
@Override
public boolean equals(Object obj) {
if (obj instanceof MyDOClass) {
MyDOClass other = (MyDOClass) obj;
return other.getId().equals(this.getId());
}
return false;
}
答案 0 :(得分:4)
我遇到了同样的问题,我解决了这个问题:
推土机使用contains
来确定成员是否在集合中
您应该实施hashCode
,以便"contains"
能够正常运作。
您可以在以下文档页面中看到: http://dozer.sourceforge.net/documentation/collectionandarraymapping.html 下:“累积与非累积列表映射(双向)”
祝你好运!答案 1 :(得分:1)
完成自定义映射。
答案 2 :(得分:0)
我确实做了自己的AbstractConverter,请在下面找到它: 它有一些适合我的限制(可能不适合您)。
样品使用
public class MyConverter extends AbstractListConverter<ClassX,ClassY>{
public MyConverter(){ super(ClassX.class, ClassY.class);}
@Override
protected boolean sameId(ClassX o1, ClassY o2) {
return // your custom comparison here... true means the o2 and o1 can update each other.
}
}
mapper.xml中的声明
<mapping>
<class-a>x.y.z.AClass</class-a>
<class-b>a.b.c.AnotherClass</class-b>
<field custom-converter="g.e.MyConverter">
<a>ListField</a>
<b>OtherListField</b>
</field>
</mapping>
public abstract class AbstractListConverter<A, B> implements MapperAware, CustomConverter {
private Mapper mapper;
private Class<A> prototypeA;
private Class<B> prototypeB;
@Override
public void setMapper(Mapper mapper) {
this.mapper = mapper;
}
AbstractListConverter(Class<A> prototypeA, Class<B> prototypeB) {
this.prototypeA = prototypeA;
this.prototypeB = prototypeB;
}
@Override
public Object convert(Object destination, Object source, Class<?> destinationClass, Class<?> sourceClass) {
if (destinationClass == null || sourceClass == null || source == null) {
return null;
}
if (List.class.isAssignableFrom(sourceClass) && List.class.isAssignableFrom(destinationClass)) {
if (destination == null || ((List) destination).size() == 0) {
return produceNewList((List) source, destinationClass);
}
return mergeList((List) source, (List) destination, destinationClass);
}
throw new Error("This specific mapper is only to be used when both source and destination are of type java.util.List");
}
private boolean same(Object o1, Object o2) {
if (prototypeA.isAssignableFrom(o1.getClass()) && prototypeB.isAssignableFrom(o2.getClass())) {
return sameId((A) o1, (B) o2);
}
if (prototypeB.isAssignableFrom(o1.getClass()) && prototypeA.isAssignableFrom(o2.getClass())) {
return sameId((A) o2, (B) o1);
}
return false;
}
abstract protected boolean sameId(A o, B t);
private List mergeList(List source, List destination, Class<?> destinationClass) {
return (List)
source.stream().map(from -> {
Optional to = destination.stream().filter(search -> same(from, search)).findFirst();
if (to.isPresent()) {
Object ret = to.get();
mapper.map(from, ret);
return ret;
} else {
return create(from);
}
}
).collect(Collectors.toList());
}
private List produceNewList(List source, Class<?> destinationClass) {
if (source.size() == 0) return source;
return (List) source.stream().map(o -> create(o)).collect(Collectors.toList());
}
private Object create(Object o) {
if (prototypeA.isAssignableFrom(o.getClass())) {
return mapper.map(o, prototypeB);
}
if (prototypeB.isAssignableFrom(o.getClass())) {
return mapper.map(o, prototypeA);
}
return null;
}
}