2013-06-28 9 views
10

Potrzebuję wyświetlić wartość pustą jako pusty element w jaxb. Używam moxb do wdrażania moxy. znalazłem tę opcjęReprezentowanie wartości pustej jako pusty element w xml jaxb

@XmlNullPolicy(emptyNodeRepresentsNull = true, nullRepresentationForXml = XmlMarshalNullRepresentation.EMPTY_NODE) 

Czy istnieje jakiś podobny rozszerzenie, które mogą być stosowane na poziomie klasy (dla wszystkich elementów zdefiniowanych w nim)

Odpowiedz

16

gorąco polecam reprezentujący null albo z braku węzła lub z atrybutem xsi:nil="true". To działa najlepiej z walidacji schematu (tzn <age/> lub <age></age> nie jest poprawnym elementem typu xsd:int Jednak jeśli nie tutaj może to w jaki sposób można osiągnąć swój przypadek użycia.

STANDARD JAXB ZACHOWANIA

Używanie standardowe interfejsy API, które można kontrolować, czy wartość null jest reprezentowana jako nieobecnego węzła lub xsi:nil="true" z dopiskiem @XmlElement (patrz: http://blog.bdoughan.com/2012/04/binding-to-json-xml-handling-null.html)

import javax.xml.bind.annotation.*; 

@XmlRootElement 
@XmlAccessorType(XmlAccessType.FIELD) 
public class Address { 

    private String street; 

    @XmlElement(nillable=true) 
    private String city; 

} 

Poniżej outpu XML. t jeśli wartości obu pól są zerowe.

<?xml version="1.0" encoding="UTF-8"?> 
<address> 
    <city xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:nil="true"/> 
</address> 

Moxy - Nadrzędny Takie zachowanie w klasie

Moxy nie zapewnia adnotację określić politykę zerowej dla wszystkich właściwości na klasy. Można jednak wykorzystać wartość DescriptorCustomizer za pomocą adnotacji @XmlCustomizer i dostosować natywne metadane odwzorowania MOXy, aby uzyskać tę samą funkcję.

DescriptorCustomizer (AddressCustomizer)

import org.eclipse.persistence.config.DescriptorCustomizer; 
import org.eclipse.persistence.descriptors.ClassDescriptor; 
import org.eclipse.persistence.mappings.DatabaseMapping; 
import org.eclipse.persistence.oxm.mappings.XMLDirectMapping; 
import org.eclipse.persistence.oxm.mappings.nullpolicy.XMLNullRepresentationType; 

public class AddressCustomizer implements DescriptorCustomizer { 

    @Override 
    public void customize(ClassDescriptor descriptor) throws Exception { 
     for(DatabaseMapping mapping : descriptor.getMappings()) { 
      if(mapping.isAbstractDirectMapping()) { 
       XMLDirectMapping xmlDirectMapping = (XMLDirectMapping) mapping; 
       xmlDirectMapping.getNullPolicy().setMarshalNullRepresentation(XMLNullRepresentationType.EMPTY_NODE); 
       xmlDirectMapping.getNullPolicy().setNullRepresentedByEmptyNode(true); 
      } 
     } 
    } 

} 

model domeny (adresu)

import javax.xml.bind.annotation.*; 
import org.eclipse.persistence.oxm.annotations.XmlCustomizer; 

@XmlRootElement 
@XmlAccessorType(XmlAccessType.FIELD) 
@XmlCustomizer(AddressCustomizer.class) 
public class Address { 

    private String street; 

    @XmlElement(nillable=true) 
    private String city; 

} 

Wyjście

<?xml version="1.0" encoding="UTF-8"?> 
<address> 
    <street/> 
    <city/> 
</address> 

Moxy - Nadrzędny to zachowanie dla wszystkich klas

Jeśli zamiast tego chcesz nadpisać zerowej obsługę dla wszystkich odwzorowanych klas Polecam przy użyciu SessionEventListener zamiast. Jeśli wolisz, możesz również użyć tego podejścia do aktualizacji metadanych dla pojedynczej klasy.

SessionEventListener (NullPolicySessionEventListener)

import org.eclipse.persistence.descriptors.ClassDescriptor; 
import org.eclipse.persistence.mappings.DatabaseMapping; 
import org.eclipse.persistence.oxm.mappings.XMLDirectMapping; 
import org.eclipse.persistence.oxm.mappings.nullpolicy.XMLNullRepresentationType; 
import org.eclipse.persistence.sessions.*; 

public class NullPolicySessionEventListener extends SessionEventAdapter { 

    @Override 
    public void preLogin(SessionEvent event) { 
     Project project = event.getSession().getProject(); 
     for(ClassDescriptor descriptor : project.getOrderedDescriptors()) { 
      for(DatabaseMapping mapping : descriptor.getMappings()) { 
       if(mapping.isAbstractDirectMapping()) { 
        XMLDirectMapping xmlDirectMapping = (XMLDirectMapping) mapping; 
        xmlDirectMapping.getNullPolicy().setMarshalNullRepresentation(XMLNullRepresentationType.EMPTY_NODE); 
        xmlDirectMapping.getNullPolicy().setNullRepresentedByEmptyNode(true); 
       } 
      } 
     } 
    } 

} 

Demo Code

import java.util.*; 
import javax.xml.bind.*; 
import org.eclipse.persistence.jaxb.JAXBContextProperties; 
import org.eclipse.persistence.sessions.SessionEventListener; 

public class Demo { 

    public static void main(String[] args) throws Exception { 
     Map<String, Object> properties = new HashMap<String, Object>(1); 
     SessionEventListener sessionEventListener = new NullPolicySessionEventListener(); 
     properties.put(JAXBContextProperties.SESSION_EVENT_LISTENER, sessionEventListener); 
     JAXBContext jc = JAXBContext.newInstance(new Class[] {Address.class}, properties); 

     Address address = new Address(); 

     Marshaller marshaller = jc.createMarshaller(); 
     marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true); 
     marshaller.marshal(address, System.out); 
    } 

} 

Wyjście

<?xml version="1.0" encoding="UTF-8"?> 
<address> 
    <street/> 
    <city/> 
</address> 
0

A „złe praktyki” obejście jeśli masz tylko pola String w klasie ma zastąpić setter dla elementu jak poniżej:

public class Address { 

    private String street; 

    @XmlElement(name = "street") 
    public void setStreet(String street){ 
    this.street = street; 
    if (this.street == null){ 
     this.street = ""; // Not NULL, empty string like new String()! 
    } 
    } 
} 

to przyzwyczajenie praca z innych typów, takich jak daty lub numeru ! Ale czasem String jest wystarczający.

@Blaise Odpowiedź Doughana wydaje się znacznie lepsza w dłuższej perspektywie, jeśli można sobie z tym poradzić. :)

Powiązane problemy