2012-01-24 3 views
6

ho una proprietà String in un oggetto annotato come segue:JAXB - tag vuoti senza xsi: nil

@XmlElement(name = "Item", required = true, nillable = true) 
private String item; 

Il risultato dopo marshaling è

<Item xsi:nil="true"/> 

mentre vorrei che fosse

<Item/> 

poiché il servizio di terze parti che accetta i miei messaggi XML lo desidera come quest'ultimo caso. Sto usando jaxb2. Qualcuno sa come potrei farlo?

Grazie mille

risposta

1

Nota: io sono il piombo EclipseLink JAXB (MOXy) e un membro del gruppo di esperti JAXB (JSR-222).

L'esempio seguente richiede l'utilizzo di MOXy come provider JAXB. Questo perché l'IR JAXB non chiama lo XmlAdapter quando il campo/proprietà è nullo. Per informazioni su come specificare moxy come provider di JAXB vedere:

StringAdapter

Il XmlAdapter convertirà il valore String ad un oggetto con una proprietà annotato con @XmlValue.

package forum8986842; 

import javax.xml.bind.annotation.*; 
import javax.xml.bind.annotation.adapters.XmlAdapter; 

public class StringAdapter extends XmlAdapter<StringAdapter.AdaptedString, String>{ 

    @Override 
    public String unmarshal(AdaptedString adaptedString) throws Exception { 
     if(null == adaptedString) { 
      return null; 
     } 
     String string = adaptedString.value; 
     if("".equals(string)) { 
      return null; 
     } 
     return string; 
    } 

    @Override 
    public AdaptedString marshal(String string) throws Exception { 
     AdaptedString adaptedString = new AdaptedString(); 
     adaptedString.value = string; 
     return adaptedString; 
    } 

    public static class AdaptedString { 
     @XmlValue public String value; 
    } 

} 

Root

Il @XmlJavaTypeAdapter annotazione viene utilizzato per specificare il XmlAdapter:

package forum8986842; 

import javax.xml.bind.annotation.*; 
import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter; 

@XmlRootElement(name="Root") 
public class Root { 

    private String item; 

    @XmlElement(name = "Item", required = true, nillable = true) 
    @XmlJavaTypeAdapter(StringAdapter.class) 
    public String getItem() { 
     return item; 
    } 

    public void setItem(String item) { 
     this.item = item; 
    } 

} 

Demo

Il seguente codice può essere utilizzato per dimostrare la mappatura di cui sopra. Due documenti sono utilizzati uno con un elemento vuoto Item e l'altro con un elemento popolato Item.

package forum8986842; 

import java.io.StringReader; 
import javax.xml.bind.*; 

public class Demo { 

    private JAXBContext jc; 

    public Demo() throws JAXBException { 
     jc = JAXBContext.newInstance(Root.class); 
    } 

    public static void main(String[] args) throws Exception { 
     Demo demo = new Demo(); 
     demo.demo("<Root><Item/></Root>"); 
     demo.demo("<Root><Item>Hello World</Item></Root>"); 
    } 

    private void demo(String xml) throws JAXBException { 
     System.out.println("\n\nINPUT: " + xml); 
     StringReader stringReader = new StringReader(xml); 
     Unmarshaller unmarshaller = jc.createUnmarshaller(); 
     Root root = (Root) unmarshaller.unmarshal(stringReader); 

     System.out.println("ITEM: " + root.getItem()); 

     System.out.print("OUTPUT: "); 
     Marshaller marshaller = jc.createMarshaller(); 
     marshaller.setProperty(Marshaller.JAXB_FRAGMENT, true); 
     marshaller.marshal(root, System.out); 
    } 

} 

uscita

Quello che segue è l'uscita da eseguire il codice demo:

INPUT: <Root><Item/></Root> 
ITEM: null 
OUTPUT: <Root><Item/></Root> 

INPUT: <Root><Item>Hello World</Item></Root> 
ITEM: Hello World 
OUTPUT: <Root><Item>Hello World</Item></Root> 

Per ulteriori informazioni

0

ho trovato cambiando il XSD era più facile

<xs:element name="name"> 
    <xs:complexType/> 
</xs:element> 

e nel codice, quando si auto genera tuoi java src/classes

si dovrebbe specificare il nuovo nome e imposta il Nome a seconda del nome dell'oggetto che appartiene a