推土机映射/更新集合

时间:2014-03-05 19:05:33

标签: java rest dozer

我正在尝试将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;
}

3 个答案:

答案 0 :(得分:4)

我遇到了同样的问题,我解决了这个问题:

推土机使用contains来确定成员是否在集合中 您应该实施hashCode,以便"contains"能够正常运作。

您可以在以下文档页面中看到: http://dozer.sourceforge.net/documentation/collectionandarraymapping.html 下:“累积与非累积列表映射(双向)

祝你好运!

答案 1 :(得分:1)

完成自定义映射。

答案 2 :(得分:0)

我确实做了自己的AbstractConverter,请在下面找到它: 它有一些适合我的限制(可能不适合您)。

  • 将基于“ sameId”实现进行更新
  • 将删除孤儿(目的地中不在源中的元素)。
  • 仅在列表上可用(足以满足我的需求)。
  • 虽然转换器将管理更新对象映射的决策,但是将对象委派回Dozer,因此您无需实现列表中元素的映射

样品使用

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;
    }
}