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

列表中的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; ...

我编写了一个JAXB映射,它将子列表存储在
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 time
    Calendar

提前谢谢你的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选择)。