2010-11-10 10 views
12

Tengo un objeto value, que es de algún tipo, ya sea @XmlRootElement -anotado o no. Quiero reunir en XML:¿Cómo ordenar un objeto a través de JAXB sin ninguna información al respecto?

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

¿Puedo hacerlo con JAXB instalaciones existentes, o debería crear algún analizador de costumbre?

Respuesta

21

Se podría aprovechar JAXBIntrospector para hacer lo siguiente:

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 { 

    } 

} 

Con el código anterior cuando el JAXBElement se marshalled que será calificado con un atributo xsi: tipo correspondiente al tipo de esquema apropiado:

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

para eliminar la calificación puede simplemente cambiar la línea que crea el JAXBElement a:

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

Esto dará como resultado el siguiente código XML:

<ROOT>Hello World</ROOT> 
+0

¡Funciona a la perfección! ¿Quizás sabes cómo deshacerte del atributo 'xsi: type'? Esto es lo que obtengo para un objeto 'String':' (239) 555 2390 ' – yegor256

+0

@Vincenzo He actualizado mi respuesta con detalles sobre cómo eliminar el atributo xsi: type. –

+0

@BlaiseDoughan, consulte este problema: http://stackoverflow.com/questions/26816798/objectfactory-methods-generated-by-jaxb – Spartan

0

Si no está anotado con @XmlRootElement, entonces JAXB no tiene suficiente información para ordenarlo. Tendría que envolverlo en un JAXBElement primero.

¿Podría hacer un poco de reflexión para saber cómo envolver el objeto en el JAXBElement apropiado?

+1

echa un vistazo a mi respuesta para ver cómo se puede utilizar JAXBIntrospector para evitar cualquier llamada de reflexión. –

3

Aquí se explica cómo ordenar value1, que es un String. Puede pasar a la yourObject.getClass()JAXBElement constructor, y 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(); 
} 

Esto funciona sin necesidad de utilizar @XmlRootElement. El resultado del código anterior era:

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

Por otra parte, esto no va a funcionar con un objeto Bar: javax.xml.bind.JAXBException: myPackage.Bar is not known to this context. Sin embargo, puede obtener el valor desde adentro de Bar y crear el JAXBElement con eso, no con el objeto en sí.

1

me dio encontrar alguna buena manera genérica de hacerlo. Aquí está mi solución genérica.

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

} 
Cuestiones relacionadas