CXF, wsdl2java. Пользовательское имя порта

Короткий вопрос: можно ли каким-то образом связать имя wsdl:port для создания пользовательского имени поля Java в службе?

Длинный вопрос: у меня есть wsdl с такой частью:

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

И цель maven wsdl2java, которая генерирует службу с именем 123xxx (которую я уже исправил с привязкой, назвав ее MyService), и внутри этой службы она создает поле:

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

Это вызывает ошибки компиляции, потому что переменные не могут начинаться с чисел в Java. И я не могу найти способ как-то настроить этот сгенерированный код без изменения исходного wsdl.

Итак, есть ли способ связать его через привязки cxf, как это делается с самим сервисом:

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

или может быть есть какие-то другие способы добиться этого?


person Michael Zhavzharov    schedule 14.05.2018    source источник
comment
Я считаю, что это должно быть возможно с использованием привязок jaxb. Посмотрите, поможет ли это? stackoverflow.com/questions/20245639/. В прошлый раз я решил аналогичную проблему с Jaxb, но ответ требовал комплексного подхода   -  person Tarun Lalwani    schedule 17.05.2018


Ответы (4)


Наконец я нашел решение. Конечно, это накладные расходы для обычного процесса генерации wsdl, но это единственный (или почти единственный) способ удовлетворить мои ограничения.

Сначала я проверил исходники библиотеки cxf и обнаружил, что есть способ создания элемента Port:

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

который просто создает JavaPort с именем, полученным из исходного wsdl, и не обрабатывает его с какой-либо привязкой:

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

Идя дальше, я обнаружил, что есть возможность внедрить собственный генератор кода, который отвечает за создание java классов из cxf модели.

После некоторых исследований я нашел этот ответ, который помог мне это сделать.

Поэтому я создал отдельный модуль с таким классом (проверьте комментарии):

//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);
            }
        }
    }
}

и поместил tools-plugin.xml в папку META-INF:

<?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>

(обратите внимание, что я поставил свой собственный генератор перед генератором по умолчанию, чтобы он работал с модифицированной моделью).

Затем я только что изменил свой файл pom в соответствии с ответом, который я разместил выше, и был рад видеть, что он работает.

person Michael Zhavzharov    schedule 19.05.2018

Если вы не привязаны к wsdl2java, используйте wsimport. Он добавит подчеркивание перед любыми переменными, начинающимися с числа. Для этого тоже есть цель maven.

person ACHC    schedule 17.05.2018
comment
Спасибо за совет. Я нашел решение для цели wsdl2java, но ваше предложение было следующим в моем списке. - person Michael Zhavzharov; 20.05.2018

Я предлагаю вам изменить WSDL. Предполагается, что это поле в WSDL имеет тип NCName, который не может начинаться с цифр. Если вы включите проверку WSDL, я думаю, вы получите ошибку непосредственно с синтаксисом WSDL. Поэтому не уверен, что вы сможете исправить это впоследствии с помощью пользовательской привязки.

person Isukthar    schedule 17.05.2018
comment
Спасибо за ответ! Я не могу изменить имя, потому что это wsdl из внешней службы. И изменить его уже тоже не могут, потому что этот wsdl используют какие-то другие внешние сервисы. Но да, вы правы, что проверка NCName сейчас не работает. - person Michael Zhavzharov; 17.05.2018

Как упоминал Тарун Лалвани в комментарии, я считаю, что вы должны использовать привязки jaxb следующим образом:

<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>

файл привязки:

<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>

см. Настройка JAXWS

person Dams    schedule 17.05.2018
comment
извините, но ваша привязка не будет работать для имени поля порта внутри класса обслуживания. Дело не в имени класса PortType. - person Michael Zhavzharov; 20.05.2018