代码之家  ›  专栏  ›  技术社区  ›  Doc Davluz

列表中的JAXB xmljavatypeadapter映射:此设计模式的优点/缺点

  •  2
  • Doc Davluz  · 技术社区  · 14 年前

    我编写了一个JAXB映射,它将子列表存储在根元素中 LinkedHashMap<String, Object> 而不是 Collection<Object> 通过特定的 XmlJavaTypeAdapter . 以下为样品:

    @XmlRootElement
    public class Parent {
        @XmlJavaTypeAdapter(ListToMapAdapter.class)
        @XmlElement
        private LinkedHashMap<String, Child> children;
    
        ...
    }

    键是根据子标记的属性(例如 <child id="key"> 给出一个 Map.Entry<String, Child> 喜欢 {key => child} .

    我的一个同事说它的设计不好,而且这个 Map 应该在对象中负责XML的解组。我不同意他。下面是这种方法的一些利弊。你认为哪种设计最好?你看到了哪些利弊来完成这场辩论?

    本设计的目标:

    • 这个 地图 让他们能够用一个标准(我的样本中的关键)来有效地搜索孩子,而不是在大学里反复搜索。

    赞成的意见:

    • 搜索和过滤子列表的职责在对象的最近位置,父对象负责检索和过滤子列表。
    • 建筑 地图 在解组时由JAXB自动生成:优雅、高效和 保留以避免构建 地图 在umarshalling(迭代)后对列表进行后处理 ,
    • 不同读者的同一个对象仍然具有过滤其子对象的能力,
    • 主观上,这真的是一种很好的方法。
    • 如果 @XmlJavaTypeAdapter 存在,部分原因在于此(网络上有很多这样的例子)。

    欺骗 (有些来自我的同事) :

    • JAXB限制代码到具体实现(而不是接口)的约束:无法声明 Map<String, Child> 在我的示例中(解组时JAXB不能实例化),
    • 也许(这是我同事的论点),映射对象(他认为简单的pojo)的作用并不是具有这种行为,
    • @xmljavatypeadapter 仅用于将简单对象转换为特定类型: xs:date 到Joda时代 Calendar 例如。

    提前谢谢你的2美分。

    2 回复  |  直到 14 年前
        1
  •  6
  •   bdoughan    14 年前

    我总是建议人们为他们的应用设计最好的模型。然后让JAXB处理将其映射到XML的困难。在这种情况下,如果父母有一个孩子的地图是有意义的,那么无论如何都要用这种方式建模。JAXB确实对map有一些支持,但是对于您描述的XML表示,您将需要使用一个XML适配器。有关详细信息,请参阅:

    所有的职业似乎都是合理的。所有缺点都无效:

    • 从上面的示例中可以看到,当使用@xmljavatypeadaper时,您的属性不限于映射的具体实现。
    • XMLadapter是POJO模型的外部,因此该模型没有列表到/从映射行为。
    • 对于任何难以映射的用例来说,XMLadapter都是一个“一网打尽”的工具。它不仅限于简单对象。一个常见的用例是映射映射的实例。

    如果希望消除包装元素,那么可以在moxy jaxb实现中使用@xmlpath扩展。我博客文章中的foo类会稍微修改一下:

    import java.util.HashMap;
    import java.util.Map;
    import javax.xml.bind.annotation.*;
    import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
    import org.eclipse.persistence.oxm.annotations.XmlPath;
    
    @XmlRootElement
    @XmlAccessorType(XmlAccessType.FIELD)
    public class Foo {
        @XmlJavaTypeAdapter(MyMapAdapter.class)
        @XmlPath(".")
        Map<Integer, String> map = new HashMap<Integer, String>();
    
        public Map<Integer, String> getMap() {
            return map;
        }
    
        public void setMap(Map<Integer, String> map) {
            this.map = map;
        }
    }
    

    有关详细信息,请参阅:

        2
  •  1
  •   Doc Davluz    14 年前

    谢谢你的精彩表演。我现在确信我的方法是好的,我的同事需要修改他的观点。

    我看过你的博客。实际上,我已经成功地实现了在接口上使用适配器取消标记。不知道我为什么要在这一点上失败。

    还有一个问题,我仍然无法实现映射未嵌套在元素包装器中的元素列表,如下所述: http://weblogs.java.net/blog/2005/04/22/xmladapter-jaxb-ri-ea . 像您和javadoc中解释的一样,我需要使用一个中间包装器对象( MyMapType )在你的例子中。是否可以直接创建 XmlJavaTypeAdapter<List<WrappedObject>, Map<String, WrappedObject>> 而不是把 List 里面 ListWrapper<WrappedObject> ?我当然会以S.O.的方式发表一篇关于这个问题的独立文章。