使用Java 1.6 wsimport
我从WSDL为Web服务生成源代码。请求结构中的一个字段在WSDL包含的XML模式中具有类型xs:dateTime
,并在生成的代码中键入javax.xml.datatype.XMLGregorianCalendar
。
通过soapUI手动测试,我确定Web服务接受以下序列化值:2011-12-08
,2011-12-08Z
。以下内容未被接受,本案例中的回复是空回复(不是明确错误):2011-12-08T20:00:00
,2011-12-08T20:00:00-05:00
。如果重要的话,服务本身就是.NET驱动的。
我的想法是服务器应该接受完整的日期/时间并拒绝日期,但反过来就是发生了什么。但我不假设服务器的维护者可以改变。所以我试图说服客户只发送日期。
我无法说服我的客户端代码将XMLGregorianCalendar
对象序列化为仅日期。实际上我可以,除了,当生成的代码执行它时。当生成的客户端代码(由wsimport
生成)执行此操作时,序列化值为空字符串,并且服务器正确返回错误。我使用数据包嗅探器验证了这一点。
以下是我在请求中创建和填充日期字段的方法:
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;
}
在我的例子中,XMLGregorianCalendar的实现类是com.sun.org.apache.xerces.internal.jaxp.datatype.XMLGregorianCalendarImpl
。在调试器中,或者如果我添加日志输出,则调用日期对象的toXMLFormat()
方法仅返回日期,例如2011-12-09
。使用调试器检查日期对象本身,我看到它填充了year
,day
和month
字段,其他所有字段都是null
或{{1这是-2147483648
的值。根据我发现的所有文档和Internet搜索结果,我的日期对象正确形成。
DatatypeConstants.FIELD_UNDEFINED
是否存在一些影响我的已知问题?
答案 0 :(得分:3)
我发现JAXB的日期转换不应该留给他们自己的设备。不熟悉wsimport,但它是否允许您指定绑定文件?我使用Joda日期/时间,但我的确是这个想法是一样的。将此添加到我的binding.xjb:
<globalBindings>
<serializable />
<javaType name="org.joda.time.DateTime" xmlType="xsd:dateTime"
printMethod="someStaticDateConverterClass.printDateIso"
parseMethod="someStaticDateConverterClass.parseDateIso" />
<javaType name="org.joda.time.DateTime" xmlType="xs:date"
printMethod="someStaticDateConverterClass.printDateYYYYDashMMDashDD"
parseMethod="someStaticDateConverterClass.parseDateYYYYDashMMDashDD" />
</globalBindings>
这样的课程:
import org.joda.time.DateTime;
import org.joda.time.format.DateTimeFormat;
import org.joda.time.format.DateTimeFormatter;
import org.joda.time.format.ISODateTimeFormat;
public class someStaticDateConverterClass{
private static DateTimeFormatter isoFormat = ISODateTimeFormat.dateTime();
private static DateTimeFormatter YYYYDashMMDashDDFormat = DateTimeFormat
.forPattern("yyyy-MM-dd");
private static DateTimeFormatter YYYYMMDDFormat = DateTimeFormat
.forPattern("yyyyMMdd");
public static String printDateIso(DateTime value) {
return printDate(value, isoFormat);
}
public static DateTime parseDateIso(String value) {
return parseDate(value, isoFormat);
}
public static String printDateYYYYDashMMDashDD(DateTime value) {
return printDate(value, YYYYDashMMDashDDFormat);
}
public static DateTime parseDateYYYYDashMMDashDD(String value) {
return parseDate(value, YYYYDashMMDashDDFormat);
}
public static String printDateYYYYMMDD(DateTime value) {
return printDate(value, YYYYMMDDFormat);
}
public static DateTime parseDateYYYYMMDD(String value) {
return parseDate(value, YYYYMMDDFormat);
}
private static String printDate(DateTime value, DateTimeFormatter format) {
String dateAsStr;
if (value != null) {
dateAsStr = value.toString(format);
} else {
dateAsStr = null;
}
return dateAsStr;
}
private static DateTime parseDate(String value, DateTimeFormatter format) {
DateTime strAsDate;
if (value != null) {
strAsDate = format.parseDateTime(value);
} else {
strAsDate = null;
}
return strAsDate;
}
}
答案 1 :(得分:1)
我看到了一些我不认识的.NET Web服务的不直观的实现细节。在我的分析中,我观察到提供完整的日期/时间序列化字符串导致服务器的响应为空,但不是明确的错误。
这是因为在服务器上,它们实际上是使用日期/时间对象,但强制所有时间都在东部标准时间的午夜。因此,如果我将请求中的时间强制到美国东部时间午夜,那么响应只会填充结果,我没有这样做。 (如果没有给出时区,服务器就会假设EST;如果没有给出时间,那么假定是美国东部时间午夜。)
所以在我的情况下,解决方案是修改客户端代码以强制时区为Olson America/New_York
并在创建请求时将当地时间强制为00:00:00
。
答案 2 :(得分:0)
除了Roy的回答,这里是apache cxf和maven cxf codegen配置的有效绑定文件
/resources/binding.jxb
<?xml version="1.0" encoding="UTF-8"?>
<jaxb:bindings xmlns:jaxb="http://java.sun.com/xml/ns/jaxb"
jaxb:extensionBindingPrefixes="xjc" xmlns:xjc="http://java.sun.com/xml/ns/jaxb/xjc"
xmlns="ns" xmlns:xsd="http://www.w3.org/2001/XMLSchema"
jaxb:version="2.1">
<jaxb:globalBindings>
<jaxb:serializable />
<jaxb:javaType name="org.joda.time.DateTime" xmlType="xsd:dateTime"
printMethod="package.converters.StaticXmlDateConverter.printDateIso"
parseMethod="package.converters.StaticXmlDateConverter.parseDateIso" />
<jaxb:javaType name="org.joda.time.DateTime" xmlType="xsd:date"
printMethod="package.converters.StaticXmlDateConverter.printDateYYYYDashMMDashDD"
parseMethod="package.converters.StaticXmlDateConverter.parseDateYYYYDashMMDashDD" />
</jaxb:globalBindings>
</jaxb:bindings>
在pom.xml中
<plugin>
<groupId>org.apache.cxf</groupId>
<artifactId>cxf-codegen-plugin</artifactId>
<version>3.1.6</version>
<executions>
<execution>
<id>generate-sources-0001</id>
<phase>generate-sources</phase>
<configuration>
<defaultOptions>
<frontEnd>jaxws21</frontEnd>
</defaultOptions>
<sourceRoot>${project.build.directory}/generated/</sourceRoot>
<wsdlOptions>
<wsdlOption>
<wsdl>${basedir}/src/main/resources/service.wsdl</wsdl>
<wsdlLocation>
http://someprovider.com/services/actualservice.asmx?WSDL
</wsdlLocation>
<bindingFiles>
<bindingFile>${basedir}/src/main/resources/binding.xjb</bindingFile>
</bindingFiles>
<extraargs>
<extraarg>-client</extraarg>
<extraarg>-verbose</extraarg>
</extraargs>
</wsdlOption>
</wsdlOptions>
</configuration>
<goals>
<goal>wsdl2java</goal>
</goals>
</execution>
</executions>
<dependencies>
<dependency>
<groupId>org.jvnet.jaxb2_commons</groupId>
<artifactId>jaxb2-basics-annotate</artifactId>
<version>1.0.2</version>
</dependency>
</dependencies>
</plugin>