JDK 6 has the wsimport tool that can be used to generate java classes based on the given wsdl file. Then the webservice client can use those classes to call the web service.
The following is the example code:
public void testMyService(){
MyService service = new MyService();
port = service.getMyPort();
port.doSomething();
}
In the above, the class MyService is generated by wsimport. It has many annotations related to web service. It is a subclass of
javax.xml.ws.Service. MyService is actually a proxy. The following is from the javadoc of the class Service:
Service objects provide the client view of a Web service.
Service acts as a factory of the following:
- Proxies for a target service endpoint.
- Instances of {@link javax.xml.ws.Dispatch} for
dynamic message-oriented invocation of a remote
operation.
Now the questions are these. How is the proxy actually created in the runtime? How are those annotations used? The following is the stack of the method calls at the point when the proxy is created:
Thread [Main Thread] (Suspended (breakpoint at line 574 in Proxy))
Proxy.newProxyInstance(ClassLoader, Class<?>[], InvocationHandler) line: 574
AnnotationParser.annotationForMap(Class, Map) line: 239
AnnotationParser.parseAnnotation(ByteBuffer, ConstantPool, Class, boolean) line: 229
AnnotationParser.parseAnnotations2(byte[], ConstantPool, Class) line: 69
AnnotationParser.parseAnnotations(byte[], ConstantPool, Class) line: 52
Class<T>.initAnnotationsIfNecessary() line: 3070
Class<T>.getAnnotation(Class<A>) line: 3029
AnnotationType.<init>(Class<?>) line: 113
AnnotationType.getInstance(Class) line: 66
AnnotationParser.parseAnnotation(ByteBuffer, ConstantPool, Class, boolean) line: 202
AnnotationParser.parseAnnotations2(byte[], ConstantPool, Class) line: 69
AnnotationParser.parseAnnotations(byte[], ConstantPool, Class) line: 52
Class<T>.initAnnotationsIfNecessary() line: 3070
Class<T>.getAnnotation(Class<A>) line: 3029
RuntimeInlineAnnotationReader.getClassAnnotation(Class<A>, Class, Locatable) line: 106
RuntimeInlineAnnotationReader.getClassAnnotation(Class, Object, Locatable) line: 57
RuntimeModelBuilder(ModelBuilder<T,C,F,M>).getTypeInfo(Ref<T,C>) line: 330
JAXBContextImpl.getTypeInfoSet() line: 460
JAXBContextImpl.<init>(JAXBContextImpl$JAXBContextBuilder) line: 298
JAXBContextImpl.<init>(JAXBContextImpl$JAXBContextBuilder, JAXBContextImpl$1) line: 141
JAXBContextImpl$JAXBContextBuilder.build() line: 1163
ContextFactory.createContext(Class[], Map) line: 145
NativeMethodAccessorImpl.invoke0(Method, Object, Object[]) line: not available [native method]
NativeMethodAccessorImpl.invoke(Object, Object[]) line: 39
DelegatingMethodAccessorImpl.invoke(Object, Object[]) line: 25
Method.invoke(Object, Object...) line: 597
ContextFinder.newInstance(Class[], Map, String) line: 202
ContextFinder.find(Class[], Map) line: 363
JAXBContext.newInstance(Class[], Map) line: 574
JAXBContext.newInstance(Class...) line: 522
ProviderImpl$2.run() line: 209
ProviderImpl$2.run() line: 206
ProviderImpl.getEPRJaxbContext() line: 206 [local variables unavailable]
ProviderImpl.() line: 77 [local variables unavailable]
NativeConstructorAccessorImpl.newInstance0(Constructor, Object[]) line: not available [native method]
NativeConstructorAccessorImpl.newInstance(Object[]) line: 39
DelegatingConstructorAccessorImpl.newInstance(Object[]) line: 27
Constructor<T>.newInstance(Object...) line: 513
Class<T>.newInstance0() line: 355 [local variables unavailable]
Class<T>.newInstance() line: 308 [local variables unavailable]
FactoryFinder.newInstance(String, ClassLoader) line: 31
FactoryFinder.find(String, String) line: 128
Provider.provider() line: 83 [local variables unavailable]
MyService(Service).<init>(URL, QName) line: 56
MyService.<init>() line: 46
SimpleClient.testMyService() line: 86
SimpleClient.main(String[]) line: 108
This stack gives some clue about how the proxy is created.
- MyService is the class generated by wsimport.
- The following call to the constructor
service = new MyService()
calls the constructor of the super class Service. And the following code is executed:
protected Service(java.net.URL wsdlDocumentLocation, QName serviceName) {
delegate = Provider.provider().createServiceDelegate(wsdlDocumentLocation,
serviceName,
this.getClass());
}
This corresponds to
MyService(Service).<init>(URL, QName) line: 56
in the stack.
- Now you can see that the Provider picks up the duty and will do all the heavy work. It uses the input parameters wsdlDocumentLocation, serviceName and Class to create the delegate object.
The Provider is javax.xml.ws.spi.Provider. My guess is that the Class object this.getClass() contains all the annotation information of the class MyService. The stack shows the process uses the following classes:
(1)RuntimeInlineAnnotationReader (package: com.sun.xml.bind.v2.model.annotation)
(2)AnnotationParser (package: sun.reflect.annotation)
These classes process the annotations.