【问题标题】:Dozer mapping/updating a collection推土机映射/更新集合
【发布时间】:2014-03-05 19:05:32
【问题描述】:

我正在尝试将 A-DTO 对象映射到 A-DO 对象,每个对象分别具有 T-DTO 和 T-DO 的集合(列表)。我正在尝试在 REST API 的上下文中执行此操作。这是否是一种正确的方法是一个单独的问题 - 我正在解决的问题是更新的情况。基本上,如果 A-DTO 内的某个 T-DTO 发生变化,我希望将该变化映射到 A-DO 内的相应 T-DO。

我在 Dozer 文档中找到了relationship-type="non-cumulative",以便更新集合内的对象(如果存在)。但我最终让 Dozer 将一个新的 T-DO 插入到 A-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;
}

【问题讨论】:

  • 您完全确定您的equalshashcode(如果适用)实现是正确的吗?而且您没有插入新对象?您介意发布您的equals 以及两个对象中的更新内容吗?
  • 感谢您的建议;我认为equals 很好...我已将其添加到问题中。至于更新的内容 - 只有一个 Float 字段。

标签: java rest dozer


【解决方案1】:

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

Dozer 使用contains 来确定成员是否在集合中。
您应该实现hashCode,以便"contains" 能够正常工作。

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

祝你好运!

【讨论】:

    【解决方案2】:

    最后做了一个自定义映射。

    【讨论】:

    • 自定义转换器长什么样子?
    • 哦,伙计,这是几年前 3 个工作 - 抱歉,我不记得了
    【解决方案3】:

    我最终做了自己的 AbstractConverter 请在下面找到它: 它有一些适合我的限制条件(可能不适合你)。

    • 将根据“sameId”实现进行更新
    • 将删除孤儿(来自目标的元素不在源中)。
    • 仅适用于 List(足以满足我的需要)。
    • 虽然转换器将管理更新对象映射的决定,但被委托给 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;
        }
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-05-22
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多