wedens
wedens

Reputation: 1830

NPE when marshalling/unmarshalling JAXBElement

I have following JAXB-mapped class:

@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "date_or_period_t", propOrder = {
    "date", "beginDate", "endDate"
})
public class DateOrPeriodT
    implements Serializable
{

    private final static long serialVersionUID = 1L;
    @XmlElementRef(name = "date", type = JAXBElement.class, required = false)
    protected JAXBElement<DateOrDatetimeT> date;
    @XmlElementRef(name = "begin_date", type = JAXBElement.class, required = false)
    protected JAXBElement<Date> beginDate;
    @XmlElementRef(name = "end_date", type = JAXBElement.class, required = false)
    protected JAXBElement<Date> endDate;

    public JAXBElement<DateOrDatetimeT> getDate() { return date; }
    public void setDate(JAXBElement<DateOrDatetimeT> value) { this.date = value; }
    public JAXBElement<Date> getBeginDate() { return beginDate; }
    public void setBeginDate(JAXBElement<Date> value) { this.beginDate = value; }
    public JAXBElement<Date> getEndDate() { return endDate; }
    public void setEndDate(JAXBElement<Date> value) { this.endDate = value; }
}

and corresponding xsd:

<xsd:complexType name="date_or_period_t">
  <xsd:choice minOccurs="0">
    <xsd:element name="date" type="date_or_datetime_t" nillable="true"></xsd:element>
    <xsd:sequence>
      <xsd:element name="begin_date" type="xsd:date" nillable="true"></xsd:element>
      <xsd:element name="end_date" type="xsd:date" nillable="true"></xsd:element>
    </xsd:sequence>
  </xsd:choice>
</xsd:complexType>

When one or both end_date, begin_date is set to xsi:nil="true", MOXy throws NPE:

Caused by: java.lang.NullPointerException
at org.eclipse.persistence.internal.jaxb.XMLJavaTypeConverter.convertDataValueToObjectValue(XMLJavaTypeConverter.java:155)
at org.eclipse.persistence.oxm.mappings.converters.XMLConverterAdapter.convertDataValueToObjectValue(XMLConverterAdapter.java:28)
at org.eclipse.persistence.oxm.mappings.converters.XMLConverterAdapter.convertDataValueToObjectValue(XMLConverterAdapter.java:1)
at org.eclipse.persistence.internal.jaxb.JAXBElementConverter.convertDataValueToObjectValue(JAXBElementConverter.java:78)
at org.eclipse.persistence.internal.jaxb.JAXBElementConverter.convertDataValueToObjectValue(JAXBElementConverter.java:56)
at org.eclipse.persistence.oxm.mappings.XMLDirectMapping.convertDataValueToObjectValue(XMLDirectMapping.java:526)
at org.eclipse.persistence.oxm.mappings.XMLDirectMapping.getAttributeValue(XMLDirectMapping.java:296)
at org.eclipse.persistence.oxm.mappings.XMLDirectMapping.getAttributeValue(XMLDirectMapping.java:1)
at org.eclipse.persistence.internal.oxm.XMLDirectMappingNodeValue.endElement(XMLDirectMappingNodeValue.java:165)
at org.eclipse.persistence.internal.oxm.XMLChoiceObjectMappingNodeValue.endElement(XMLChoiceObjectMappingNodeValue.java:177)
at org.eclipse.persistence.internal.oxm.record.UnmarshalRecordImpl.endElement(UnmarshalRecordImpl.java:1050)
at org.eclipse.persistence.internal.oxm.record.XMLStreamReaderReader.parseEvent(XMLStreamReaderReader.java:154)
at org.eclipse.persistence.internal.oxm.record.XMLStreamReaderReader.parse(XMLStreamReaderReader.java:99)
at org.eclipse.persistence.internal.oxm.record.XMLStreamReaderReader.parse(XMLStreamReaderReader.java:86)
at org.eclipse.persistence.internal.oxm.record.SAXUnmarshaller.unmarshal(SAXUnmarshaller.java:895)
at org.eclipse.persistence.oxm.XMLUnmarshaller.unmarshal(XMLUnmarshaller.java:659)
at org.eclipse.persistence.jaxb.JAXBUnmarshaller.unmarshal(JAXBUnmarshaller.java:585)
at org.eclipse.persistence.jaxb.JAXBUnmarshaller.unmarshal(JAXBUnmarshaller.java:140)

When date is xsi:nil it works fine, when both begin_date and end_date is not xsi:nil it's fine.

@XmlElementDecl(namespace = "", name = "date", scope = DateOrPeriodT.class)
public JAXBElement<DateOrDatetimeT> createDateOrPeriodTDate(DateOrDatetimeT value) {
    return new JAXBElement<DateOrDatetimeT>(_DateOrPeriodTDate_QNAME, DateOrDatetimeT.class, DateOrPeriodT.class, value);
}
@XmlElementDecl(namespace = "", name = "begin_date", scope = DateOrPeriodT.class)
@XmlJavaTypeAdapter(AdapterDate.class)
public JAXBElement<Date> createDateOrPeriodTBeginDate(Date value) {
    return new JAXBElement<Date>(_DateOrPeriodTBeginDate_QNAME, Date.class, DateOrPeriodT.class, value);
}
@XmlElementDecl(namespace = "", name = "end_date", scope = DateOrPeriodT.class)
@XmlJavaTypeAdapter(AdapterDate.class)
public JAXBElement<Date> createDateOrPeriodTEndDate(Date value) {
    return new JAXBElement<Date>(_DateOrPeriodTEndDate_QNAME, Date.class, DateOrPeriodT.class, value);

Upvotes: 0

Views: 1070

Answers (1)

Martin Vojtek
Martin Vojtek

Reputation: 391

When I use the following setup, everything works fine.

class DateOrDatetimeT ->

package org.eclipse.persistence.testing.jaxb.aso.np;

import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlType;

@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "date", propOrder = {
    "date"
})
public class DateOrDatetimeT {
    private java.util.Date date;

    public java.util.Date getDate() {
        return date;
    }

    public void setDate(java.util.Date date) {
        this.date = date;
    }

    @Override
    public String toString() {
        return "DateOrDatetimeT [date=" + date + "]";
    }

}

class DateOrPeriodT ->

package org.eclipse.persistence.testing.jaxb.aso.np;

import java.io.Serializable;
import java.util.Date;

import javax.xml.bind.JAXBElement;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElementRef;
import javax.xml.bind.annotation.XmlType;

@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "date_or_period_t", propOrder = {
        "date", "beginDate", "endDate"
})
public class DateOrPeriodT
        implements Serializable {

    private final static long serialVersionUID = 1L;
    @XmlElementRef(name = "date", type = JAXBElement.class, required = false)
    protected JAXBElement<DateOrDatetimeT> date;
    @XmlElementRef(name = "begin_date", type = JAXBElement.class, required = false)
    protected JAXBElement<Date> beginDate;
    @XmlElementRef(name = "end_date", type = JAXBElement.class, required = false)
    protected JAXBElement<Date> endDate;

    public JAXBElement<DateOrDatetimeT> getDate() {
        return date;
    }

    public void setDate(JAXBElement<DateOrDatetimeT> value) {
        this.date = value;
    }

    public JAXBElement<Date> getBeginDate() {
        return beginDate;
    }

    public void setBeginDate(JAXBElement<Date> value) {
        this.beginDate = value;
    }

    public JAXBElement<Date> getEndDate() {
        return endDate;
    }

    public void setEndDate(JAXBElement<Date> value) {
        this.endDate = value;
    }

    @Override
    public String toString() {
        return "DateOrPeriodT [date=" + getJAXBElementString(date) + ", beginDate=" + getJAXBElementString(beginDate) + ", endDate=" + getJAXBElementString(endDate) + "]";
    }

    private String getJAXBElementString(JAXBElement<?> element) {

        if (null == element) {
            return null;
        }

        return "{" + element.getName() + ":" + element.getValue() + "}";
    }

}

class ObjectFactory

package org.eclipse.persistence.testing.jaxb.aso.np;

import javax.xml.bind.JAXBElement;
import javax.xml.bind.annotation.XmlElementDecl;
import javax.xml.bind.annotation.XmlRegistry;
import javax.xml.namespace.QName;
import java.util.Date;

@XmlRegistry
public class ObjectFactory {

    @XmlElementDecl(name = "date")
    JAXBElement<DateOrDatetimeT> createDate(Date date) {
        DateOrDatetimeT dateOrDateTime = new DateOrDatetimeT();
        dateOrDateTime.setDate(date);
        return new JAXBElement<DateOrDatetimeT>(new QName("date"), DateOrDatetimeT.class, dateOrDateTime);
    }

    @XmlElementDecl(name = "begin_date")
    JAXBElement<Date> createBeginDate(Date date) {
        return new JAXBElement<Date>(new QName("begin_date"), Date.class, date);
    }

    @XmlElementDecl(name = "end_date")
    JAXBElement<Date> createEndDate(Date date) {
        return new JAXBElement<Date>(new QName("end_date"), Date.class, date);
    }

}

file jaxb.properties

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

class Test

package org.eclipse.persistence.testing.jaxb.aso.np;

import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBElement;
import javax.xml.bind.Unmarshaller;
import java.io.InputStream;
import java.util.HashMap;

public class Test {
    public static void main(String[] args) throws Exception {
        try (InputStream is = Thread.currentThread().getContextClassLoader().getResourceAsStream("org/eclipse/persistence/testing/jaxb/aso/date.xml")) {
            JAXBContext jc = JAXBContext.newInstance(new Class[]{DateOrPeriodT.class, DateOrDatetimeT.class, ObjectFactory.class}, new HashMap<String, Object>());
            Unmarshaller marshaller = jc.createUnmarshaller();
            JAXBElement el = (JAXBElement) marshaller.unmarshal(is);
            DateOrPeriodT dateOrPeriodT = (DateOrPeriodT) el.getValue();
            System.out.println("dateOrPeriodT=" + dateOrPeriodT);
        }
    }
}

different versions of date.xml (tested with EclipseLink 2.5.2)

<date_or_period_t xsi:type="date_or_period_t" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
    <date>2015-02-16T14:49:46.583+01:00</date>
    <begin_date>2015-02-16T14:49:46.583+01:00</begin_date>
    <end_date>2015-02-15T14:49:46.583+01:00</end_date>
</date_or_period_t>

<date_or_period_t xsi:type="date_or_period_t" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
    <date>2015-02-16T14:49:46.583+01:00</date>
    <begin_date xsi:nil="true" />
    <end_date>2015-02-15T14:49:46.583+01:00</end_date>
</date_or_period_t>

<date_or_period_t xsi:type="date_or_period_t" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
    <date>2015-02-16T14:49:46.583+01:00</date>
    <begin_date xsi:nil="true" />
    <end_date xsi:nil="true" />
</date_or_period_t>

<date_or_period_t xsi:type="date_or_period_t" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
    <begin_date xsi:nil="true" />
    <end_date>2015-02-15T14:49:46.583+01:00</end_date>
</date_or_period_t>

<date_or_period_t xsi:type="date_or_period_t" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
    <begin_date xsi:nil="true" />
    <end_date xsi:nil="true" />
</date_or_period_t>

<date_or_period_t xsi:type="date_or_period_t" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
    <begin_date>2015-02-15T14:49:46.583+01:00</begin_date>
    <end_date>2015-02-15T14:49:46.583+01:00</end_date>
</date_or_period_t>

If you use EclipseLink 2.6.0, xml needs nested date element:

<date_or_period_t xsi:type="date_or_period_t" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
    <date><date>2015-02-16T14:49:46.583+01:00</date></date>
    <begin_date>2015-02-16T14:49:46.583+01:00</begin_date>
    <end_date>2015-02-15T14:49:46.583+01:00</end_date>
</date_or_period_t>

Upvotes: 1

Related Questions