2010-06-11 9 views
12

Mi scuso se questo è stato risposto, ma i termini di ricerca ho utilizzato (cioè JAXB @XmlAttribute condensato o JAXB maresciallo XML a stringa risultati diversi) non stanno arrivando con niente.JAXB marescialli XML in modo diverso a OutputStream vs. StringWriter

Sto utilizzando JAXB per gli oggetti un/marshal annotati con annotazioni @XmlElement e @XmlAttribute. Ho una classe di formattazione che fornisce due metodi: uno avvolge il metodo di marshal e accetta l'oggetto da maresciallo e uno OutputStream, l'altro accetta solo l'oggetto e restituisce l'output XML come stringa. Sfortunatamente, questi metodi non forniscono lo stesso output per gli stessi oggetti. Quando marshalling a un file, campi oggetto semplici contrassegnati internamente con @XmlAttribute vengono stampate come:

<element value="VALUE"></element> 

mentre quando marshalling in una stringa, che sono:

<element value="VALUE"/> 

io preferirei il secondo formato per entrambi i casi , ma sono curioso di sapere come controllare la differenza, e mi accontenterò che siano uguali a prescindere. Ho persino creato un marshaller statico che entrambi i metodi usano per eliminare diversi valori di istanza. Il codice di formattazione segue:

/** Marker interface for classes which are listed in jaxb.index */ 
public interface Marshalable {} 

/** Local exception class */ 
public class XMLMarshalException extends BaseException {} 

/** Class which un/marshals objects to XML */ 
public class XmlFormatter { 
    private static Marshaller marshaller = null; 
    private static Unmarshaller unmarshaller = null; 

    static { 
     try { 
      JAXBContext context = JAXBContext.newInstance("path.to.package"); 
      marshaller = context.createMarshaller(); 
      marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true); 
      marshaller.setProperty(Marshaller.JAXB_ENCODING, "UTF-8"); 

      unmarshaller = context.createUnmarshaller(); 
     } catch (JAXBException e) { 
      throw new RuntimeException("There was a problem creating a JAXBContext object for formatting the object to XML."); 
     } 
    } 

    public void marshal(Marshalable obj, OutputStream os) throws XMLMarshalException { 
     try { 
      marshaller.marshal(obj, os); 
     } catch (JAXBException jaxbe) { 
      throw new XMLMarshalException(jaxbe); 
     } 
    } 

    public String marshalToString(Marshalable obj) throws XMLMarshalException { 
     try { 
      StringWriter sw = new StringWriter(); 
      return marshaller.marshal(obj, sw); 
     } catch (JAXBException jaxbe) { 
      throw new XMLMarshalException(jaxbe); 
     } 
    } 
} 

/** Example data */ 
@XmlType 
@XmlAccessorType(XmlAccessType.FIELD) 
public class Data { 

    @XmlAttribute(name = value) 
    private String internalString; 
} 

/** Example POJO */ 
@XmlType 
@XmlRootElement(namespace = "project/schema") 
@XmlAccessorType(XmlAccessType.FIELD) 
public class Container implements Marshalable { 

    @XmlElement(required = false, nillable = true) 
    private int number; 

    @XmlElement(required = false, nillable = true) 
    private String word; 

    @XmlElement(required = false, nillable = true) 
    private Data data; 
} 

Il r isultato di chiamare marshal(container, new FileOutputStream("output.xml")) e marshalToString(container) sono i seguenti:

Output come file

<?xml version="1.0" encoding="UTF-8" standalone="yes"?> 
<ns2:container xmlns:ns2="project/schema"> 
    <number>1</number> 
    <word>stackoverflow</word> 
    <data value="This is internal"></data> 
</ns2:container> 

e

uscita a String

<?xml version="1.0" encoding="UTF-8" standalone="yes"?> 
<ns2:container xmlns:ns2="project/schema"> 
    <number>1</number> 
    <word>stackoverflow</word> 
    <data value="This is internal"/> 
</ns2:container> 
+0

Grazie per la pulizia che un po ', ho avuto problemi non avendo il XML interpretato. – Andy

+0

Ulteriori indagini hanno dimostrato che quello che sto cercando è la capacità di controllare se JAXB scrive "elementi vuoti" in stile HTML (tag appaiati) o XML (tag singolo). In altri provider JAXB come JaxMe, questa è una proprietà che può essere impostata, ma apparentemente non in JAXB. Mi chiedo solo perché è diverso a seconda del tipo di destinazione. So che sono funzionalmente equivalenti, ma ho bisogno che siano identici a lavorare con il nostro sistema. Qualche idea? – Andy

risposta

8

Sembra che questo potrebbe essere un "bug" in JAXB.Guardando alla fonte, le chiamate per marshal() creano scrittori diversi in base al parametro tipo di uscita/scrittore:

public void marshal(Object obj, OutputStream out, NamespaceContext inscopeNamespace) throws JAXBException { 
    write(obj, createWriter(out), new StAXPostInitAction(inscopeNamespace,serializer)); 
} 

public void marshal(Object obj, XMLStreamWriter writer) throws JAXBException { 
    write(obj, XMLStreamWriterOutput.create(writer,context), new StAXPostInitAction(writer,serializer)); 
} 

Le implementazioni degli scrittori è diversa per quanto riguarda il modo in cui gestire "Elementi vuoti". Il codice sopra riportato è il seguente:

jaxb-ri \ runtime \ src \ com \ sun \ xml \ bind \ v2 \ runtime \ MarshallerImpl.java.

I due scrittori si sta creando sono:

JAXB-ri \ runtime \ src \ com \ sole \ xml \ bind \ v2 \ runtime \ output \ UTF8XmlOutput.java

JAXB-ri \ runtime \ src \ com \ sun \ xml \ bind \ v2 \ runtime \ output \ XMLStreamWriterOutput.java

+4

Più precisamente questo è un bug nell'implementazione Metro JAXB. Altre implementazioni JAXB come EclipseLink JAXB (MOXy) non hanno questo bug. –

1

Non so perché JAXB sta facendo questo - o anche se è JAXB - se JAXB è ou per esempio, tramite XML SAXContentHandler, non ha alcun controllo diretto su come vengono prodotti i tag vicini.

Per ottenere un comportamento coerente, è possibile avvolgere OutputStream in un OutputStreamWriter, ad es.

public void marshal(Marshalable obj, OutputStream os) throws XMLMarshalException { 
     try { 
      marshaller.marshal(obj, new OutputStreamWriter(os, "UTF-8")); 
     } catch (JAXBException jaxbe) { 
      throw new XMLMarshalException(jaxbe); 
     } 
    } 

Sulla stessa linea, si potrebbe vedere che cosa succede se si avvolge lo StringWriter in un PrintWriter. Forse c'è qualche codice personalizzato che rileva StringWriter per cercare di mantenere l'output più breve possibile. Sembra improbabile, ma non ho altra spiegazione.

+0

Ho finito per fare esattamente questo prima di ricontrollare qui e ottenere risultati consistenti. Grazie. – Andy

0

Perché è importante? < attributo di tag = "valore"> </tag> è equivalente a < etichetta di attributo = "valore" /> in XML

+0

Capisco che sono funzionalmente equivalenti, ma ci sono idiosincrasie all'interno dell'applicazione che sto codificando per richiedere output identico a livello lessicografico. – Andy

2

La buona notizia è che JAXB è una specifica con più di un'applicazione (come JPA). Se un'implementazione non soddisfa le vostre esigenze, altri sono disponibili come EclipseLink JAXB (Moxy):

+0

In effetti, dato che il link è ora defunto –

Problemi correlati