Spring JAX-WS clients, with less config

More with less. I got rather annoyed at some of the default messages that came out of the JaxWsPortProxyFactoryBean. Things like, “service name blah does not exist in the wsdl, did you mean wop?” Well, SURE! I told you the wsdl, there’s only one service, I mean THAT ONE!

So, I made my own port proxy factory….

Ugly old way

portname, serviceName and namespaceUri are all completely mechanical drudgery, but you have to get them exactly right.

    <bean id="oldStyleClient" class="org.springframework.remoting.jaxws.JaxWsPortProxyFactoryBean">
        <property name="serviceInterface" value="full.class.path.IService"/>
        <property name="wsdlDocumentUrl" value="http://server:port/webapp/services/BlahService?wsdl"/>
        <property name="endpointAddress" value="http://server:port/webapp/services/BlahService"/>
        <property name="lookupServiceOnStartup" value="false"/>
        <property name="portName" value="BlahServiceSOAP"/>
        <property name="serviceName" value="BlahService"/>
        <property name="namespaceUri" value="http://some.namespace/from/the/wsdl/"/>
    </bean>

Sexy new way

Sexy ways are always better ways.

    <bean id="potsClient" class="is.vf.common.jaxws.SimpleJaxWsFactory">
        <property name="serviceInterface" value="full.class.path.IService"/>
        <property name="localWsdlName" value="/BlahService.wsdl"/>
        <property name="endpointAddress" value="http://server:port/webapp/services/BlahService"/>
    </bean>

Hooray! So how? Just xpath into the wsdl! I used dom4j, because I’ve already got that in my app, but you could use anything really. I briefly tried using the xml apis in the jdk, but gave up very quickly.

Full Source below

package blah;
 
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Node;
import org.dom4j.io.SAXReader;
import org.springframework.remoting.jaxws.JaxWsPortProxyFactoryBean;
import java.net.URL;
 
/**
 * Set up a jaxws client with less effort.
 * Originally, I couldn't work out how to get spring/jaxws to reference a local wsdl file that was actually inside a jar.
 * And then, because I was damn sick of having to go and look up hardcoded strings from the wsdl just to copy into the config,
 * I decided to just read the damn wsdl and suck up the necessary blobs myself.
 *
 * No guarantees that this will work on all wsdls, but most people use the wsdl: prefix right?
 * Now, the only _required_ parameters are, localWsdlName and serviceInterface! whee. 
 * @author karlp
 *         Date: 8.2.2010
 */
public class SimpleJaxWsFactory extends JaxWsPortProxyFactoryBean {
    private String localWsdlName;
 
    /**
     * use dom4j to determine what's in the wsdl.
     * (I tried using the java built in methods, but a) it's ugly, and b) it didn't work)
     * Then just go back to the parent to load up the rest of the properties, now that we've done  the tedious ones...
     */
    @Override
    public void afterPropertiesSet() {
        if (localWsdlName != null) {
            URL url = getServiceInterface().getResource(localWsdlName);
            setWsdlDocumentUrl(url);
            Document doc;
            try {
                doc = new SAXReader().read(url);
            } catch (DocumentException e) {
                throw new IllegalStateException("Shouldn't be getting exceptions reading your local wsdl!" + e.getMessage(), e);
            }
            this.setServiceName(doc.selectSingleNode("//wsdl:service/@name").getStringValue());
            this.setPortName(doc.selectSingleNode("//wsdl:service/wsdl:port/@name").getStringValue());
            this.setNamespaceUri(doc.selectSingleNode("/wsdl:definitions/@targetNamespace").getStringValue());
        }
        super.afterPropertiesSet();
    }
 
    /**
     * This is the name of the wsdl, as seen in the jar containing the {@link serviceInterface}
     * @param localWsdlName the path to the wsdl in the containing jar
     */
    public void setLocalWsdlName(String localWsdlName) {
        this.localWsdlName = localWsdlName;
    }
}
  1. Great job–and makes sense. Not to diminish your solution, but why can’t the SpringSource folks do that for us so we don’t have to! I even like your class’ naming convention of “SimpleJaxWsFactory”

    Hey, SpringSource folks–do any of you read this?!?!

Leave a Comment

NOTE - You can use these HTML tags and attributes:
<a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>