列表中的JAXB XmlJavaTypeAdapter映射:此设计模式的优点/缺点
我编写了一个JAXB映射,它将子列表存储在列表中的JAXB XmlJavaTypeAdapter映射:此设计模式的优点/缺点,java,design-patterns,map,jaxb,Java,Design Patterns,Map,Jaxb,我编写了一个JAXB映射,它将子列表存储在LinkedHashMap的根元素中,而不是通过特定的XmlJavaTypeAdapter维护的集合中。以下是一个样本: @XmlRootElement public class Parent { @XmlJavaTypeAdapter(ListToMapAdapter.class) @XmlElement private LinkedHashMap<String, Child> children; ...
LinkedHashMap
的根元素中,而不是通过特定的XmlJavaTypeAdapter
维护的集合中。以下是一个样本:
@XmlRootElement
public class Parent {
@XmlJavaTypeAdapter(ListToMapAdapter.class)
@XmlElement
private LinkedHashMap<String, Child> children;
...
}
@XmlRootElement
公共类父类{
@XmlJavaTypeAdapter(ListToMapAdapter.class)
@XmlElement
私有链接SHMAP儿童;
...
}
键是根据子标记的属性构建的(例如,
给出一个映射。条目
如{key=>child}
)
我的一位同事说它的设计很糟糕,而且这个映射应该由负责对XML进行解密的对象负责。我不同意他的观点。下面是这种方法的一些优缺点。你认为哪种设计最好?你看到了哪些优缺点来完成这场辩论
此设计的目标:
Map
提供了使用条件(我的示例中的键)高效搜索子项的能力,而不是在集合上进行迭代搜索
优点:
- 负责搜索和筛选子列表位于距离对象最近的位置,父对象负责检索和筛选其子对象
- 当解组时,JAXB会自动生成
映射图
:优雅、高效且在umarshalling(迭代)后通过列表的后处理避免生成映射
- 不同读者中的同一对象仍然具有过滤其子对象的能力
- 主观上,这确实是一种很好的方法:)
- 如果
@XmlJavaTypeAdapter
存在,部分原因在于此(网络上有大量的示例)
缺点(一些来自我的同事):
- JAXB将代码限制为具体实现而不是接口:无法在我的示例中声明
Map
(在解组时JAXB不可实例化)
- 也许(这是我同事的观点),有这样的行为并不是映射对象的角色(他认为是简单的POJO)
@XmlJavaTypeAdapter
仅用于将简单对象转换为特定类型:xs:date
例如转换为Joda timeCalendar
提前谢谢你的2美分。我一直建议人们为他们的应用设计最好的型号。然后让JAXB处理将其映射到XML的困难。在这种情况下,如果父母有一张孩子的地图是有意义的,那么无论如何,用这种方式对它进行建模。JAXB确实对Map有一些支持,但对于您描述的XML表示,您将需要使用XmlAdapter。有关更多信息,请参阅:
所有的专业人士似乎都很合理。以下所有条件均无效:
- 从上面的示例可以看出,当使用@XmlJavaTypeAdaper时,您的属性并不局限于Map的具体实现
- XmlAdapter位于POJO模型的外部,因此该模型没有列表到/从映射行为
- 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;
}
}
import java.util.HashMap;
导入java.util.Map;
导入javax.xml.bind.annotation.*;
导入javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
导入org.eclipse.persistence.oxm.annotations.XmlPath;
@XmlRootElement
@XmlAccessorType(XmlAccessType.FIELD)
公开课Foo{
@XmlJavaTypeAdapter(MyMapAdapter.class)
@XmlPath(“.”)
Map Map=newhashmap();
公共地图getMap(){
返回图;
}
公共无效集合映射(映射映射){
this.map=map;
}
}
有关更多信息,请参阅:
谢谢你的精彩报道。我现在确信我的方式是好的方式,我的同事需要修正他的观点:-)
我已经看过你的博客了。事实上,我已经成功地通过接口上的适配器实现了解组。我不知道我为什么在这一点上失败了
仍然存在一个问题,我仍然无法映射未嵌套在元素包装器中的元素列表,如下所述:。就像您和JavaDoc中解释的一样,我需要在您的示例中使用一个中间包装器对象(
MyMapType
)。是否可以直接创建XmlJavaTypeAdapter
,而不是将列表
放在列表包装器
中?我肯定会以S.O.的方式单独发布这个问题。我已经编辑了“按答案”以包含一些关于如何消除包装器元素的细节。另外,由于您不熟悉堆栈溢出,一旦您找到问题的答案,惯例是将其标记为已接受的答案。你也可以投票选出任何你觉得有用的答案。谢谢。我正在使用JAXB RI实现,但我没有自由使用另一个(enterpise选择)。