用于任意 XML 的 JAXB @XmlAdapter [英] JAXB @XmlAdapter for arbitrary XML

查看:26
本文介绍了用于任意 XML 的 JAXB @XmlAdapter的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个 org.w3c.dom.Element,我从我的 XmlAdapter 返回一个自定义 @XmlElement 并且我'我想将它作为 JAXB 对象的一部分作为任意 XML 包含(我知道我必须手工制作 XSD).但是,JAXB 抱怨

I have a org.w3c.dom.Element that I'm returning from my XmlAdapter for a custom @XmlElement and I'd like to include it as part of a JAXB object as arbitrary XML (I'm aware I'll have to hand-craft the XSD). However, JAXB complains with

org.w3c.dom.Element is an interface, and JAXB can't handle interfaces.

显然 w3c XML 类型是 Java 不支持类型,这是一种耻辱.但除此之外,当我使用显然受支持的 javax.xml.transform.Result 时,我遇到了同样的错误.

Apparently the w3c XML types are not supported as Java types, which is a shame. But further than this, I get the same error when I use javax.xml.transform.Result which is apparently supported.

如何在 JAXB 中包含任意 XML 元素作为元素?

注意:根据 https://forums.oracle.com/thread/1668210 我也试过

Note: as per https://forums.oracle.com/thread/1668210 I've also tried

MessageFactory factory = MessageFactory.newInstance();
message = factory.createMessage();          
SOAPElement element = message.getSOAPBody().addDocument(doc);

但这也给出了同样的错误.

but that is also giving the same error.

推荐答案

TL;DR

您可以使用 XmlAdapter 将域对象转换为 org.w3c.dom.Element 的实例,只要您将值类型指定为 对象(不是Element).

TL;DR

You can have an XmlAdapter that converts you domain object to an instance of org.w3c.dom.Element as long as you specify the value type as Object (not Element).

下面是一个完整的例子.

Below is a full example.

java.lang.Object 类型的字段/属性会将未知内容保留为 DOM 节点.您可以通过将 XmlAdapter 中的值类型指定为 Object 来在您的用例中利用这一点.您需要确保从 marshal 方法返回的根元素与 @XmlElement 注释定义的字段/属性匹配.

A field/property of type java.lang.Object will keep unknown content as DOM nodes. You can leverage this in your use case by specifying the value type in your XmlAdapter as Object. You will need to ensure that the root element returned from the marshal method matches the field/property as defined by the @XmlElement annotation.

import javax.xml.bind.annotation.adapters.XmlAdapter;
import javax.xml.parsers.*;
import org.w3c.dom.*;

public class BarAdapter extends XmlAdapter<Object, Bar>{

    private DocumentBuilder documentBuilder;

    public BarAdapter() {
        try {
            DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
            documentBuilder = dbf.newDocumentBuilder();
        } catch(Exception e) {
            // TODO - Handle Exception
        }
    }

    @Override
    public Bar unmarshal(Object v) throws Exception {
        Bar bar = new Bar();
        Element element = (Element) v;
        bar.value = element.getTextContent();
        return bar;
    }

    @Override
    public Object marshal(Bar v) throws Exception {
        Document document = documentBuilder.newDocument();
        Element root = document.createElement("bar");
        root.setTextContent(v.value);
        return root;
    }

}

Java 模型

Foo

@XmlJavaTypeAdapter注解用于引用XmlAdapter.

import javax.xml.bind.annotation.*;
import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;

@XmlRootElement
@XmlAccessorType(XmlAccessType.FIELD)
public class Foo {

    @XmlJavaTypeAdapter(BarAdapter.class)
    private Bar bar;

}

条形

import javax.xml.bind.annotation.*;

@XmlAccessorType(XmlAccessType.FIELD)
public class Bar {

    String value;

}

演示代码

演示

由于创建 DocumentBuilderFactory 需要成本,因此我们可以通过在 Marshaller 上设置实例来利用 JAXB 处理 XmlAdapter 的有状态实例的能力.

Since there is a cost to creating the DocumentBuilderFactory we can leverage JAXB's ability to handle stateful instances of XmlAdapter by setting an instance on the Marshaller.

import java.io.File;
import javax.xml.bind.*;

public class Demo {

    public static void main(String[] args) throws Exception {
        JAXBContext jc = JAXBContext.newInstance(Foo.class);

        Unmarshaller unmarshaller = jc.createUnmarshaller();
        File xml = new File("src/forum18272059/input.xml");
        Foo foo = (Foo) unmarshaller.unmarshal(xml);

        Marshaller marshaller = jc.createMarshaller();
        marshaller.setAdapter(new BarAdapter());
        marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
        marshaller.marshal(foo, System.out);
    }

}

input.xml/输出

<?xml version="1.0" encoding="UTF-8"?>
<foo>
    <bar>Hello World</bar>
</foo>

这篇关于用于任意 XML 的 JAXB @XmlAdapter的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆