在JavaEye问答频道发帖,迟迟不见回复,偶尔发现此贴已解心中疑惑。
Exception:java.lang.NumberFormatException: Invalid date
项目遇到这个情况,服务端返回的数据中,有几个类型为 xsd:dateTime,AXIS映射到Java的类是java.util.Calendar。偏偏服务器有时候有的字段是不会带有任何数据的,有的字段是一个字符"T"(因为Web Service中传输dateTime类型的数据字符串格式为yyyy-MM-dd'T'hh:mm:ss.SSS,例如 2008-07-24T23:49:15.000),也就是应该生成对应Java的null对象。可能是考虑到和.NET客户端的兼容性吧(.NET不熟悉,但是为了解决这个问题查看一些资料,都是说对于dateTime类型,如果是空,会在.NET的客户端出现问题),AXIS在处理无数据的 dateTime类型的节点时,就粗暴的报错了。没办法,服务器端是没有办法改程序了,只好在客户端下手了,反正这几个字段对于我的客户端不是很重要,只要不要因为这几个特殊的数据影响了其它数据。
第一个反应就是修改AXIS的代码,但是这种方案是不到万不得已是不能用的,太危险了。然后就看AXIS的文档以及API,看到有typeMapping的配置项,但是对于其中的各个属性又没有详细阐述,网上的例子大部分都是针对服务器端的。经过询问其它同事,他们也遇到了类似的问题,他们定了自己的序列化/反序列化类,然后在AXIS产生的客户端Stub代码中以服务命名的方法,例如 process方法插入自定义的序列化/反序列化类:
public XXResponse process(XXRequest req) throws java.rmi.RemoteException {
if (super.cachedEndpoint == null) {
throw new org.apache.axis.NoEndPointException();
}
org.apache.axis.client.Call _call = createCall();
_call.setOperation(_operations[0]);
_call.setUseSOAPAction(true);
_call.setSOAPActionURI("process");
_call.setEncodingStyle(null);
_call.setProperty(org.apache.axis.client.Call.SEND_TYPE_ATTR,
Boolean.FALSE);
_call.setProperty(org.apache.axis.AxisEngine.PROP_DOMULTIREFS,
Boolean.FALSE);
_call
.setSOAPVersion(org.apache.axis.soap.SOAPConstants.SOAP11_CONSTANTS);
_call.setOperationName(new javax.xml.namespace.QName("", "process"));
WsUtil.prepareCall(_call); // 这一句是用来插入自定义的Serializer和Deserializer
setRequestHeaders(_call);
看看WsUtil的prepareCall如何编写的:
public class WsUtil {
public static void prepareCall(org.apache.axis.client.Call _call) {
_call.registerTypeMapping(
java.util.Date.class,
new javax.xml.namespace.QName("http://www.w3.org/2001/XMLSchema", "dateTime"),
new CalendarSerializerFactory(java.util.Date.class, new javax.xml.namespace.QName(http://www.w3.org/2001/XMLSchema, "dateTime")),
new CalendarDeserializerFactory(java.util.Date.class, new javax.xml.namespace.QName(http://www.w3.org/2001/XMLSchema, "dateTime")), true);
_call.registerTypeMapping(
java.util.Calendar.class,
new javax.xml.namespace.QName("http://www.w3.org/2001/XMLSchema", "dateTime"),
new CalendarSerializerFactory(java.util.Date.class,
new javax.xml.namespace.QName(http://www.w3.org/2001/XMLSchema, "dateTime")),
new CalendarDeserializerFactory(java.util.Date.class, new javax.xml.namespace.QName("http://www.w3.org/2001/XMLSchema","dateTime")), true);
}
这里,通过调用org.apache.axis.client.Call对象的registerTypeMapping方法来插入自定义的Serializer和Deserializer。(以上代码感谢我不认识的那位同事无私的奉献和帮助)
但是这种方法有一个问题就是如果重新生成了客户端代码,需要在Stub类中插入,也是比较具有破坏性的。我就觉得总有一个方法是比较优雅的解决这个问题的,然后顺着这个思路继续往下找,发现可以在Service locator类,也即extends了org.apache.axis.client.Service的那个类来获取到 TypeMappingRegistery,于是,不再修改Stub类,在调用者代码中,生成locator对象之后,调用注册TypeMapping的方法:
LabService locator = new LabServiceLocator();
TypeMappingRegistry tmr = locator.getTypeMappingRegistry();
TypeMapping tm = tmr.getDefaultTypeMapping();
tm.register(java.util.Date.class, new QName(
"http://www.w3.org/2001/XMLSchema", "dateTime"),
new CustomizedCalendarSerializerFactory(java.util.Date.class,
new javax.xml.namespace.QName(
"http://www.w3.org/2001/XMLSchema",
"dateTime")),
new CustomizedCalendarDeserializerFactory(
java.util.Date.class,
new javax.xml.namespace.QName(
"http://www.w3.org/2001/XMLSchema",
"dateTime")));
tm.register(java.util.Calendar.class, new QName(
"http://www.w3.org/2001/XMLSchema", "dateTime"),
new CustomizedCalendarSerializerFactory(java.util.Calendar.class,
new javax.xml.namespace.QName(
"http://www.w3.org/2001/XMLSchema",
"dateTime")),
new CustomizedCalendarDeserializerFactory(
java.util.Calendar.class,
new javax.xml.namespace.QName(
"http://www.w3.org/2001/XMLSchema",
"dateTime")));
通过测试,发现此方法可行,基本上比较好了,但是如果这么多的Service每次调用都干这么一件事,也是很麻烦的,而且,如果以后又有其它的自定义 Serializer和Deserizlizer,还得修改代码。于是乎继续寻找更好的解决办法。仔细阅读AXIS的文档,发现还有client- config.wsdd可用。在AXIS的代码中,
org/apache/axis/client/client-config.wsdd
给出了一个样本,但是是基本的配置,copy这个样本到你的工程的source文件夹,不需要包即可,只要AXIS在运行的时候,能够在classes目录找到这个文件就可以。
以下是配置文件及相关类的代码:
client- config.wsdd:(为了确保安全,把java.util.Date和java.util.Calendar都注册了, 如果服务器端没有强制指定encodingStyle,就把encodingStyle属性设置为"",不知道为什么,改天抽时间再研究:P)
---------------------------------------------------------
<deployment xmlns="http://xml.apache.org/axis/wsdd/"
xmlns:java="http://xml.apache.org/axis/wsdd/providers/java"
xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<globalConfiguration>
<parameter name="disablePrettyXML" value="false" />
</globalConfiguration>
<transport name="http"
pivot="java:org.apache.axis.transport.http.HTTPSender" />
<transport name="local"
pivot="java:org.apache.axis.transport.local.LocalSender" />
<transport name="java"
pivot="java:org.apache.axis.transport.java.JavaSender" />
<typeMapping
encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"
languageSpecificType="java:java.util.Date"
qname="xsd:dateTime" classname="java.util.Date"
serializer="lab.serviceclient.mis.CustomizedCalendarSerializerFactory"
deserializer="lab.serviceclient.mis.CustomizedCalendarDeserializerFactory" />
<typeMapping
encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"
languageSpecificType="java:java.util.Calendar"
qname="xsd:dateTime" classname="java.util.Calendar"
serializer="lab.serviceclient.mis.CustomizedCalendarSerializerFactory"
deserializer="lab.serviceclient.mis.CustomizedCalendarDeserializerFactory" />
</deployment>
---------------------------------------------------------
在client-config.wsdd样本的基础上修改的。
languageSpecificType="java:java.util.Date" 以及languageSpecificType="java:java.util.Calendar"表明映射到Java中哪种类型的数据要求使用自定义的Serializer和Deserializer。注意写法,前面有name space "java",
qname就是指返回的XML文件中的节点类型,对于dateTime类型的全称就是xsd:dateTime,其中xsd=http://www.w3.org/2001/XMLSchema",在这个文件的Root节点定义。
serializer和deserializer节点是指向你的自定义serializer和deserializer的工厂类,而不是serializer和deserializer类本身,这个要注意。
由于不需要序列化的自定义,所以一开始我用的AXIS原有的CalendarSerializerFactory,但是发现有问题,参考 CustomizedCalendarSerializerFactory中create方法的注释不分。所以后来还是加上了自定义的 Serializer,但是很简单了(注意继承的父类):
CustomizedCalendarSerializer.java:
---------------------------------------------------------
package lab.serviceclient.mis;
import org.apache.axis.encoding.ser.CalendarSerializer;
public class CustomizedCalendarSerializer extends CalendarSerializer {
private static final long serialVersionUID = 1L;
}
---------------------------------------------------------
CustomizedCalendarSerializerFactory.java:
---------------------------------------------------------
package lab.serviceclient.mis;
import javax.xml.namespace.QName;
import org.apache.axis.encoding.ser.BaseSerializerFactory;
public class CustomizedCalendarSerializerFactory extends BaseSerializerFactory {
private static final long serialVersionUID = 1L;
public CustomizedCalendarSerializerFactory(Class javaType, QName xmlType) {
super(CustomizedCalendarSerializer.class, xmlType, javaType);
}
// 这个static的create方法是必须的。如果使用前面介绍的编程注册TypeMapping的方式,就不需要这个create方法;如果是定义在client-config.wsdd文件中,
//AXIS在初始化的时候,org.apache.axis.deployment.wsdd.WSDDDeployment.deployMapping方法会调用factory的create方法,如果没有这个方法,就不能注册成功
// 对于Deserializer也是一样的
public static CustomizedCalendarSerializerFactory create(Class javaType, QName xmlType) {
return new CustomizedCalendarSerializerFactory(javaType, xmlType);
}
}
---------------------------------------------------------
CustomizedCalendarDeserializer.java
---------------------------------------------------------
package lab.serviceclient.mis;
import javax.xml.namespace.QName;
import org.apache.axis.encoding.ser.CalendarDeserializer;
public class CustomizedCalendarDeserializer extends CalendarDeserializer {
private static final long serialVersionUID = 1L;
public CustomizedCalendarDeserializer(Class javaType, QName xmlType) {
super(javaType, xmlType);
}
public Object makeValue(String source) {
System.out.println("========= This is the Customized Calendar Deserializer ========="); //为了测试是否到达了自定义的类
if ( source == null || source.length() == 0 || "T".equals(source)) return null;
return super.makeValue(source);
}
}
---------------------------------------------------------
CustomizedCalendarDeserializerFactory.java
---------------------------------------------------------
package lab.serviceclient.mis;
import javax.xml.namespace.QName;
import org.apache.axis.encoding.ser.BaseDeserializerFactory;
import org.apache.axis.encoding.ser.CalendarDeserializer;
public class CustomizedCalendarDeserializerFactory extends BaseDeserializerFactory {
private static final long serialVersionUID = 1L;
public CustomizedCalendarDeserializerFactory(Class javaType, QName xmlType) {
super(CustomizedCalendarDeserializer.class, xmlType, javaType);
}
public static CustomizedCalendarDeserializerFactory create(Class javaType, QName xmlType) {
return new CustomizedCalendarDeserializerFactory(javaType, xmlType);
}
}
分享到:
相关推荐
在使用Idea根据wsdl自动生成java code的时候;抛出无法找到主类:org.apache.axis.wsdl.WSDL2Java(Throws Could not find main class: org.apache.axis.wsdl.WSDL2Java)。 添加本文的jar包压缩包解压出来的所有jar包...
faultString: java.lang.reflect.InvocationTargetException faultActor: faultNode: faultDetail: {http://xml.apache.org/axis/}stackTrace: AxisFault faultCode: {...
在Java开发过程中,我们经常会遇到`java.lang.NoClassDefFoundError`这个异常,尤其是在进行JDK版本升级时。这个错误通常表示在运行时找不到某个类的定义,即使编译时该类是可用的。在本例中,问题发生在从一个较低...
在Java编程中,`java.lang.NoSuchMethodException` 是一个常见的运行时异常,它表示尝试调用一个不存在的方法。这个异常通常发生在动态方法调用或反射操作中。在给出的标题 "java.lang.NoSuchMethodException: ....
jdk升级jdk10后,原本jdk自带的 webservice一些包确实,引起的一系列错误解决方案
错误信息"无法解析运行时描述符: java.lang.IllegalStateException: MASM0001:"指出在部署Web服务时遇到了异常情况。这个错误代码MASM0001通常与WebLogic的模块组装(Module Assembly)过程有关,该过程是将应用组件...
"java.net.SocketException Connection reset 解决方法" 在 Java 编程中,SocketException 是一种常见的异常,特别是在网络编程中。Conexion reset by peer 是一种特殊的 SocketException,它发生在客户端和服务器...
解决使用wsdl生成java客户端报错:java.lang.reflect.invocationtargetexception的方法之一
java调用webservicejava调用webservice.zipjava调用webservice.zipjava调用webservice.zipjava调用webservice.zipjava调用webservice.zipjava调用webservice.zipjava调用webservice.zipjava调用webservice.zipjava...
在IT行业中,尤其是在服务端开发领域,经常需要与不同平台的应用进行交互,这通常涉及到跨语言、跨平台的通信。本教程将详细讲解如何使用Apache Axis2库来调用.Net平台上的Web服务接口,以天气预报的`getSupportCity...
### Java代码发布为WebService的方法与步骤 在当前的软件开发领域中,将Java代码发布为WebService是一种常见的做法,尤其在企业级应用和服务交互场景中。本文将基于提供的标题、描述及部分图片描述内容,详细阐述...
webservice CXF 报错:java.lang.NoClassDefFoundError: org/apache/neethi/builders/AssertionBuilder 需要用到此jar文件 通过apache官网可获得。 文件位置\apache-cxf-2.7.13\lib
首先,WebService是一种基于XML的开放标准,它允许不同系统之间的数据交换。Web服务使用SOAP(简单对象访问协议)通过HTTP协议传输数据,这使得跨平台通信变得可能。在C#中,我们通常使用.NET Framework提供的System...
2. 在“添加服务引用”对话框中,选择“Web 服务”类型,然后输入 WebService 的 URL。 3. 点击“添加引用”按钮,以便将 WebService 添加到项目中。 二、解决添加 WebService 引用出现的问题 在添加 WebService ...
-- 定义数据类型 --> </xsd:schema> </wsdl:types> <wsdl:message ...> <!-- 定义消息格式 --> </wsdl:message> <wsdl:portType ...> <!-- 定义操作 --> </wsdl:portType> <wsdl:binding ...> <!-- 绑定...
javax.wsdl.WSDLException: WSDLException: faultCode=PARSER_ERROR: Problem parsing '- WSDL Document -'.: org.xml.sax.SAXParseException: The element type "p" must be terminated by the matching end-tag ...
"Java实现WebService实例" WebService是基于XML的、分布式的、跨语言的应用程序通信协议。它允许不同的应用程序之间进行交互和集成,从而实现业务逻辑的复杂交互。Java是其中一种常用的实现WebService的语言。 在...
### Spring中配置WebService及其基础开发 #### 一、Spring配置文件 在Spring配置文件中加入以下配置以启用WebService功能。 1. **添加命名空间:** - 首先需要在Spring配置文件的根元素`<beans>`中声明命名空间...
String targetNamespace = "http://webservice.interfacebiz.crpharm.com/"; call.setOperationName(new QName(targetNamespace, "targetNamespace")); //设置参数名: call.addParameter("arg0", //参数名 ...
Java的Web服务支持是Java平台在企业级应用开发中的一项重要功能,它允许不同系统间的应用程序通过网络交换数据,实现跨平台的互操作性。Web服务基于开放的标准,如XML(可扩展标记语言)、WSDL(Web服务描述语言)和...