JAXB XmlIDREF和地图/列表

时间:2012-08-30 08:37:13

标签: java xml jaxb jersey unmarshalling

我有一个相当复杂的数据结构,我似乎无法正确地解组。

@XmlRootElement
class Tree {
  @XmlID
  private String id;

  @XmlJavaTypeAdapter(type=TreeFooAdapter.class)
  Map<Tree, Foo> fooMap;
}

class Foo {
  @XmlID
  private String id;
}

我有两棵树。两个节点(每个树中一个)可以配对并与Foo的实例相关联。 fooMap用于跟踪给定树节点与其配对的其他节点,以及Foo结果的实例。

TreeFooAdapter非常简单,但请注意它使用ID refs:

public class TreeFooAdapter extends XmlAdapter<TreeFooAdapter.MapType, Map<Tree, Foo>> {
  public static class MapType {
    public static class MapEntry {
      @XmlAttribute
      @XmlIDREF
      public Tree key;
      @XmlAttribute
      @XmlIDREF
      public Foo value;
    }
    // etc...
  }

  // Standard drill for marshal/unmarshal...
}

问题:转发参考不起作用!在解组时,无论哪个树首先出现在XML中,它的fooMap中都会有空键。由于这两棵树相互引用,我无法改变XML的顺序来解决这个问题。

我尝试过一个hack,其中我有一个私有方法来获取/设置List<TreeFooMapEntry>,但它会产生相同的结果。

为什么JAXB在包含在Map或List中时无法处理转发ID引用,我该如何解决?

2 个答案:

答案 0 :(得分:0)

我发现了一个(可怕的,可怕的,丑陋的)解决方法,受到this的启发。我基本上概括了PhoneNumberAdapter类以使用任何东西&#34; Identifiable&#34;,即具有唯一ID(即,Foo和Tree)。我没有一个AdaptedPhoneNumber类,而是有一个ObjectWrapper bean,它将包含被包装的实际对象(第一次遇到时),或者仅包含其ID(在后续遇到时)。 TreeFooAdapter中的MapEntry类,而不是XmlIDREF,而是将我的IdentifiableAdapter指定为XmlJavaTypeAdapter。

这会产生难以理解的,难以理解的XML,但至少它可行。尽管如此,这似乎是JAXB中的一个错误:经过一些痛苦的调试后,我仍然无法弄清楚为什么XmlIDREF在改编的Map类中不起作用。

答案 1 :(得分:0)

我尝试了另一个似乎有效的黑客攻击。诀窍涉及以下内容:

  • 创建一个私有的getter / setter对,将fooMap转换为TreeFooAdapter.MapType
  • 向TreeFooAdapter.MapType添加XmlID,并使用XmlIDREF注释getter
  • 维护TreeFooAdapter.MapType
  • 的静态实例集
  • 编组时,在编组Tree和Foo的所有实例之后,还会编组实例集。

这会产生更清晰的XML:树用fooMaps为简单的IDREF编组,而XML文件的末尾只是一长串的TreeFooAdapter.MapTypes列表,它们本身就是IDREF对的列表。如果你多次封送/解组,你必须小心清理静态实例集。