如何使用JAXB附加外部生成的XML而不是POJO的变量值



如何使用JAXB附加外部生成的XML而不是POJO的变量值?

我的具体数据结构如下:

Map<CustomEnum, CustomList>

到目前为止,我使用实用程序类来生成此结构中数据的xml表示。它使用SAX生成xml输出。

为了进一步阅读,CustomEnumjava enumCustomList扩展了java.util.List,其实现是通过factory methods获得的。它只允许包含实现specific interface的对象。它们的实现也是通过factory methods获得的,主要是基于特定的条件。我没有修改这些类的权限。

这就是为什么通过jaxb转换这个结构在我看来相当复杂,但还有许多其他原因,为什么该实用程序类被写入(有很多条件求值,例如,如果某些值不为空,则从其他值获取数据,否则提供默认值,等等)

现在,这个数据结构需要作为更大结构的一部分,基于POJO,并使用jaxb转换为xml。

类似这样的东西:

public class CustomPojo {
...
private String data;
...
private Map<CustomEnum, CustomList> items;
}

XML输出应为:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<rootElement>
<data> value </data>
...
<items>  
<!-- generated xml from my utility class -->
</items>
</rootElement>

我需要的是,无论jaxb-marshaller在哪里找到Map类型的pojo成员变量,而不是试图从该变量生成xml,插入我的实用程序类生成的xml。

所以我想出了实现自定义适配器的想法:

public class CustomAdapter extends XmlAdapter<String, Map<CustomEnum, CustomList>> 

将其用作

...
@XmlJavaTypeAdapter(CustomAdapter.class)
private Map<CustomEnum, CustomList> items;

在overridenmarshal方法中,让返回我的实用程序生成的xml。

但它给出了与此类似的输出:

<items>&#xD;&lt;item itemType="1"&gt;&#xD; ...

因此,正如我所看到的,它是带有xml数据的转义字符串,而不是xml标记树。

我的问题是:有没有办法告诉jaxb不要从属性值生成xml,而是将外部生成的xml作为自己xml的一部分插入?

附言:很抱歉描述太长了,但我想把图片写得尽可能清楚。请注意,我知道这个设计并不理想,但我需要它发挥作用。我正在计划一般的重构,但这似乎是一个很长的机会。

默认情况下,JAXB的编组器实现转义所有字符,即使对于自定义适配器也是如此(因为它们也通过相同的编组器)。防止字符转义的解决方案是覆盖默认机制。因此,我们需要提供一个CharacterEscapeHandler的自定义实现,它在字符转义方面绝对不会起任何作用。JAXB文档中给出了如何做到这一点的说明:

  1. 编写一个实现com.sun.xml.bind.marshaller.CharacterEscapeHandler接口的类
  2. 创建它的新实例
  3. 使用此属性(即com.sun.xml.bind.characterEscapeHandler)将该实例设置为Marshaller

因此,这样的实现看起来像。。。

public class NullCharacterEscapeHandler implements CharacterEscapeHandler {
public NullCharacterEscapeHandler() {
super();
}
public void escape(char[] ch, int start, int length, boolean isAttVal, Writer writer) throws IOException {
// Proxy the characters to the writer, with no encoding escape.
writer.write( ch, start, length );
}
}

并以这种方式使用:

Marshaller m = jcb.createMarshaller();
m.setProperty("com.sun.xml.bind.marshaller.CharacterEscapeHandler",
new NullCharacterEscapeHandler());

这个回复受到了这条stackoverflow线索的极大启发。

最新更新