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

时间:2014-01-14 15:19:22

标签: java xml jaxb

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

我的具体数据结构如下:

Map<CustomEnum, CustomList>

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

如需进一步阅读,CustomEnumjava enumCustomList延伸java.util.List,其实施方式是factory methods。它允许仅包含实现specific interface的对象。它们的实现也是通过factory methods获得的,主要基于特定条件。我没有权限修改任何这些类。

这就是为什么通过jaxb对这个结构进行转换对我来说似乎很复杂,但还有很多其他原因,为什么要编写实用程序类(有很多条件评估,例如,如果某些值不是null,从其他值获取数据,否则提供默认值等。)

现在需要将此数据结构作为更大结构的一部分包含在内,基于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;

并在重写marshal方法中,让我的实用程序生成xml。

但它给出了类似的输出:

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

正如我所看到的,它是使用xml数据而不是xml标签树的转义字符串。

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

P.S。很抱歉有很长的描述,但我想尽可能清晰地拍照。 请注意,我知道这个设计并不理想,但我需要这个才能工作。我正在计划一般的重构,但这似乎是一个很长的镜头。

1 个答案:

答案 0 :(得分:2)

默认情况下,JAXB的marshaller实现会转义所有字符,即使对于自定义适配器也是如此(因为它们也通过相同的marshaller)。防止字符转义的解决方案是覆盖默认机制。所以我们需要提供一个CharacterEscapeHandler的自定义实现,它绝对不会在字符转义方面做任何事情。有关如何操作的说明在JAXB documentation

中给出
  1. 编写一个实现com.sun.xml.bind.marshaller.CharacterEscapeHandler接口的类。
  2. 创建一个新实例。
  3. 使用此属性(即com.sun.xml.bind.characterEscapeHandler)将该实例设置为Marshaller。
  4. 因此,这样的实现看起来像......

    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 thread的极大启发。