我编写了一个 JAXB 映射,它将子列表存储在 LinkedHashMap<String, Object>
的根元素内。而不是Collection<Object>
通过特定的 XmlJavaTypeAdapter
维护。下面是一个示例:
@XmlRootElement public class Parent { @XmlJavaTypeAdapter(ListToMapAdapter.class) @XmlElement private LinkedHashMap<String, Child> children; ... }
key 是根据子标签的属性构建的(例如 <child id="key">
给出 Map.Entry<String, Child>
像 {key => child}
。
我的一位同事说它的设计很糟糕,并且这个 Map
应该位于负责解码 XML 的对象中。我不同意他的观点。以下是这种方法的一些优点和缺点。您认为哪种设计最好?您认为哪些优点和缺点可以结束辩论?
此设计的目标:
Map
能够使用标准(我的示例中的键)有效地搜索子项,而不是通过集合上的迭代进行搜索。
优点:
- 搜索和过滤子列表的责任位于最近的对象,父对象负责检索和过滤其子对象,
- 大楼
Map
解码时由 JAXB 自动生成:优雅、高效,并且避免构建Map
在编码(迭代)后对列表进行后处理, - 不同阅读器中的同一对象仍然具有过滤其子对象的能力,
- 主观,这确实是一个很好的方法:),
- 如果
@XmlJavaTypeAdapter
存在,部分是为了这个(网上有很多这样的示例)。
缺点(有些来 self 的同事):
- JAXB 将代码限制为具体实现而不是接口(interface):无法声明
Map<String, Child>
在我的示例中(在解码时不能由 JAXB 实例化), - 也许(这是我同事的论点),具有这种行为的不是映射对象(根据他的说法是简单的 POJO)的角色,
-
@XmlJavaTypeAdapter
仅旨在将简单对象转换为特定类型:xs:date
到乔达时间Calendar
例如。
提前感谢您的 2 美分。
最佳答案
我总是建议人们为他们的应用程序设计最好的模型。然后让 JAXB 处理将其映射到 XML 的困难。在这种情况下,如果父级拥有子级映射是有意义的,那么无论如何都要以这种方式建模。 JAXB 确实对 Map 有一些支持,但是对于您描述的 XML 表示,您将需要使用 XmlAdapter。欲了解更多信息,请参阅:
所有的优点似乎都是合理的。所有缺点均无效:
- 从上面的示例中可以看出,使用 @XmlJavaTypeAdaper 时,您的属性不限于 Map 的具体实现。
- XmlAdapter 位于 POJO 模型外部,因此该模型没有往返于 map 行为的列表。
- XmlAdapter 旨在囊括所有难以映射的用例。它不仅限于简单的对象。一个常见的用例是映射 Map 实例。
如果您想消除包装器元素,则可以在 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;
}
}
更多信息请参见:
关于java - 列表 : pros/cons of this design pattern 中的 JAXB XmlJavaTypeAdapter 映射,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3790487/