Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to avoid the need to specify the WSDL location in a CXF or JAX-WS generated webservice client?

People also ask

What is CXF in WSDL?

Advertisements. The CXF-POJO application that you have developed results in a very tight coupling between the client and the server. Giving a direct access to the service interface can also pose severe security threats.

What is WSDL location?

Typically, all WSDL or XSD files are initially placed into the META-INF/wsdl directory when using Enterprise JavaBeans (EJB) or the WEB-INF/wsdl directory when using Java™.

What is CXF used for?

Overview. Apache CXF™ is an open source services framework. CXF helps you build and develop services using frontend programming APIs, like JAX-WS and JAX-RS. These services can speak a variety of protocols such as SOAP, XML/HTTP, RESTful HTTP, or CORBA and work over a variety of transports such as HTTP, JMS or JBI.


I finally figured out the right answer to this question today.

<plugin>
    <groupId>org.apache.cxf</groupId>
    <artifactId>cxf-codegen-plugin</artifactId>
    <version>${cxf.version}</version>
    <executions>
        <execution>
            <id>generate-sources</id>
            <phase>generate-sources</phase>
            <configuration> 
                <sourceRoot>${project.build.directory}/generated-sources/cxf</sourceRoot>
                <wsdlOptions>
                    <wsdlOption>
                        <wsdl>${project.basedir}/src/main/resources/wsdl/FooService.wsdl</wsdl>
                        <wsdlLocation>classpath:wsdl/FooService.wsdl</wsdlLocation>
                    </wsdlOption>
                </wsdlOptions>
            </configuration>
            <goals>
                <goal>wsdl2java</goal>
            </goals>
        </execution>
    </executions>
</plugin>

Notice that I have prefixed the value in wsdlLocation with classpath:. This tells the plugin that the wsdl will be on the classpath instead of an absolute path. Then it will generate code similar to this:

@WebServiceClient(name = "FooService", 
                  wsdlLocation = "classpath:wsdl/FooService.wsdl",
                  targetNamespace = "http://org/example/foo") 
public class Foo_Service extends Service {

    public final static URL WSDL_LOCATION;

    public final static QName SERVICE = new QName("http://org/example/foo", "Foo");
    public final static QName FooSOAPOverHTTP = new QName("http://org/example/foo", "Foo_SOAPOverHTTP");
    static {
        URL url = Foo_Service.class.getClassLoader().getResource("wsdl/FooService.wsdl");
        if (url == null) {
            java.util.logging.Logger.getLogger(Foo_Service.class.getName())
                .log(java.util.logging.Level.INFO, 
                     "Can not initialize the default wsdl from {0}", "classpath:wsdl/FooService.wsdl");
        }       
        WSDL_LOCATION = url;
    }

Note that this only works with version 2.4.1 or newer of the cxf-codegen-plugin.


We use

wsdlLocation = "WEB-INF/wsdl/WSDL.wsdl"

In other words, use a path relative to the classpath.

I believe the WSDL may be needed at runtime for validation of messages during marshal/unmarshal.


For those using org.jvnet.jax-ws-commons:jaxws-maven-plugin to generate a client from WSDL at build-time:

  • Place the WSDL somewhere in your src/main/resources
  • Do not prefix the wsdlLocation with classpath:
  • Do prefix the wsdlLocation with /

Example:

  • WSDL is stored in /src/main/resources/foo/bar.wsdl
  • Configure jaxws-maven-plugin with <wsdlDirectory>${basedir}/src/main/resources/foo</wsdlDirectory> and <wsdlLocation>/foo/bar.wsdl</wsdlLocation>

1) In some cases, yes. If the WSDL contains things like Policies and such that direct the runtime behavior, then the WSDL may be required at runtime. Artifacts are not generated for policy related things and such. Also, in some obscure RPC/Literal cases, not all the namespaces that are needed are output in the generated code (per spec). Thus, the wsdl would be needed for them. Obscure cases though.

2) I thought something like would work. What version of CXF? That sounds like a bug. You can try an empty string in there (just spaces). Not sure if that works or not. That said, in your code, you can use the constructor that takes the WSDL URL and just pass null. The wsdl wouldn't be used.

3) Just the limitations above.


I was able to generate

static {
    WSDL_LOCATION = null;
}

by configuring pom file to have a null for wsdlurl:

    <plugin>
        <groupId>org.apache.cxf</groupId>
        <artifactId>cxf-codegen-plugin</artifactId>
        <executions>
            <execution>
                <id>generate-sources</id>
                <phase>generate-sources</phase>
                <configuration>
                    <sourceRoot>${basedir}/target/generated/src/main/java</sourceRoot>
                    <wsdlOptions>
                        <wsdlOption>
                            <wsdl>${basedir}/src/main/resources/service.wsdl</wsdl>
                            <extraargs>
                                <extraarg>-client</extraarg>
                                <extraarg>-wsdlLocation</extraarg>
                                <wsdlurl />
                            </extraargs>
                        </wsdlOption>
                    </wsdlOptions>
                </configuration>
                <goals>
                    <goal>wsdl2java</goal>
                </goals>
            </execution>
        </executions>
    </plugin>