2012-01-10 27 views
8

Mục đích là để tạo ra XML sau đây với JAXBJAXB generic @XmlValue

<foo> 
    <bar>string data</bar> 
    <bar>binary data</bar> 
</foo> 

Có một cách giải quyết để cho phép generic@XmlValue lĩnh vực (Tôi cần phải lưu trữ byte[]String dữ liệu)? Dưới đây là những gì tôi mong muốn:

@XmlRootElement 
public class Foo { 
    private @XmlElement List<Bar> bars; 
} 

@XmlRootElement 
public class Bar<T> { 
    private @XmlValue T value; // (*) 
} 

Nhưng tôi nhận được ngoại lệ này

(*) IllegalAnnotationException:
@ XmlAttribute/@ XmlValue cần phải tham khảo một loại Java mà các bản đồ vào văn bản trong XML.

Trả lời

8

Bạn có thể tận dụng một XmlAdapter đối với trường hợp sử dụng này thay vì @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

Các XmlAdapter được kết hợp với bars tài sản bằng cách sử dụng @XmlJavaTypeAdapter chú thích:

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

Bạn có thể kiểm tra ví dụ này bằng cách sử dụng sau đây cá tuyết giới thiệu e:

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

Lưu ý cách đầu ra bao gồm các thuộc tính xsi:type để bảo tồn các loại giá trị. Bạn có thể loại bỏ các thuộc tính xsi:type bằng cách XmlAdapter của bạn trở lại String thay vì Object, nếu bạn làm điều này, bạn sẽ cần xử lý việc chuyển đổi từ String để loại thích hợp cho mình cho các hoạt động unmarshal:

<?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> 
0

Có lý do nào bạn không chỉ đơn giản là xây dựng một chuỗi với byte của bạn []? Bạn có thực sự cần một chung chung?

+0

Điều đó sẽ yêu cầu tôi chuyển đổi dữ liệu nhị phân mờ thành Chuỗi, ví dụ: tôi phải mã hóa thủ công dữ liệu đó thành ví dụ: hexBinary hoặc base64. Nhưng có, đó là những gì tôi đang sử dụng như một cách giải quyết. –

+0

Bạn có đang sử dụng thuật toán mã hóa của riêng mình không? Nó sẽ được khá đau nếu bạn sử dụng [apache commons encoder] (http://commons.apache.org/codec/apidocs/org/apache/commons/codec/binary/Base64.html). –

+0

Tôi đang sử dụng [HexBinaryAdapter] (http://docs.oracle.com/javaee/5/api/javax/xml/bind/annotation/adapters/HexBinaryAdapter.html) mà alt. lớp cơ sở commons base64, cả hai đều là một lớp lót đẹp. –

4

Tôi không thể nhận được @XmlValue làm việc như tôi luôn luôn có NullPointerException trên đường đi — không chắc chắn lý do. Tôi đã đưa ra một cái gì đó như sau để thay thế.

Thả toàn bộ lớp học Bar vì bạn muốn nó có thể chứa bất kỳ thứ gì bạn chỉ cần thể hiện nó với 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() {} 
} 

Không nói JAXB mà không gian tên loại của bạn đang sử dụng mỗi bar yếu tố bên trong một foo sẽ chứa các khai báo không gian tên riêng biệt và các công cụ-the package-info.java và tất cả những thứ namespace chỉ phục vụ duy nhất fancification mục đích.

@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; 

Chạy thử nghiệm đơn giản này sẽ tạo ra một thứ gì đó tương tự như đoạn mã XML của bạn.

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); 
} 

Output:

<?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> 
+1

+1 - Đây là một ví dụ về cách bạn có thể sử dụng một 'XmlAdapter' để làm điều tương tự, nhưng giữ cho lớp' Bar': http://stackoverflow.com/a/8901997/383861 –

+0

@BlaiseDoughan Cảm ơn bạn đã làm rõ! –

0

Bí quyết tôi m thường sử dụng là tạo lược đồ với các kiểu bạn muốn và sau đó sử dụng xjc để tạo các lớp Java và xem cách sử dụng các chú thích. :) Tôi tin vào lược đồ XML loại bản đồ thích hợp cho byte [] là 'base64Binary', vì vậy tạo ra sơ đồ như thế này:

<?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> 

và chạy XJC chúng tôi sẽ nhận sau mã được tạo:

@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)); 
}