jaxb-ri
jaxb-ri copied to clipboard
Potential data loss in field of type xs:dateTime
JAXB appears to silently lose data if an XMLGregorianCalendar
, which corresponds to the XML Schema type dateTime
doesn't specify the "time" fields hours, minutes and seconds.
See this unit test:
https://github.com/h908714124/wsdl2java-gradle6-bug/blob/master/generator/src/test/java/com/foo/bar/zoinks/DataTest.java
In this test, if you marshal data2
again, you see that the form of the xml string even changes on re-marshal:
System.out.println(marshal(data1));
System.out.println(marshal(data2));
which prints the following
<?xml version="1.0" encoding="UTF-8" standalone="yes"?><Data xmlns="http://foo.com/bar/zoinks"><created></created></Data>
<?xml version="1.0" encoding="UTF-8" standalone="yes"?><Data xmlns="http://foo.com/bar/zoinks"/>
One possible solution would be to automatically pad the output of calendar.toString()
to the right, using the pattern T00:00:00
.
Then, the string 2010-11-20
would become 2010-11-20T00:00:00
. This might lead to a different calendar being created on unmarshal (one which has the time fields set to zero, as opposed to not having them set at all), so just throwing an exception instead might be preferable.
Of course, using java.time
types in the generated java classes would also fix this.
Maybe it should also be mentioned that the time fields can be omitted for a field of type xs:date
, which also corresponds to XMLGregorianCalendar
. In that case, specifying them has no effect: The calendar will be "rounded" to the start of the day.
@h908714124 I think that the original test is incomplete because of XMLGregorianCalendar expects every field filled:
private String marshal(Data data) throws JAXBException {
Marshaller marshaller = jaxbContext.createMarshaller();
StringWriter writer = new StringWriter();
ValidationEventCollector validationCollector = new ValidationEventCollector() {
@Override
public boolean handleEvent(ValidationEvent event) {
return super.handleEvent(event);
}
};
marshaller.setEventHandler(validationCollector);
marshaller.marshal(objectFactory.createData(data), writer);
if(validationCollector.hasEvents()) {
for(ValidationEvent event:validationCollector.getEvents()) {
String msg = event.getMessage();
System.out.println(msg);
}
}
return writer.toString();
}
created 1: 2010-11-20
Invalid set of fields set for XMLGregorianCalendar type dateTime. Seconds not set. Minutes not set. Hour not set.
created 2: null
Otherwise, then it would have to change RuntimeBuiltinLeafInfoImpl class to adapt the correct format:
https://github.com/eclipse-ee4j/jaxb-ri/blob/master/jaxb-ri/runtime/impl/src/main/java/org/glassfish/jaxb/runtime/v2/model/impl/RuntimeEnumLeafInfoImpl.java
Regards, Antonio.