目标是使用JAXB
生成以下XML<foo>
<bar>string data</bar>
<bar>binary data</bar>
</foo>
是否有解决方法允许通用 @XmlValue
字段(我需要存储byte[]
和String
数据)?以下是我的愿望:
@XmlRootElement
public class Foo {
private @XmlElement List<Bar> bars;
}
@XmlRootElement
public class Bar<T> {
private @XmlValue T value; // (*)
}
但是我得到了这个例外
(*)IllegalAnnotationException:
@ XmlAttribute / @ XmlValue需要引用映射到XML格式的Java类型。
答案 0 :(得分:8)
您可以针对此用例使用XmlAdapter
而不是@XmlValue
:
<强> BarAdapter 强>
package forum8807296;
import javax.xml.bind.annotation.adapters.XmlAdapter;
public class BarAdapter extends XmlAdapter<Object, Bar<?>> {
@Override
public Bar<?> unmarshal(Object v) throws Exception {
if(null == v) {
return null;
}
Bar<Object> bar = new Bar<Object>();
bar.setValue(v);
return bar;
}
@Override
public Object marshal(Bar<?> v) throws Exception {
if(null == v) {
return null;
}
return v.getValue();
}
}
<强>富强>
XmlAdapter
使用bars
注释与@XmlJavaTypeAdapter
属性相关联:
package forum8807296;
import java.util.List;
import javax.xml.bind.annotation.*;
import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
@XmlRootElement
public class Foo {
private List<Bar> bars;
@XmlElement(name="bar")
@XmlJavaTypeAdapter(BarAdapter.class)
public List<Bar> getBars() {
return bars;
}
public void setBars(List<Bar> bars) {
this.bars = bars;
}
}
<强>酒吧强>
package forum8807296;
public class Bar<T> {
private T value;
public T getValue() {
return value;
}
public void setValue(T value) {
this.value = value;
}
}
<强>演示强>
您可以使用以下演示代码测试此示例:
package forum8807296;
import java.util.ArrayList;
import java.util.List;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.Marshaller;
public class Demo {
public static void main(String[] args) throws Exception {
JAXBContext jc = JAXBContext.newInstance(Foo.class);
Foo foo = new Foo();
List<Bar> bars = new ArrayList<Bar>();
foo.setBars(bars);
Bar<String> stringBar = new Bar<String>();
stringBar.setValue("string data");
bars.add(stringBar);
Bar<byte[]> binaryBar = new Bar<byte[]>();
binaryBar.setValue("binary data".getBytes());
bars.add(binaryBar);
Marshaller marshaller = jc.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
marshaller.marshal(foo, System.out);
}
}
<强>输出强>
请注意输出如何包含xsi:type
属性以保留值的类型。您可以通过xsi:type
返回XmlAdapter
而不是String
来消除Object
属性,如果您这样做,则需要处理从String
到<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<foo>
<bar xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xs="http://www.w3.org/2001/XMLSchema" xsi:type="xs:string">string data</bars>
<bar xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xs="http://www.w3.org/2001/XMLSchema" xsi:type="xs:base64Binary">YmluYXJ5IGRhdGE=</bars>
</foo>
的转换适用于解组操作的类型:
{{1}}
答案 1 :(得分:4)
我无法让@XmlValue
正常工作,因为我一直都有NullPointerException
- 不知道为什么。我想出了类似下面的东西。
完全删除您的Bar
课程,因为您希望它能够包含任何内容,您可以使用Object
代表它。
@XmlRootElement(name = "foo", namespace = "http://test.com")
@XmlType(name = "Foo", namespace = "http://test.com")
public class Foo {
@XmlElement(name = "bar")
public List<Object> bars = new ArrayList<>();
public Foo() {}
}
在没有告诉JAXB您的类型使用哪个名称空间的情况下,bar
中的每个foo
元素都包含单独的名称空间声明和内容 - package-info.java
并且所有名称空间内容仅用于幻想目的。
@XmlSchema(attributeFormDefault = XmlNsForm.QUALIFIED,
elementFormDefault = XmlNsForm.QUALIFIED,
namespace = "http://test.com",
xmlns = {
@XmlNs(namespaceURI = "http://test.com", prefix = ""),
@XmlNs(namespaceURI = "http://www.w3.org/2001/XMLSchema-instance", prefix = "xsi"),
@XmlNs(namespaceURI = "http://www.w3.org/2001/XMLSchema", prefix = "xs")})
package test;
import javax.xml.bind.annotation.XmlNs;
import javax.xml.bind.annotation.XmlNsForm;
import javax.xml.bind.annotation.XmlSchema;
运行这个简单的测试会传出类似于XML片段的内容。
public static void main(String[] args) throws JAXBException {
JAXBContext context = JAXBContext.newInstance(Foo.class);
Foo foo = new Foo();
foo.bars.add("a");
foo.bars.add("b".getBytes());
Marshaller marshaller = context.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);
marshaller.marshal(foo, System.out);
}
输出:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<foo xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns="http://test.com" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<bar xsi:type="xs:string">a</bar>
<bar xsi:type="xs:base64Binary">Yg==</bar>
</foo>
答案 2 :(得分:0)
你有没有理由不用你的byte []构造一个String?你真的需要通用吗?
答案 3 :(得分:0)
我通常使用的技巧是使用您想要的类型创建模式,然后使用xjc生成Java类并查看注释的使用方式。 :)我相信在XML模式中,byte []的正确类型映射是'base64Binary',所以创建这样的模式:
<?xml version="1.0" encoding="UTF-8"?>
<schema xmlns="http://www.w3.org/2001/XMLSchema" targetNamespace="http://www.example.org/NewXMLSchema" xmlns:tns="http://www.example.org/NewXMLSchema" elementFormDefault="qualified">
<element name="aTest" type="base64Binary"></element>
</schema>
并运行xjc我们将得到以下代码生成:
@XmlElementDecl(namespace = "http://www.example.org/NewXMLSchema", name = "aTest")
public JAXBElement<byte[]> createATest(byte[] value) {
return new JAXBElement<byte[]>(_ATest_QNAME, byte[].class, null, ((byte[]) value));
}
答案 4 :(得分:0)
https://stackoverflow.com/a/3074027/1851289可能是重复的,但答案还有其他两个选项。