笔者项目要用到webservice,以往都是直接用cxf或者axis,来发布和动态的生成客户端,去调用,仅仅会用。作为一个骨灰级的程序猿,笔者想一探webservice的本身,但是,出师未捷身先死,第一步,就卡主了,因为照着网上的教程,笔者碰到一个错误,而且几乎无从下手。
1.描述惨案的发生过程
1.1 编写并发布服务端
接口:IHelloWorld
package server;
import javax.jws.WebMethod;
import javax.jws.WebService;
@WebService
public interface IHelloWorld {
@WebMethod
public String sayHello(String name);
}
实现类:HelloWorldImpl
package server;
import javax.jws.WebService;
@WebService
public class HelloWorldImpl implements IHelloWorld {
@Override
public String sayHello(String name) {
return "hello [" + name + "]";
}
}
服务端发布类:ServerPublish
package server;
import javax.xml.ws.Endpoint;
public class ServerPublish {
public static void main(String[] args) {
Endpoint.publish("http://192.168.8.101:9001/helloworld", new HelloWorldImpl());
}
}
1.2测试发布情况
在浏览器中输入:http://192.168.8.101:9001/helloworld?wsdl 就可以看到wsdl描述文件了1.3自动生成客户端代码
wsimport.exe -keep http://192.168.8.101:9001/helloworld?wsdl
然后在笔者的test目录下,可以看到新生成了一个server目录,里面是自动生成的.class和.java文件
1.4把自动生成的代码集成到我自己的工程中
然后,"理所当然"的,笔者,在自己工程下建立了一个package:client.error
然后,手动的把之前server目录下的.java文件,拷贝到,client.error包下,然后打开每个类,修正其中的package的错误
这一切看来似乎都理所当然。
1.5 编写客户端测试类
TestClient:
package client.error;
public class TestClient {
public static void main(String[] args) {
System.out.println(new HelloWorldImplService().getHelloWorldImplPort().sayHello("robin"));
}
}
然后,运行,得到了错误的结果:
Exception in thread "main" com.sun.xml.internal.ws.spi.db.DatabindingException: com.sun.xml.internal.bind.v2.runtime.IllegalAnnotationsException: 2 counts of IllegalAnnotationExceptions
两个类具有相同的 XML 类型名称 "{http://server/}sayHello"。请使用 @XmlType.name 和 @XmlType.namespace 为类分配不同的名称。
this problem is related to the following location:
at client.error.SayHello
at public client.error.SayHello client.error.ObjectFactory.createSayHello()
at client.error.ObjectFactory
this problem is related to the following location:
at server.SayHello
两个类具有相同的 XML 类型名称 "{http://server/}sayHelloResponse"。请使用 @XmlType.name 和 @XmlType.namespace 为类分配不同的名称。
this problem is related to the following location:
at client.error.SayHelloResponse
at public client.error.SayHelloResponse client.error.ObjectFactory.createSayHelloResponse()
at client.error.ObjectFactory
this problem is related to the following location:
at server.SayHelloResponse
at com.sun.xml.internal.ws.db.glassfish.JAXBRIContextFactory.newContext(JAXBRIContextFactory.java:90)
at com.sun.xml.internal.ws.spi.db.BindingContextFactory.create(BindingContextFactory.java:167)
at com.sun.xml.internal.ws.model.AbstractSEIModelImpl$1.run(AbstractSEIModelImpl.java:203)
at com.sun.xml.internal.ws.model.AbstractSEIModelImpl$1.run(AbstractSEIModelImpl.java:176)
at java.security.AccessController.doPrivileged(Native Method)
at com.sun.xml.internal.ws.model.AbstractSEIModelImpl.createJAXBContext(AbstractSEIModelImpl.java:176)
at com.sun.xml.internal.ws.model.AbstractSEIModelImpl.postProcess(AbstractSEIModelImpl.java:95)
at com.sun.xml.internal.ws.model.RuntimeModeler.buildRuntimeModel(RuntimeModeler.java:309)
at com.sun.xml.internal.ws.db.DatabindingImpl.<init>(DatabindingImpl.java:85)
at com.sun.xml.internal.ws.db.DatabindingProviderImpl.create(DatabindingProviderImpl.java:59)
at com.sun.xml.internal.ws.db.DatabindingProviderImpl.create(DatabindingProviderImpl.java:43)
at com.sun.xml.internal.ws.db.DatabindingFactoryImpl.createRuntime(DatabindingFactoryImpl.java:105)
at com.sun.xml.internal.ws.client.WSServiceDelegate.buildRuntimeModel(WSServiceDelegate.java:875)
at com.sun.xml.internal.ws.client.WSServiceDelegate.createSEIPortInfo(WSServiceDelegate.java:892)
at com.sun.xml.internal.ws.client.WSServiceDelegate.addSEI(WSServiceDelegate.java:855)
at com.sun.xml.internal.ws.client.WSServiceDelegate.getPort(WSServiceDelegate.java:435)
at com.sun.xml.internal.ws.client.WSServiceDelegate.getPort(WSServiceDelegate.java:404)
at com.sun.xml.internal.ws.client.WSServiceDelegate.getPort(WSServiceDelegate.java:386)
at javax.xml.ws.Service.getPort(Service.java:119)
at client.error.HelloWorldImplService.getHelloWorldImplPort(HelloWorldImplService.java:72)
at client.error.TestClient.main(TestClient.java:5)
Caused by: com.sun.xml.internal.bind.v2.runtime.IllegalAnnotationsException: 2 counts of IllegalAnnotationExceptions
两个类具有相同的 XML 类型名称 "{http://server/}sayHello"。请使用 @XmlType.name 和 @XmlType.namespace 为类分配不同的名称。
this problem is related to the following location:
at client.error.SayHello
at public client.error.SayHello client.error.ObjectFactory.createSayHello()
at client.error.ObjectFactory
this problem is related to the following location:
at server.SayHello
两个类具有相同的 XML 类型名称 "{http://server/}sayHelloResponse"。请使用 @XmlType.name 和 @XmlType.namespace 为类分配不同的名称。
this problem is related to the following location:
at client.error.SayHelloResponse
at public client.error.SayHelloResponse client.error.ObjectFactory.createSayHelloResponse()
at client.error.ObjectFactory
this problem is related to the following location:
at server.SayHelloResponse
at com.sun.xml.internal.bind.v2.runtime.IllegalAnnotationsException$Builder.check(IllegalAnnotationsException.java:91)
at com.sun.xml.internal.bind.v2.runtime.JAXBContextImpl.getTypeInfoSet(JAXBContextImpl.java:445)
at com.sun.xml.internal.bind.v2.runtime.JAXBContextImpl.<init>(JAXBContextImpl.java:277)
at com.sun.xml.internal.bind.v2.runtime.JAXBContextImpl.<init>(JAXBContextImpl.java:124)
at com.sun.xml.internal.bind.v2.runtime.JAXBContextImpl$JAXBContextBuilder.build(JAXBContextImpl.java:1123)
at com.sun.xml.internal.bind.v2.ContextFactory.createContext(ContextFactory.java:147)
at com.sun.xml.internal.bind.api.JAXBRIContext.newInstance(JAXBRIContext.java:152)
at com.sun.xml.internal.bind.api.JAXBRIContext.newInstance(JAXBRIContext.java:96)
at com.sun.xml.internal.ws.developer.JAXBContextFactory$1.createJAXBContext(JAXBContextFactory.java:98)
at com.sun.xml.internal.ws.db.glassfish.JAXBRIContextFactory.newContext(JAXBRIContextFactory.java:79)
... 20 more
ok,拿到这个异常信息,笔者是一头雾水,网上百度了一番,也没有找到直接的解决办法
2.解决问题
某一个时刻,重新回顾异常"
两个类具有相同的 XML 类型名称 "{http://server/}sayHello"。请使用 @XmlType.name 和 @XmlType.namespace 为类分配不同的名称。"
莫名,笔者感觉,可以试由于路径的问题,因为笔者在1.4中,修改了包名,而自动生成的代码中,或许有引用的时候,写的是 包名.类名 的方式,这样,就会使得路径不正确。
基于这一灵感,笔者去做了一些实验。于是修改步骤 1.3和1.4
2.3 动态生成客户端代码,并指定包名
wsimport -keep -p client.right http://192.168.8.101:9001/helloworld?wsdl
2.4 导入到工程
保证工程中的包名也是 client.right
然后,同样的和之前的1.5一样,运行测试客户端,得到正确的输出结果。
3.回顾
回顾之前的做法,
最开始,笔者基本是全部找网上搜到的教程来做的,可就算照做,还是出现了问题,而且难以解决,问题在于
1.wsimport的命令笔者没有理解,知其然不知其所以然
2.对自动生成的代码过于信赖,并没有去分析源码
对于wsimport其实只要-help就能很详细的看到其使用方法
-keep 会同时生成.class和.java
当目标的地址的webservice,发布的方法很多,可能要想办法将.java和.class分开,否则,手动导入到自己工程的时候,也会不小心出错。
这个时候可以直接使用-s哦