Jaxbで空の要素としてnull値を表示する必要があります。私はjaxbのmoxy実装を使用しています。このオプションを見つけました
@XmlNullPolicy(emptyNodeRepresentsNull = true, nullRepresentationForXml = XmlMarshalNullRepresentation.EMPTY_NODE)
クラスレベルで適用できる同様の拡張機能はありますか(クラスで定義されているすべての要素に対して)
ノードがないか、またはxsi:nil="true"
属性でnull
を表すことを強くお勧めします。これは、スキーマ検証で最も効果的に機能します(つまり、<age/>
または<age></age>
は、タイプxsd:int
の有効な要素ではありません。ただし、ここにできない場合は、次のようにしてユースケースを実現できます。
標準JAXB動作
標準のAPIを使用すると、nullが不在ノードとして表されるか、xsi:nil="true"
注釈に@XmlElement
注釈が付けられるかを制御できます(参照: 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;
}
以下は、両方のフィールドの値がnullの場合のXML出力です。
<?xml version="1.0" encoding="UTF-8"?>
<address>
<city xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:nil="true"/>
</address>
MOXy-クラスごとのこの動作のオーバーライド
MOXyは、クラスのすべてのプロパティにnullポリシーを指定するアノテーションを提供していません。ただし、@XmlCustomizer
アノテーションを使用してDescriptorCustomizer
を活用し、ネイティブのMOXyマッピングメタデータを微調整して同じことを行うことができます。
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);
}
}
}
}
DomainModel(アドレス)
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;
}
出力
<?xml version="1.0" encoding="UTF-8"?>
<address>
<street/>
<city/>
</address>
MOXy-すべてのクラスでこの動作を無効にする
代わりに、マップされたすべてのクラスのnull処理をオーバーライドする場合は、代わりにSessionEventListener
を使用することをお勧めします。必要に応じて、このアプローチを使用して単一クラスのメタデータを更新することもできます。
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);
}
}
}
}
}
デモコード
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);
}
}
出力
<?xml version="1.0" encoding="UTF-8"?>
<address>
<street/>
<city/>
</address>
クラスにStringフィールドしかない場合の「悪い習慣」の回避策は、次のように要素のセッターをオーバーライドすることです。
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()!
}
}
}
これは日付や数値などの他のタイプでは機能しません!しかし、時にはStringで十分です。
@Blaise Doughanの回答は、対処できれば、長期的にははるかに良くなります。 :)