The problem is in the following :
I get the soap response with empty element inside (e.g. ... <someDate /> ...
)
and as a result exception is being throwed when JAXB wants to parse this element
instead to set the appropriate field with null
value.
How to configure JAXB to treat empty elements as null ? Can we do this with JAXB only (not using some third-party workarounds)
Empty String
is not a valid value for the xsd:date
type. To be valid with the XML schema an optional element should be represented as an absent node.,
All JAXB implementations will recognize that empty String
is not a valid value for xsd:date
. They do this by reporting it to an instance of ValidationEventHandler
. You can see this yourself by doing the following:
Unmarshaller unmarshaller = jc.createUnmarshaller();
unmarshaller.setEventHandler(new ValidationEventHandler() {
@Override
public boolean handleEvent(ValidationEvent event) {
System.out.println(event);
return true;
}
});
The implementation of JAX-WS you are using, leverages EclipseLink MOXy as the JAXB provider. And in the version you are using MOXy will by default throw an exception when a ValidationEvent
of severity ERROR
is encountered instead of FATAL_ERROR
like the reference implementation. This has since been fixed in the following bug:
If you are using the JAXB APIs directly you could simply override the default ValidationEventHandler
. In a JAX-WS environment a XmlAdapter
can be used to provide custom conversion logic. We will leverage an XmlAdapter
to override how the conversion to/from Date
is handled.
XmlAdapter (DateAdapter)
import java.text.SimpleDateFormat;
import java.util.Date;
import javax.xml.bind.annotation.adapters.XmlAdapter;
public class DateAdapter extends XmlAdapter<String, Date>{
private SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
@Override
public Date unmarshal(String v) throws Exception {
if(v.length() == 0) {
return null;
}
return dateFormat.parse(v);
}
@Override
public String marshal(Date v) throws Exception {
if(null == v) {
return null;
}
return dateFormat.format(v);
}
}
Java Model (Root)
The XmlAdapter
is referenced using the @XmlJavaTypeAdapter
annotation. If you wish this XmlAdapter
to apply to all instances of Date
you can register it at the package level (see: http://blog.bdoughan.com/2012/02/jaxb-and-package-level-xmladapters.html).
import java.util.Date;
import javax.xml.bind.annotation.*;
import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
@XmlRootElement
@XmlAccessorType(XmlAccessType.FIELD)
public class Root {
@XmlSchemaType(name = "date")
@XmlJavaTypeAdapter(value=DateAdapter.class, type=Date.class)
private Date abc;
@XmlSchemaType(name="date")
@XmlJavaTypeAdapter(value=DateAdapter.class, type=Date.class)
private Date qwe;
}
Below is a standalone example you can run to see that everything works.
jaxb.properties
In a standalone example to use MOXy as your JAXB provider you need to include a file called jaxb.propeties
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
input.xml
<?xml version="1.0" encoding="UTF-8"?>
<root>
<abc></abc>
<qwe>2013-09-05</qwe>
</root>
Demo
import java.io.File;
import javax.xml.bind.*;
public class Demo {
public static void main(String[] args) throws Exception {
JAXBContext jc = JAXBContext.newInstance(Root.class);
Unmarshaller unmarshaller = jc.createUnmarshaller();
File xml = new File("src/forum18617998/input.xml");
Root root = (Root) unmarshaller.unmarshal(xml);
Marshaller marshaller = jc.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
marshaller.marshal(root, System.out);
}
}
Output
Note that in the marshalled XML the Date
field that was null was marshalled as an absent element (see: http://blog.bdoughan.com/2012/04/binding-to-json-xml-handling-null.html).
<?xml version="1.0" encoding="UTF-8"?>
<root>
<qwe>2013-09-05</qwe>
</root>
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With