JAXB通用@XmlValue [英] JAXB generic @XmlValue
问题描述
目标是使用 JAXB 制作以下XML
< foo>
< bar>字符串数据< / bar>
< bar>二进制数据< / bar>
< / foo>
是否有解决方法允许通用 @XmlValue
字段(我需要存储 byte []
和 String
data)?以下是我的愿望:
@XmlRootElement
公共类Foo {
私有@XmlElement列表< Bar> ;酒吧;
}
@XmlRootElement
public class Bar< T> {
private @XmlValue T值; //(*)
}
但是我得到这个异常
$ b $
(*)IllegalAnnotationException:
@ XmlAttribute / @ XmlValue需要引用映射到XML文本的Java类型。
您可以利用 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)抛出Exception {
if(null == v){
return null;
}
Bar< Object> bar = new Bar< Object>();
bar.setValue(v);
返回栏;
}
@Override
public Object marshal(Bar<> v)抛出Exception {
if(null == v){
return空值;
}
return v.getValue();
}
}
Foo
$ b
XmlAdapter
与 bars
属性相关联使用 @XmlJavaTypeAdapter
注解:
package forum8807296;
import java.util.List;
import javax.xml.bind.annotation。*;
import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
@XmlRootElement
公共类Foo {
私人列表< Bar>酒吧;
@XmlElement(name =bar)
@XmlJavaTypeAdapter(BarAdapter.class)
public List< Bar> getBars(){
返回酒吧;
}
public void setBars(List< Bar> bars){
this.bars = bars;
}
}
Bar
package forum8807296;
公开课Bar< T> {
私人T值;
public T getValue(){
返回值;
}
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();
列表< 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 属性来保留值的类型。您可以通过让 XmlAdapter
返回字符串$>来消除
xsi:type
属性c $ c>而不是 Object
,如果你这样做,你需要处理从 String
到相应类型的转换你自己的解组操作:
<?xml version =1.0encoding =UTF-8standalone =yes >?;
< foo>
< bar xmlns:xsi =http://www.w3.org/2001/XMLSchema-instancexmlns:xs =http://www.w3.org/2001/XMLSchemaxsi:type =xs:string>字符串数据< / bars>
< bar xmlns:xsi =http://www.w3.org/2001/XMLSchema-instancexmlns:xs =http://www.w3.org/2001/XMLSchemaxsi:type = XS:base64Binary的 > YmluYXJ5IGRhdGE = LT; /棒>
< / foo>
The goal is to produce the following XML with JAXB
<foo>
<bar>string data</bar>
<bar>binary data</bar>
</foo>
Is there a workaround to allow generic @XmlValue
fields (I need to store byte[]
and String
data)? Below is what I desire:
@XmlRootElement
public class Foo {
private @XmlElement List<Bar> bars;
}
@XmlRootElement
public class Bar<T> {
private @XmlValue T value; // (*)
}
But I get this exception
(*) IllegalAnnotationException:
@XmlAttribute/@XmlValue need to reference a Java type that maps to text in XML.
You could leverage an XmlAdapter
for this use case instead of @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();
}
}
Foo
The XmlAdapter
is associated with the bars
property using the @XmlJavaTypeAdapter
annotation:
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;
}
}
Bar
package forum8807296;
public class Bar<T> {
private T value;
public T getValue() {
return value;
}
public void setValue(T value) {
this.value = value;
}
}
Demo
You can test this example using the following demo code:
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);
}
}
Output
Note how the output includes the xsi:type
attributes to preserve the type of the value. You can eliminate the the xsi:type
attribute by having your XmlAdapter
return String
instead of Object
, if you do this you will need handle the conversion from String
to the appropriate type yourself for the unmarshal operation:
<?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>
这篇关于JAXB通用@XmlValue的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!