1

Short question: Can I somehow bind wsdl:port name to generate custom java field name in service?

Long question: I have a wsdl with such part:

<wsdl:service name="123xxx">
   <wsdl:port name="123xxxHttpSoap11Endpoint" binding="tns:123xxxSoap11Binding">
     <soap:address location="..."/>
   </wsdl:port>
</wsdl:service>

And a maven wsdl2java goal which generates the service with name 123xxx (which I've already fixed with binding by calling it MyService) and inside this service it generates a field:

public class MyService extends Service {
    ...
    public final static QName 123xxxHttpSoap11Endpoint = 
                 new QName("http://new.webservice.namespace", "123xxxHttpSoap11Endpoint");
    ...
}

This causing a compile errors because variables can't start with numbers in Java. And I can't find a way to somehow customize this generated code without changing the original wsdl.

So, is there a way to bind it through the cxf bindings, like it is done with service itself:

<bindings...>
    <bindings node="wsdl:definitions/wsdl:service">
    <class name="MyService"/>
    </bindings>
</bindings>

or may be there are some other ways to achive this?

Michael Zhavzharov
  • 1,727
  • 13
  • 26
  • It should be possible using jaxb bindings I believe. See if this helps? https://stackoverflow.com/questions/20245639/how-to-change-the-name-of-a-webservice-using-cxf. Last time I solved a similar [issue](https://stackoverflow.com/questions/18667358/jaxb-binding-schema-of-dtd-file/49835844#49835844) with Jaxb, but the answer required a complex approach – Tarun Lalwani May 17 '18 at 11:50

4 Answers4

6

Finally I found the solution. Of course it's an overhead for common wsdl-generating process, but it is only (or almost only) the way to satisfy my restrictions.

First I've checked the sources of the cxf library and found that there is a method for generating Port element:

org.apache.cxf.tools.wsdlto.frontend.jaxws.processor.internal.ServiceProcessor#processPort

which just creates JavaPort with name, fetched from the original wsdl and does not process it with any binding:

JavaPort jport = new JavaPort(NameUtil.mangleNameToClassName(port.getName().getLocalPart()));

Going further I found that there is a possibility to inject custom code generator, which is responsible for creation of java classes from cxf model.

After some research I found this answer which helped me to make it.

So I've created a separate module with such class (check comments):

//note that I've put my class inside the package, 
//which is used for other default generators in cxf
package org.apache.cxf.tools.wsdlto.frontend.jaxws.generators;

import java.util.List;
import java.util.Map;

import org.apache.cxf.tools.common.ToolContext;
import org.apache.cxf.tools.common.ToolException;
import org.apache.cxf.tools.common.model.JavaPort;
import org.apache.cxf.tools.common.model.JavaServiceClass;

public class CustomSEIGenerator extends SEIGenerator {

    @Override
    public void generate(ToolContext penv) throws ToolException {
        //no streams, because we still on java 7
        //fetch all services
        Map<String, JavaServiceClass> ss = penv.getJavaModel().getServiceClasses();
        for (Map.Entry<String, JavaServiceClass> s : ss.entrySet()) {
            //fetch all ports from each service
            for (JavaPort port : s.getValue().getPorts()) {
                //set custom name to each port
                port.setName("_" + port.getName);
            }
        }
    }
}

and placed a tools-plugin.xml into META-INF folder:

<?xml version="1.0" encoding="utf-8"?>
<plugin xmlns="http://cxf.apache.org/tools/plugin" name="play" version="" provider="play.typesafe.com">
    <frontend name="sample" package="org.apache.cxf.tools.wsdlto.frontend.jaxws" profile="JAXWSProfile">
        <container name="JAXWSContainer" package="org.apache.cxf.tools.wsdlto.frontend.jaxws" toolspec="jaxws-toolspec.xml"/>
        <processor name="WSDLToJavaProcessor" package="org.apache.cxf.tools.wsdlto.frontend.jaxws.processor"/>
        <builder name="JAXWSDefinitionBuilder" package="org.apache.cxf.tools.wsdlto.frontend.jaxws.wsdl11"/>
        <generators package="org.apache.cxf.tools.wsdlto.frontend.jaxws.generators">
            <generator name="CustomSEIGenerator"/>
            <generator name="AntGenerator"/>
            <generator name="ClientGenerator"/>
            <generator name="FaultGenerator"/>
            <generator name="ImplGenerator"/>
            <generator name="SEIGenerator"/>
            <generator name="ServerGenerator"/>
            <generator name="ServiceGenerator"/>
        </generators>
    </frontend>
</plugin>

(note that I've put my custom generator before default ones to make them work with modified model).

Next I've just modified my pom file according to the answer, which I've posted above, and was happy to see it's working.

Michael Zhavzharov
  • 1,727
  • 13
  • 26
3

Unless you're tied to wsdl2java, use wsimport instead. It will add an underscore before any variables starting with a number. There is a maven goal for it too.

ACHC
  • 312
  • 1
  • 2
  • 10
2

I suggest you change the WSDL. This field in WSDL is supposed to have NCName type that can't start with numbers. If you enable WSDL validation, I think you'll get an error directly with WSDL syntax. So, not sure you can correct this afterwise with custom binding.

Isukthar
  • 185
  • 8
  • Thanks for the answer! I can't change the naming, because it's a wsdl from external service. And they also can't change it already, because some other external services use this wsdl. But yes, you are right that NCName validation is failing now. – Michael Zhavzharov May 17 '18 at 09:25
2

As mentioned by Tarun Lalwani in comment I thing you should use jaxb bindings like this :

<plugin>
    <groupId>org.apache.cxf</groupId>
        <artifactId>cxf-codegen-plugin</artifactId>
        <version>${cxf.version}</version>
        <executions>
            <execution>
                <phase>generate-sources</phase>
                <configuration>
                    <sourceRoot>
                        ${basedir}/src/main/java
                    </sourceRoot>
                    <wsdlOptions>
                        <wsdlOption>
                            <wsdl>
                                ${basedir}/xxx/yourwsdl.wsdl
                            </wsdl>
                                <extraargs>
                                <!-- you can redefine the client -->
                                <extraarg>-client</extraarg>
                                <extraarg>-b</extraarg>
                                <extraarg>${basedir}/xxx/binding.xml</extraarg>
                    </extraargs>
                    </wsdlOption>
                </wsdlOptions>
            </configuration>
            <goals>
                <goal>wsdl2java</goal>
            </goals>
        </execution>
    </executions>
</plugin>

the binding file :

<bindings
    xmlns:xsd="http://www.w3.org/2001/XMLSchema"
    xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"
    wsdlLocation="yourwsdl.wsdl"
    xmlns="http://java.sun.com/xml/ns/jaxws">

    <bindings node="wsdl:definitions/wsdl:portType[@name='123xxxHttpSoap11Endpoint']">
    <class name="yourservice"/>
    </bindings>
</bindings>

see JAXWS Customization

Dams
  • 997
  • 12
  • 28