Wednesday, December 21, 2005

Part II:Using Spring to consume web services; advanced example using Google Web APIs doGoogleSearch

I should point out that what I am about to show is not necessarily the quickest way of getting the Google Web API doGoogleSearch up and running. In this particular case Google already provides a Google Web API Developer's Kit which you could use to do all of the functionality I am about to describe, indeed some of the precompiled Google Web API package will be interchangeable with what I am about to generate using the Axis WSDL2Java tool but I hope this example will give you some ideas that can be applied to web services in general and not just the Google Web API.

In my last blog entry, I showed how you can access doSpellingSuggestion with Spring and since this service only returns a String there was no particular complexity involved. doGoogleSearch returns a more complex response and so I am going to use Axis' WSDL2Java tool to generate the beans that I will need to capture this more complex response. Remember that WSDL2Java is intended to produce Axis specific code and since I'm using Spring to do the web service access I don't actually need all the generated Axis code. I downloaded Axis 1.3 and created an Ant script containing the relevant Axis WSDL2Java Ant task.

<?xml version="1.0" encoding="UTF-8"?>
<project name="googleApi" default="wsdl2java" basedir=".">

<path id="axis.classpath">
<fileset dir="./lib">
<include name="**/*.jar" />

<taskdef resource="" classpathref=""axis.classpath" />

<target name="wsdl2java">
<mkdir dir="src"/>
url="" >
package="" />


The important thing to notice about this is that I am using the helpergen="true" option by doing this I am asking WSDL2Java to store any Axis specific code away from the valuable beans that I actually want. After running this script I have a collection of generated classes, some of which I don't actually need. The following list shows the classes that are produced by running WSDL2Java against the Google WSDL with the classes I don't need indicated via a strikethrough.


After deleting all the helper classes, BindingStub and Locator I have removed all the Axis specific code. I am left with the beans I need to capture my responses to doGoogleSearch and also a convenient port interface class.

In this case we are expecting the web service to return something more complicated than a String so we need to extend JaxRpcPortProxyFactoryBean in order to map the service response given to our generated beans. Modifying the example given in the Chapter 16. Remoting and web services using Spring I get:

package fullgoogleapi;

import javax.xml.namespace.QName;
import javax.xml.rpc.Service;
import javax.xml.rpc.encoding.TypeMapping;
import javax.xml.rpc.encoding.TypeMappingRegistry;
import org.apache.axis.encoding.ser.BeanDeserializerFactory;
import org.apache.axis.encoding.ser.BeanSerializerFactory;
import org.springframework.remoting.jaxrpc.JaxRpcPortProxyFactoryBean;

public class GooglePortProxyFactoryBean extends JaxRpcPortProxyFactoryBean {

protected void postProcessJaxRpcService(Service service) {
TypeMappingRegistry registry = service.getTypeMappingRegistry();
TypeMapping mapping = registry.createTypeMapping();
registerBeanMapping(mapping, GoogleSearchResult.class, "GoogleSearchResult");
registerBeanMapping(mapping, ResultElement.class, "ResultElement");
registerBeanMapping(mapping, DirectoryCategory.class, "DirectoryCategory");
registry.register("", mapping);

protected void registerBeanMapping(TypeMapping mapping, Class type, String name) {
QName qName = new QName("urn:GoogleSearch", name);
mapping.register(type, qName,
new BeanSerializerFactory(type, qName),
new BeanDeserializerFactory(type, qName));


Now to add a service interface. This is essentially a slightly modified version of the generated class but in the service interface we no longer throw RMI exceptions. Contrast this to the previous doSpellingSuggest example as I will define all the methods properly and not just to satisfy the endpoint matching so that I can now use all of the methods if I want to.

package fullgoogleapi;

public interface GoogleSearchService {

public byte[] doGetCachedPage(String key, String url);
public String doSpellingSuggestion(String key, String phrase);
public doGoogleSearch(String key, String q, int start, int maxResults, boolean filter, String restrict, boolean safeSearch, String lr, String ie, String oe);


My new applicationContext.xml file incorporating the extended JaxRpcPortProxyFactoryBean, generated port interface class and the service interface above will look something like this:


<bean id="googleService" class="fullgoogleapi.GooglePortProxyFactoryBean">

<property name="serviceFactoryClass">

<property name="wsdlDocumentUrl">

<property name="namespaceUri">

<property name="serviceName">

<property name="portName">

<property name="portInterface">

<property name="serviceInterface">


The test class will now look something like this:

package fullgoogleapi;

import org.apache.commons.collections.BeanMap;
import org.springframework.context.ApplicationContext;

public class MainApplication {

private static ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
private static GoogleSearchService service = (GoogleSearchService) context.getBean("googleService");

public static void main(String [] args) throws Exception {
String key="<Insert Google Web API key here>";
String test = "webservie";

String q ="shrdlu winograd maclisp teletype";
int start = 0;
int maxResults = 10;
boolean filter = true;
String restrict = "";
boolean safeSearch = true;
String lr = "";
String ie = "latin1";
String oe = "latin1";
GoogleSearchResult gsr = service.doGoogleSearch(key, q, start, maxResults, filter, restrict, safeSearch, lr, ie, oe);

BeanMap googleResults = new BeanMap(gsr);

If you have used Axis before I hope you'll agree that this is considerably simpler than wiring together all the generated BindingStubs and Locators. In this example I've reduced the role of WSDL2Java from an Axis code generator to a simple WSDL aware bean generator. The minute you run into problems you will probably have to go away and learn how to use Axis's TCP Monitor etc. Using this method, if you are lucky, you may get away with not even having to look through a WSDL or even browse a SOAP message. It would be nice if you knew all the intricacies of SOAP, Axis and web services but with this method I think it becomes slightly less important than it was before. I would expect you to be more productive at consuming web services using the Spring enabled web services approach than the method that Axis previously offered.


Mark McLaren said...


Tutorial is very good. very simple to understand. I am facing a problem when executing the client code. I followed the tutorial and created XML, mapping and client files. when i compile the client, i was getting 'MySearchService' (similar to GoogleSearchService interface) not found. I added the MySearchService.class file to the classpath of client. Now, when i execute the client class, i am getting 'Service not found - MyService(similar to GoogleService). Do i need to do anything more. Can tell me where i am going wrong. Do i need to add something into Web.xml of Webservice application. Thanks in advance.
Note: Comment imported. Original by Senthil at 2006-03-06 05:06

Mark McLaren said...

I can't be sure exactly what the problem is.

If it seems to be having problems locating MyService then you need to double check the details of the service WSDL file. Maybe a namespace hasn't been specified correctly, check what targetNamespace is currently set to in your WSDL file and make sure your client "qName" matches (in the above case it was "urn:GoogleSearch").

You shouldn't need to specify anything in your web.xml. For testing purposes you should be able to run this on the command line outside of any web application. If it's any help I used Axis 1.3 and Spring 1.2.6 for the above example.

Note: Comment imported. Original by markmc website: at 2006-03-06 08:48

Mark McLaren said...

Thanks Mark, I got my problem solved. It was becoz of wrong targetNamespace. I just copy/pasted the value of targetNamespace from generated WSDL to the applicationContext.xml. It works now.

Thanks for the help.

By the way, I need another help.

I have to pass Username,Password to my Webservice. I have users.lst file under WEB-INF folder which has some users and their passord.

Now, i am getting Axis fault - 'faultString: (401)Unauthorized xxx' -- 'faultStringUser 'null' not authenticated (unknown user)'.

Can you help me in sending this parameters while calling Axis Webservice from the Spring Client?

Thanks in Advance.


Note: Comment imported. Original by Senthil at 2006-03-06 20:03

Mark McLaren said...

Lucky guess! JaxRpcPortProxyFactoryBean accepts username and password parameters. So if you're lucky it might just be a case of specifying username/password in the configuration. e.g. in the above example it would look something like this:





Note: Comment imported. Original by markmc website: at 2006-03-06 21:31

Mark McLaren said...

Yes, that works nicely for RPC style web services. I can execute both Google search service and my own Spring-Axis test service. However if I change the service style/use to document/literal for my Spring-Axis service, I start getting a "could not find deserializer for type ..." error on the client side. Any idea why is that happening or where would be a good place to ask this question?

Btw I noticed that my portType uses the parameterOrder option which is intended for RPC style services, and the top-level element in the SOAP response body is of the form Return. why is that?
Note: Comment imported. Original by Alex at 2006-04-21 14:31

Mark McLaren said...

I have to admit your question scared me! People have told me that my tutorials are simple and easy to understand, the reason for that is I am fairly simple!

I had to go away and look up the difference between RPC/Encoded and Document/Literal. Fortunately I found a quite simple article explaining it.

Selecting the Best Approach for Designing an Interoperable Web Service

From the article above and various solutions I found on the net I suspect the problem can be fixed by modifying the bean mapping code.

If the Google service were to start using Document/Literal style then GooglePortProxyFactoryBean would need to be modified thus

registry.register("", mapping);


registry.register("", mapping);

I'm guessing that would fix it.

If I understand the article above correctly then the part of the mapping basically implies that the web service types are represented via the use style "encoded". If your web service is of the use style "literal" then registering the encoded mapping for this response makes no sense.

See also:

As for your second question regarding parameterOrder and parametername, I'm not really sure what you are asking. WSDL and SOAP responses are two completely separate XML formats. portType elements and parameterOrder attributes are usually associated with WSDL documents, whereas parametername elements are used in SOAP documents.

Note: Comment imported. Original by markmc website: at 2006-04-21 20:39

Mark McLaren said...

Good Article, Thanks Mark. I am just wonder ing if the bean created by SpringFrame is thread safe ? I know the sub create by Axis is not .

Note: Comment imported. Original by Feng Chao at 2006-07-20 04:29

Mark McLaren said...

I'm not absolutely sure and I haven't tried this. The API docs for JaxRpcPortClientInterceptor mention using something called the dynamic call mechanism to ensure thread safety. As you say, the documentation states that Apache Axis port stubs are known to be non-thread-safe. AFAICT the dynamic call mechanism can be implemented on beans that extend JaxRpcPortProxyFactoryBean (such as GooglePortProxyFactoryBean above). If I read it right, all you would need to do is implement the alwaysUseJaxRpcCall() method so that it returns true.


Note: Comment imported. Original by markmc website: at 2006-07-20 09:00

Mark McLaren said...


I've just noticed it is only the JaxRpcPortClientInterceptor docs for Spring 2.0.x that specifically mention thread safety in terms of alwaysUseJaxRpcCall(). Although I'm not sure if that equates to only Spring 2.0.x implementations being thread safe.

Note: Comment imported. Original by markmc website: at 2006-07-20 09:09

Mark McLaren said...

Your are article is really good.

i have small problem with my web service. It is an RPC/encoded web service and deployed in https. And i save the wsdl file into local file and configured the spring by extending the JaxRpcPortProxyFactoryBean. But i am exception "PKIX path building failed: unable to find valid certification path to requested target". I appreciate your help on this.

Note: Comment imported. Original by Anonymous at 2006-08-04 23:03

Mark McLaren said...

I think this is a SSL certificate trust issue. The certificate of the HTTPS web service that you are accessing is not signed by one of the certificate authorities (CAs) that Java trusts by default (such as VeriSign and Thawte). It could be that the certicificate on the server is self signed.

What you should do is import the root certificate from the CA that signed the web service's SSL certificate into your Java keystore. Doing this will allow Java connections to trust this connection.

To do this, I first go to the HTTPS URL of the service and use MS Internet Explorer to obtain the root certifcate. See

Export a root certificate from Microsoft Internet Explorer

Then import your certificate into your keystore. There is a Java command line tool that you can use to do this called keytool. Keytool tends to be a bit painful to use, so you might want to use something more user friendly such as portecle.


Note: Comment imported. Original by markmc website: at 2006-08-05 00:49

Mark McLaren said...

Thanks a lot. It helped me a lot.

I have one more question. We have requirement of keeping an customizable "TimeOut" option for the service. I know that, we can do this using Stub class/Call using setTimeout option. So how can i accomplish this using the "JaxRpcPortProxyFactoryBean".

I appreciate your help on this.
Note: Comment imported. Original by Anonymous at 2006-08-17 01:03

Mark McLaren said...

I'm not exactly sure if this is the best way to do it but the following code extends JaxRpcPortProxyFactoryBean so that you can set a timeout.


Also this looked relevant:

Eric Hauser's Weblog: Axis and Spring

Note: Comment imported. Original by markmc website: at 2006-08-17 09:36

Mark McLaren said...

Thanks Mark for the information.

And i have one more last question :)

how can we set the Endpoint address dynamically?
Note: Comment imported. Original by Anonymous at 2006-08-18 22:27

Mark McLaren said...

How can we set the Endpoint address dynamically? I am not exactly sure what you mean. The service endpoint is set inside the WSDL. I cobbled together a SimpleWSDLAnalyzer using Axis 1.3 (and some JBoss code I found) to illustrate this. This program uses the Axis WSDL parsing code to obtain information from a WSDL file. For the Google SOAP Search API this program outputs:


Namespace URI: urn:GoogleSearch

Service Name: GoogleSearchService

Port Name: GoogleSearchPort

Endpoint URL:

Operation: doGetCachedPage

Operation: doSpellingSuggestion

Operation: doGoogleSearch

As you see, the endpoint for Google SOAP Search API at the time of writing this is

If Google moves the endpoint then, AFAICT, as long as this change is reflected inside the WSDL document then the above technique will continue to work. AFAIK, the endpoint location is not hard coded anywhere in the Axis generated model objects nor is it explicitly contained inside the Spring code.

You can of course change the WSDL address dynamically. e.g.

service.setWsdlDocumentUrl("some new url")

I'm not sure why you would need to do this. Your question got me thinking about more generic means of consuming web services, this lead me to soapui which is very interesting. The problem with the ultra generic approach is that it is not very useful beyond testing very simple web services.

Note: Comment imported. Original by markmc website: at 2006-08-21 15:48

Mark McLaren said...

I am using http host and proxy to connect to internet.

When i run the MainApplication it gives me ConnectionTimedOut exception

How can I fix this problem
Note: Comment imported. Original by MR at 2006-09-26 12:12

Mark McLaren said...

You can connect through a proxy using Java.

Note: Comment imported. Original by markmc website: at 2006-09-26 21:43

Mark McLaren said...

I am consuming web service through spring 1.2.5+axis 1.2.1. The speciality of that particular web service is that at the time of wrong/invalid input the request is coming back as response. So when I am passing valid inputs my code is running fine but when I am passing wrong/invalid input I am getting org.xml.sax.SAXException Invalid Element-.I have tried same web service with weblogic 7 client & it's working fine for valid/invalid inputs. So what may be the problem in Spring+Axis when request is coming back as response?
Note: Comment imported. Original by Sujoy at 2007-01-03 05:31

Mark McLaren said...

just thanks for this article!
Note: Comment imported. Original by Martin at 2007-01-16 13:45

Mark McLaren said...

you can encounter a problem with mappings if you delete helper classes and YourServiceBindingStub. You should rather leave helpergen="false" and not delete YourServiceBindingStub class.

i've almost converted to XFire because of this problem :-)
Note: Comment imported. Original by Martin Zdila at 2007-02-06 11:08

Mark McLaren said...

Martin is absolutely right; If you set helpergen=true and rely on deleting the Helper and SoapBindingStub classes you run the risk of getting the, "Could not find deserialiser for type . . ." error. Just set helpergen=false, and leave all the generated files intact(though deleting the ServiceLocator clas doesnt seem to unsettle things); just make sure you have the SoapBindingStub in there.

Top class tutorial by the way ! ! !
Note: Comment imported. Original by Thapelo Tlhong at 2007-02-08 07:53

Mark McLaren said...

Hello mark !

What about if I have to set the username and password at the first page of my application ?? What should I do ???
Note: Comment imported. Original by Rodrigo at 2007-09-26 20:12

Mark McLaren said...

Hi Rodrigo,

I am not sure what you mean. Could you please explain what you want to do.


Note: Comment imported. Original by markmc website: at 2007-09-26 20:48

Mark McLaren said...

Hi Mark,

I followed your example for setting web service invocation using the RPC approach given in your example. Do, I need to configure anything other than setting the username and password in the applicationContext.xml for accessing a webservice which requires username/password authentication ?

Thank you in advance.

Note: Comment imported. Original by Anonymous at 2008-01-31 17:42

Mark McLaren said...

Hi Jilani,

Setting username/password in the applicationContext.xml should work if your web service is using basic authentication.

Note: Comment imported. Original by markmc website: at 2008-02-01 08:32

Mark McLaren said...

Hi Mark,

I am sure it is using basic authentication because when I try to access the webservice through a browser it prompts me for a username/password. And it does not look for any certificate. Will it make any difference if the webservice on the whole is password protected instead of just the endpoint ?

And do I have to modify the stubs as suggested by Alan here

BTW, i tried this approach but does not seem to help.

Am I missing any jars ?


Note: Comment imported. Original by Anonymous at 2008-02-01 17:34

Mark McLaren said...

Hi Jilani,

If the WSDL itself is protected, the following thread suggests an ugly fix (and a possible cause - this was written back in 2004 so it might no longer be true):

The solution given was to pass the username/password as part of the WSDL URL - not ideal.


The thread you mentioned was talking more about Spring-WS rather than the Spring Framework. Spring-WS is not part of the main Spring Framework code. Spring-WS is useful for creating document driven web services (the wsdl first kind!).

You can create web service clients using only the main Spring Framework code.

Note: Comment imported. Original by markmc website: at 2008-02-01 21:27

Mark McLaren said...

Hi Mark,

I had already tried that approach of specifying the username and password in the url but it did not seem to solve the problem and I was still getting the 401 error. I am suprised that such a basic thing (username/password authentication) in web service invocation is so complex to configure in Spring. I don't know what else to do as the web service is not under my control (that I could modify to just secure the endpoint instead of the entire url). I looked at so many different forums online but could not see one example which gives a working version for this issue. May be I should see if there are other options using Spring for accomplishing this task.



Note: Comment imported. Original by Anonymous at 2008-02-03 00:12

Mark McLaren said...

When I call the web service i get an error could not find deserializer for type. I have used Eclipse for the client.

The web service is implemented using Spring. The service endpoints classes for all the requests are extended from AbstractMarshallingPayloadEndpoint.

The part of applicationContext-container.xml under src/main/resources dir is as


The part of spring-ws-servlet.xml under /WEB-INF dir is as


web.xml has







On the client side, I used Axis1.1 WSDL2JAVA to create java classes. I followed the example and created the manual interface, proxy classes etc. on the postProcessJaxRpcService method , i have set the proper request/ response class

registerBeanMapping(mapping, FindDataSummaryListBySearchCriteriaResponse.class, "FindDataSummaryListBySearchCriteriaResponse");

registry.register("", mapping);

I used SoapUI to test the web service and it's working fine.. But when i run the Axis client from my Eclipse i get the error as ERROR org.apache.axis.client.Call - Exception:

org.xml.sax.SAXException: Deserializing parameter 'findDataSummaryListBySearchCriteriaResponse': could not find deserializer

I checked several other example for Web Service with SPring/ Axis and i found that my project web service implementation do not have interface (as we have in client created by Axis) or any deployment file that tells the mapping with serializing/ deserializing class.. pls help me how to fix this issue.

Note: Comment imported. Original by Anonymous at 2008-02-11 05:30

Mark McLaren said...

I would love to help but this looks a little beyond me and I have not yet used Spring-WS. I have only used XFire for producing services, (as CXF is not quite able to do what I want yet). Did you try this without deleting any of the Axis generated classes as suggested by Martin Zdila below?
Note: Comment imported. Original by markmc website: at 2008-02-11 07:50

Mark McLaren said...

yes Marc. i tried deleting those files and without deleting them.. but always get this error.
Note: Comment imported. Original by Anonymous at 2008-02-11 15:04

Mark McLaren said...

I am still not sure but could it be case that is the source of the problem? Have you tried?:

registerBeanMapping(mapping, FindDataSummaryListBySearchCriteriaResponse.class, "findDataSummaryListBySearchCriteriaResponse");

instead of:

registerBeanMapping(mapping, FindDataSummaryListBySearchCriteriaResponse.class, "FindDataSummaryListBySearchCriteriaResponse");

Note: Comment imported. Original by markmc website: at 2008-02-11 17:54

Mark McLaren said...

i had tried that too. but didnt help..
Note: Comment imported. Original by Anonymous at 2008-02-11 22:26

Mark McLaren said...


I looked at several other examples and found that if xalan jar is added to sprin-ws , the Axis client would work it seems.. I tried adding xalan 2.7.0 jar and after then due to several errors, i kept adding the required jars to pom.xml

I tested the Spring WS using soapUI and getting a error like this (the request is received by WS)....

DEBUG transport.http.MessageDispatcherServlet - Could not complete request


Do you have any idea what should be done to this?
Note: Comment imported. Original by Anonymous at 2008-02-12 17:44

Mark McLaren said...

I hope these links help:
Note: Comment imported. Original by markmc website: at 2008-02-12 19:20

Mark McLaren said...

Hi Mark,

The webservice I was trying to invoke was using windows digest authentication (so you would be prompted for a username and password even to read the WSDL) and my code was failing at the part where Axis tries to parse the WSDL itself. So, I think Spring tries to parse the wsdl before it even sets the username and password for the actual invocation. So, in order to solve this problem, I just downloaded the wsdl locally and put it in the classpath so that Spring could read it from there instead of going through authentication at the remote. Also overriding the afterPropertiesSet() method would also help in setting the username/password dynamically for the web service invocation instead of setting in the config file.

public void afterPropertiesSet() {





Thanks once again for your help !


Note: Comment imported. Original by Anonymous at 2008-02-14 15:59

Mark McLaren said...


With Axis client and Spring-ws i could not resolve the issues that i had. Finally i used IBM web service to generate my client code and it works fine now..

I have a different question now...

on the spring-ws-servlet.xml i have the locationUri as

and when the wsdl file gets generated, the soap location is displayed as "/data-ws/services". I have to manually chg it to different server as

"http://devserver:8080/data-ws/services/", "http://uaServer:8080/data-ws/services/" .

Can anyone tell me how to change this remote url for each environment without this manual update?
Note: Comment imported. Original by Anonymous at 2008-02-18 17:34

Mark McLaren said...

I recently answered a very similar question elsewhere on my blog. The short answer is NO! The longer answer is that you can get hold of the ServletContext through Spring's web application context but Server name, server port and context path are properties of the HTTP servlet request. e.g. I can access my blog using: and http://localhost/blog/ and the given values for server and port could change! These values are request specific.

That said, if you would rather put the server URL in a properties file your Spring application context could acquire this value using a PropertyPlaceholderConfigurer.

Note: Comment imported. Original by markmc website: at 2008-02-18 22:06