Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
263 views
in Technique[技术] by (71.8m points)

java - How to represent null value as empty element with JAXB?

My XSD structure is like the below:-

<element name="XYZDate" maxOccurs="1" minOccurs="1" nillable="true" type="date"/>

When I set the null value in this field it allow me but at he time of XML Generation from JAXB marshaling it produce the output with

<XYZDate xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:nil="true"/>

Whereas in the result I want the out put as <XYZDate/> i.e. do not want the schema and other attribute.
I get rid of this with the help of using XMLStreamWriter but it produce the complete XML in Single line. I need formatted well formed XML. If I need to use IndentingXMLStreamWriter my Java version do not support it and I do not have control over Java Container to change or modify.

Please suggest any solution to form XML Well Formatted.

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

NOTE #1: I am the EclipseLink JAXB (MOXy) lead and a member of the JAXB (JSR-222) expert group.


NOTE #2: The output that you are seeing matches what you have mapped with JAXB. For more information see:


REPRESENTING NULL AS AN EMPTY ELEMENT

If you want to represent null as an empty element, there are a couple of options.

Option #1 - Using the Standard JAXB APIs

DateAdapter

You could use an XmlAdapter to change the way an instance of Date is marshalled to XML. We will convert the date to an instance of a class that has one property mapped with @XmlValue (see http://blog.bdoughan.com/2011/06/jaxb-and-complex-types-with-simple.html). The JAXB RI does not call the XmlAdapter mechanism for null values, so you will need to use a JAXB impl that does such as MOXy.

package forum11743306;

import javax.xml.bind.annotation.XmlValue;
import javax.xml.bind.annotation.adapters.XmlAdapter;
import javax.xml.datatype.XMLGregorianCalendar;

public class DateAdapter extends XmlAdapter<DateAdapter.AdaptedDate, XMLGregorianCalendar>{

    @Override
    public AdaptedDate marshal(XMLGregorianCalendar date) throws Exception {
        AdaptedDate adaptedDate = new AdaptedDate();
        adaptedDate.value = date;
        return adaptedDate;
    }

    @Override
    public XMLGregorianCalendar unmarshal(AdaptedDate adaptedDate) throws Exception {
        return adaptedDate.value;
    }

    public static class AdaptedDate {
        @XmlValue
        public XMLGregorianCalendar value;
    }

}

Root

The XmlAdapter is referenced using the @XmlJavaTypeAdapter annotation.

package forum11743306;

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

@XmlRootElement
public class Root {

    private XMLGregorianCalendar xyzDate;

    @XmlElement(name = "XYZDate", required=true, nillable = true)
    @XmlJavaTypeAdapter(DateAdapter.class)
    public XMLGregorianCalendar getXyzDate() {
        return xyzDate;
    }

    public void setXyzDate(XMLGregorianCalendar xyzDate) {
        this.xyzDate = xyzDate;
    }

}

Option #2 - Using MOXy's @XmlNullPolicy Extension

MOXy offers an @XmlNullPolicy extension that gives you some flexibility in how you represent null.

package forum11743306;

import javax.xml.bind.annotation.*;
import javax.xml.datatype.XMLGregorianCalendar;

import org.eclipse.persistence.oxm.annotations.*;

@XmlRootElement
public class Root {

    private XMLGregorianCalendar xyzDate;

    @XmlElement(name = "XYZDate", required=true, nillable = true)
    @XmlNullPolicy(emptyNodeRepresentsNull = true, nullRepresentationForXml = XmlMarshalNullRepresentation.EMPTY_NODE)
    public XMLGregorianCalendar getXyzDate() {
        return xyzDate;
    }

    public void setXyzDate(XMLGregorianCalendar xyzDate) {
        this.xyzDate = xyzDate;
    }

}

Other Files

The following files can be used with either option to complete the example.

jaxb.properties

To specify MOXy as your JAXB provider you need to include a file called jaxb.properties in the same package as your domain model with the following entry (see: http://blog.bdoughan.com/2011/05/specifying-eclipselink-moxy-as-your.html).

javax.xml.bind.context.factory=org.eclipse.persistence.jaxb.JAXBContextFactory

Demo

package forum11743306;

import javax.xml.bind.*;
import javax.xml.datatype.DatatypeFactory;

import org.eclipse.persistence.Version;

public class Demo {

    public static void main(String[] args) throws Exception {
        JAXBContext jc = JAXBContext.newInstance(Root.class);
        System.out.println(Version.getVersion());
        System.out.println(jc.getClass());

        Marshaller marshaller = jc.createMarshaller();
        marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);

        Root root = new Root();
        root.setXyzDate(null);
        marshaller.marshal(root, System.out);

        root.setXyzDate(DatatypeFactory.newInstance().newXMLGregorianCalendar("2012-08-01"));
        marshaller.marshal(root, System.out);
    }

}

Output

2.4.0
class org.eclipse.persistence.jaxb.JAXBContext
<?xml version="1.0" encoding="UTF-8"?>
<root>
   <XYZDate/>
</root>
<?xml version="1.0" encoding="UTF-8"?>
<root>
   <XYZDate>2012-08-01</XYZDate>
</root>

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

2.1m questions

2.1m answers

60 comments

56.9k users

...