Using Java 1.6 wsimport
I generated source from a WSDL for a web service. One of the fields in the request structure has type xs:dateTime
in the XML schema included by the WSDL and type javax.xml.datatype.XMLGregorianCalendar
in the generated code.
Through manual testing with soapUI I have determined that the following serialized values are accepted by the web service: 2011-12-08
, 2011-12-08Z
. The following are not accepted and the response in this case is an empty reply (not an explicit error): 2011-12-08T20:00:00
, 2011-12-08T20:00:00-05:00
. The service itself is .NET powered if that matters.
My thought is that the server should accept the full date/time and reject the date only, but the other way around is what is happening. But I am under no assumption that maintainers of the server will be open to change. So I have attempted to convince the client to send a date only.
I can't convince my client code to serialize an XMLGregorianCalendar
object into a date only. Well actually I can, except when the generated code does it. When the generated client code (produced by wsimport
) does it, the serialized value is the empty string, and the server correctly returns an error. I verified this using a packet sniffer.
Here is how I'm creating and populating the date field in the request:
import java.util.Calendar;
import java.util.GregorianCalendar;
import javax.xml.datatype.DatatypeConfigurationException;
import javax.xml.datatype.DatatypeConstants;
import javax.xml.datatype.DatatypeFactory;
import javax.xml.datatype.XMLGregorianCalendar;
import java.util.TimeZone;
// also import GeneratedRequest from generated packages
private makeRequest() {
GeneratedRequest request;
// ...
request.setDateField(xmlDayNow(TimeZone.getTimeZone("America/New_York"),
6)); // broadcast day starts at 6 am EST
// ...
}
@XmlSchemaType(name="date")
private static XMLGregorianCalendar xmlDayNow(TimeZone tz, int localHourStart)
throws MyException {
GregorianCalendar cal = gregorianBroadcastDayNow(tz, localHourStart);
XMLGregorianCalendar result;
try {
result = DatatypeFactory.newInstance().newXMLGregorianCalendarDate(
cal.get(Calendar.YEAR), cal.get(Calendar.MONTH) + 1,
cal.get(Calendar.DAY_OF_MONTH), DatatypeConstants.FIELD_UNDEFINED)
.normalize();
} catch (DatatypeConfigurationException e) {
throw new MyException("XMLGregorianCalendar issue", e);
}
return result;
}
protected static GregorianCalendar gregorianBroadcastDayNow(TimeZone tz,
int localHourStart) {
GregorianCalendar now = new GregorianCalendar(tz);
if (now.get(GregorianCalendar.HOUR_OF_DAY) < localHourStart) {
now.add(GregorianCalendar.DAY_OF_MONTH, -1);
}
return now;
}
The implementation class for XMLGregorianCalendar in my case is com.sun.org.apache.xerces.internal.jaxp.datatype.XMLGregorianCalendarImpl
. In the debugger, or if I add log output, calling the date object's toXMLFormat()
method returns a date only, such as 2011-12-09
. Using a debugger to inspect the date object itself, I see that its year
, day
and month
fields are populated, and all the others are either null
or -2147483648
which is the value of DatatypeConstants.FIELD_UNDEFINED
. According to all documentation and Internet search results I have found, my date object is correctly formed.
Am I crazy? Is the server really in error? Is the refusal of the generated client code to send a date only correct? Is this a justifiable "undefined behavior" case? Is the wrong implementation class being used (could that possibly matter anyway)? Is there some known issue with wsimport
that's affecting me?
I was seeing an unintuitive implementation detail of .NET web services that I did not recognize. In my analysis I observed that providing a complete date/time serialized string resulted in an empty response from the server, but not an explicit error.
This was because on the server, they were in fact using date/time objects, but were forcing all of the times to midnight Eastern Standard Time. So the responses were only populated with results if I forced the time in the request to midnight EST, which I was not doing. (In the event that no time zone was given, the server assumed EST; and if no time was given at all, midnight EST was assumed.)
So in my case, the solution was to modify the client code to force the time zone to Olson America/New_York
and force the local time to 00:00:00
when creating the request.