In the JAX-WS programming model to develop a web services client you would compile the deployed WSDL using wsimport and then at runtime the same WSDL is used to determine binding information. The runtime accesses the WSDL over the network, but sometimes because of the size of the WSDL or for whatever reason (such as you want to edit it to fix workaround some bug, dangerous but we do it sometimes) you may like to keep the WSDL locally and would expect the runtime to access the local wsdl. It does not happen automatically.

There are the different ways in which you can provide the local WSDL information to the JAX-WS runtime:

Use Service API to pass the WSDL information

Sample service creation using local WSDL
        URL baseUrl = client.MtomService.class.getResource(".");
        URL url = new URL(baseUrl, "../Soap11MtomUtf8.svc.xml");
        MtomService service = new MtomService(url, new QName("http://tempuri.org/", "MtomService"));
        IMtomTest proxy = service.getBasicHttpBindingIMtomTest();
        String input="Hello World";
        byte[] response = proxy.echoStringAsBinary(input);
   

Xml Catalog

This works well but requires some work, such as composing the right catalog file then package it appropriately.

Using -wsdlLocation switch

There is another easy way to do it - just run wsimport with -wsdlLocation switch and provide the WSDL location value which is relative to the generated Service class and you need to put this WSDL file at this relative location.

Let us try to create a client for the NET 3.0 MTOM endpoint. I am using Metro 1.0 M5.

First I save the .NET 3.0 MTOM WSDLlocally then run wsimport giving the relative location to where you will package the wsdl with your application Sample wsimport command

        wsimport -keep -d build/classes -p client etc/Soap11MtomUtf8.svc.xml -wsdlLocation ../Soap11MtomUtf8.svc.xml
   
    
tip.pngWhy is the relative location is ../Soap11MtomUtf8.svc.xml? Basically the generated Service will be at build/classes/client location and I would copy this WSDL at build/classes, see option -d and -p.

Here is excerpt from the generated MtomService class. You can see how the wsdlLocation value is generated inside it and is used internally to create the Service.

        /**
        * This class was generated by the JAX-WS RI.
        * JAX-WS RI 2.1.2-hudson-53-SNAPSHOT
        * Generated source version: 2.1
        *
        */
        @WebServiceClient(name = "MtomService", targetNamespace = "http://tempuri.org/", ../Soap11MtomUtf8.svc.xml")
        public class MtomService
        extends Service{

            private final static URL MTOMSERVICE_WSDL_LOCATION;
            private final static Logger logger = Logger.getLogger(client.MtomService.class.getName());

            static {
                URL url = null;
                try {
                    URL baseUrl;

                    baseUrl = client.MtomService.class.getResource(".");
                    url = new URL(baseUrl, "../Soap11MtomUtf8.svc.xml");
                } catch (MalformedURLException e) {
                    logger.warning("Failed to create URL for the wsdl Location: ../Soap11MtomUtf8.svc.xml");
                    logger.warning(e.getMessage());
                }
                MTOMSERVICE_WSDL_LOCATION = url;
            }

            public MtomService() {
                super(MTOMSERVICE_WSDL_LOCATION, new QName("http://tempuri.org/", "MtomService"));
            }

            ...
   

See Client.java below it invokes the .NET 3.0 service. You may notice here that you dont need to enable MTOM explicitly. Metro bring in .NET 3.0 interop thru WSIT and due to this the MTOM policy assertions in the .NET 3.0 WSDL, it correctly interpreted and the IMtomTest port is configured with MTOM enabled.

package client;

import com.sun.xml.ws.transport.http.client.HttpTransportPipe;

/**
 * Client that invokes .NET 3.0 MTOM endpoint using a local wsdl
 */
public class Client {

    public static void main(String[] args) {

        //enble SOAP Message logging
        HttpTransportPipe.dump = true;

        //Create IMtomTest proxy to invoke .NET 3.0 MTOM service
        IMtomTest proxy = new MtomService().getBasicHttpBindingIMtomTest();
        String input="Hello World";
        byte[] response = proxy.echoStringAsBinary(input);
        System.out.println("Sent: "+input+", Received: "+new String(response));
    }
}

Get the complete client bundle from here and see the enclosed Readme.txt for instructions on how to run it.