2010-11-10 17 views
12

Tôi có một đối tượng value, một loại nào đó, hoặc là @XmlRootElement-đã được báo cáo hay không. Tôi muốn so sánh nó thành XML:Làm thế nào để sắp xếp một đối tượng thông qua JAXB mà không cần bất kỳ thông tin nào về nó?

String value1 = "test"; 
assertEquals("<foo>test</foo>", toXml("foo", value1)); 
// ... 
@XmlRootElement 
class Bar { 
    public String bar = "test"; 
} 
assertEquals("<foo><bar>test</bar></foo>", toXml("foo", new Bar())); 

Tôi có thể làm điều đó với các tiện ích hiện có của JAXB hay tôi nên tạo một số phân tích tùy chỉnh?

Trả lời

21

Bạn có thể tận dụng JAXBIntrospector phải làm như sau:

import javax.xml.bind.JAXBContext; 
import javax.xml.bind.JAXBElement; 
import javax.xml.bind.JAXBIntrospector; 
import javax.xml.bind.Marshaller; 
import javax.xml.bind.annotation.XmlRootElement; 
import javax.xml.namespace.QName; 

public class Demo { 


    public static void main(String[] args) throws Exception { 
     Object value = "Hello World"; 
     //Object value = new Bar(); 

     JAXBContext jc = JAXBContext.newInstance(String.class, Bar.class); 
     JAXBIntrospector introspector = jc.createJAXBIntrospector(); 
     Marshaller marshaller = jc.createMarshaller(); 
     if(null == introspector.getElementName(value)) { 
      JAXBElement jaxbElement = new JAXBElement(new QName("ROOT"), Object.class, value); 
      marshaller.marshal(jaxbElement, System.out); 
     } else { 
      marshaller.marshal(value, System.out); 
     } 
    } 

    @XmlRootElement 
    public static class Bar { 

    } 

} 

Với đoạn mã trên khi JAXBElement được marshalled nó sẽ được đủ điều kiện với một xsi: thuộc tính type tương ứng với kiểu lược đồ thích hợp:

<ROOT 
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
    xmlns:xs="http://www.w3.org/2001/XMLSchema" xsi:type="xs:string">Hello World</ROOT> 

Để loại bỏ chứng chỉ bạn chỉ có thể thay đổi dòng tạo ra JAXBElement thành:

JAXBElement jaxbElement = new JAXBElement(new QName("ROOT"), value.getClass(), value); 

này sẽ dẫn đến việc XML sau:

<ROOT>Hello World</ROOT> 
+0

Hoạt động hoàn hảo! Có lẽ bạn biết cách loại bỏ thuộc tính 'xsi: type'? Đây là những gì tôi nhận được cho một đối tượng 'String':' (239) 555 2390 ' – yegor256

+0

@Vincenzo Tôi đã cập nhật câu trả lời của mình với các chi tiết về cách loại bỏ thuộc tính xsi: type. –

+0

@BlaiseDoughan vui lòng xem vấn đề này: http://stackoverflow.com/questions/26816798/objectfactory-methods-generated-by-jaxb – Spartan

0

Nếu nó không được chú thích với @XmlRootElement, thì JAXB không có đủ thông tin để so sánh nó. Trước tiên, bạn cần bọc nó vào một số JAXBElement.

Bạn có thể làm một số yêu thích phản chiếu 'để tìm hiểu cách quấn đối tượng vào JAXBElement thích hợp không?

+1

xem câu trả lời của tôi để xem cách JAXBIntrospector có thể được sử dụng để tránh bất kỳ cuộc gọi phản chiếu nào. –

3

Dưới đây là cách soái value1, là String. Bạn có thể vượt qua yourObject.getClass() để các nhà xây dựng JAXBElement, và value1:

try { 
    JAXBContext jc = JAXBContext.newInstance(); 
    Marshaller m = jc.createMarshaller(); 
    String value1 = "test"; 
    JAXBElement jx = new JAXBElement(new QName("foo"), value1.getClass(), value1); 
    m.marshal(jx, System.out); 
} catch (JAXBException ex) { 
    ex.printStackTrace(); 
} 

này hoạt động mà không sử dụng @XmlRootElement. Kết quả của đoạn mã trên là:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?><foo>test</foo> 

Về phía khác, điều này sẽ không làm việc với một đối tượng Bar: javax.xml.bind.JAXBException: myPackage.Bar is not known to this context. Tuy nhiên, bạn có thể nhận giá trị từ bên trong Bar và tạo JAXBElement với điều đó, không phải chính đối tượng đó.

1

tôi không tìm thấy bất kỳ cách chung chung tốt để làm việc đó. Đây là giải pháp chung của tôi.

import javax.xml.bind.*; 
import javax.xml.namespace.QName; 
import javax.xml.transform.stream.StreamSource; 
import java.io.StringReader; 
import java.io.StringWriter; 

public class XMLConverter { 

    /** 
    * Serialize object to XML string 
    * @param object object 
    * @param <T> type 
    * @return 
    */ 
    public static <T> String marshal(T object) { 
     try { 
      StringWriter stringWriter = new StringWriter(); 
      JAXBContext jc = JAXBContext.newInstance(object.getClass()); 
      Marshaller m = jc.createMarshaller(); 
      m.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE); 

      QName qName = new QName(object.getClass().getCanonicalName(), object.getClass().getSimpleName()); 
      JAXBElement<T> root = new JAXBElement(qName, object.getClass(), object); 

      m.marshal(root, stringWriter); 
      return stringWriter.toString(); 
     } catch (Exception e) { 
      // log the exception 
     } 
     return null; 
    } 

    /** 
    * Deserialize XML string back to object 
    * @param content XML content 
    * @param clasz class 
    * @param <T> type 
    * @return 
    */ 
    public static <T> T unMarshal(final String content, final Class<T> clasz) { 
     try { 
      JAXBContext jc = JAXBContext.newInstance(clasz); 
      Unmarshaller u = jc.createUnmarshaller(); 
      return u.unmarshal(new StreamSource(new StringReader(content)), clasz).getValue(); 
     } catch (Exception e) { 
      // log the exception 
     } 
     return null; 
    } 

} 
Các vấn đề liên quan