2010-11-10 3 views
12

Ich habe ein Objekt value, das von einem Typ ist, entweder @XmlRootElement -annotated, oder nicht. Ich will es in XML Marschall:Wie man ein Objekt über JAXB ohne jegliche Informationen marshale?

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

Kann ich es mit JAXB bestehenden Einrichtungen zu tun, oder sollte ich einige benutzerdefinierte Analysator erstellen?

Antwort

21

Sie könnten JAXBIntrospector nutzen folgendes zu tun:

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 { 

    } 

} 

Mit dem obigen Code, wenn der JAXBElement vermarshallten ist, wird es mit einem xsi qualifiziert werden: type-Attribut entsprechend dem entsprechenden Schematyp:

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

um die Qualifikation zu beseitigen können Sie einfach die Zeile, die die JAXBElement zu erstellt:

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

Dies wird in der folgenden XML-Ergebnis:

<ROOT>Hello World</ROOT> 
+0

Funktioniert perfekt! Vielleicht wissen Sie, wie Sie das Attribut "xsi: type" loswerden können? Das bekomme ich für ein 'String'-Objekt:' (239) 555 2390 ' – yegor256

+0

@Vincenzo Ich habe meine Antwort mit Details zur Beseitigung des xsi: type Attributs aktualisiert. –

+0

@BlaiseDoughan bitte sehen Sie dieses Problem: http://stackoverflow.com/questions/26816798/objectfactory-methods-generated-by-jaxb – Spartan

0

Wenn es nicht mit @XmlRootElement annotiert ist, dann hat JAXB nicht genügend Informationen, um es zu marshallen. Sie müssten es zuerst in eine JAXBElement wickeln.

Konnten Sie etwas reflektierendes lovin 'tun, um herauszufinden, wie man das Objekt in die passende wickelt?

+1

überprüfen Sie meine Antwort zu sehen, wie JAXBIntrospector verwendet werden kann, um jede Reflexion zu vermeiden. –

3

Hier ist, wie man , die eine String ist. Sie können yourObject.getClass() zum JAXBElement Konstruktor übergeben, und 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(); 
} 

Dies funktioniert ohne @XmlRootElement zu verwenden. Das Ergebnis des obigen Code war:

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

Auf dem anderen Teil, wird dies nicht mit einem Bar Objekt arbeiten: javax.xml.bind.JAXBException: myPackage.Bar is not known to this context. Sie können jedoch den Wert von innerhalb Bar abrufen und das damit nicht das Objekt selbst erstellen.

1

ich es zu tun alle gut generic Weg finden abgepfiffen. Hier ist meine generische Lösung.

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

}