¿Cómo evitar la necesidad de especificar la ubicación WSDL en un cliente webservice generado por CXF o JAX-WS?


Cuando genero un cliente webservice usando wsdl2java desde CXF (que genera algo similar a wsimport), a través de maven, mis servicios comienzan con códigos como este:

@WebServiceClient(name = "StatusManagement", 
                  wsdlLocation = "c:/some_absolute_path_to_a_wsdl_file.wsdl",
                  targetNamespace = "http://tempuri.org/") 
public class StatusManagement extends Service {

    public final static URL WSDL_LOCATION;
    public final static QName SERVICE = new QName("http://tempuri.org/", "StatusManagement");
    public final static QName WSHttpBindingIStatus = new QName("http://tempuri.org/", "WSHttpBinding_IStatus");
    static {
        URL url = null;
        try {
            url = new URL("c:/some_absolute_path_to_a_wsdl_file.wsdl");
        } catch (MalformedURLException e) {
            System.err.println("Can not initialize the default wsdl from c:/some_absolute_path_to_a_wsdl_file.wsdl");
            // e.printStackTrace();
        }
        WSDL_LOCATION = url;
    }

El camino absoluto codificado realmente apesta. La clase generada no funcionará en ningún otro equipo que no sea el mío.

La primera idea es poner el archivo WSDL (más todo lo que importa, otros WSDLs y XSDs) en algún lugar de un archivo jar y classpath. Pero queremos evitar esto. Ya que todo eso era generado por CXF y JAXB basado en los WSDLs y XSDs, no vemos ningún punto en la necesidad de conocer el WSDL en tiempo de ejecución.

El atributo wsdlLocation pretende anular la ubicación WSDL (al menos esto es lo que leí en alguna parte), y su valor predeterminado es "". Ya que estamos usando maven, intentamos incluir <wsdlLocation></wsdlLocation> dentro de la configuración de CXF para intentar forzar al generador de fuentes a dejar en blanco el wsdlLocation. Sin embargo, esto simplemente hace que ignore la etiqueta XML porque está vacía. Hicimos un realmente feo hack vergonzoso, usando <wsdlLocation>" + "</wsdlLocation>.

Esto cambia otros lugares también:

@WebServiceClient(name = "StatusManagement", 
                  wsdlLocation = "" + "",
                  targetNamespace = "http://tempuri.org/") 
public class StatusManagement extends Service {

    public final static URL WSDL_LOCATION;
    public final static QName SERVICE = new QName("http://tempuri.org/", "StatusManagement");
    public final static QName WSHttpBindingIStatus = new QName("http://tempuri.org/", "WSHttpBinding_IStatus");
    static {
        URL url = null;
        try {
            url = new URL("" + "");
        } catch (MalformedURLException e) {
            System.err.println("Can not initialize the default wsdl from " + "");
            // e.printStackTrace();
        }
        WSDL_LOCATION = url;
    }

Entonces, mis preguntas son:

  1. ¿Realmente necesitamos una ubicación WSDL incluso si todas las clases fueron generadas por CXF y JAXB? En caso afirmativo, ¿por qué?

  2. Si realmente no necesitamos la ubicación WSDL, ¿cuál es la forma correcta y limpia de hacer que CXF no lo genere y lo evite por completo?

  3. ¿Qué efectos secundarios podríamos tener con ese hackeo? Todavía no podemos probar eso para ver qué pasa, así que si alguien pudiera decirlo de antemano, sería bueno.

Author: Donal Fellows, 2010-12-16

8 answers

Finalmente descubrí la respuesta correcta a esta pregunta hoy.

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

Observe que he prefijado el valor en wsdlLocation con classpath:. Esto le dice al plugin que el wsdl estará en la ruta de clase en lugar de una ruta absoluta. Luego generará código similar a este:

@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;
    }

Tenga en cuenta que esto solo funciona con la versión 2.4.1 o posterior del complemento cxf-codegen.

 186
Author: Kyle,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-09-12 11:54:41

Usamos

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

En otras palabras, use una ruta relativa a la ruta de clase.

Creo que el WSDL puede ser necesario en tiempo de ejecución para la validación de mensajes durante marshal/unmshal.

 19
Author: BPS,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-01-13 16:05:49

1) En algunos casos, sí. Si el WSDL contiene cosas como Políticas y tales que dirigen el comportamiento de tiempo de ejecución, entonces el WSDL puede ser requerido en tiempo de ejecución. Los artefactos no se generan para cosas relacionadas con la política y cosas por el estilo. Además, en algunos casos RPC/Literales oscuros, no todos los espacios de nombres que se necesitan se generan en el código generado (por especificación). Por lo tanto, el wsdl sería necesario para ellos. Casos oscuros sin embargo.

2) Pensé que algo así funcionaría. ¿Qué versión de CXF? Que suena como un bicho. Puedes probar con una cadena vacía (solo espacios). No estoy seguro si eso funciona o no. Dicho esto, en su código, puede usar el constructor que toma la URL WSDL y simplemente pasa null. El wsdl no se usaría.

3) Solo las limitaciones anteriores.

 9
Author: Daniel Kulp,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-12-15 22:03:14

Para aquellos que usan org.jvnet.jax-ws-commons:jaxws-maven-plugin para generar un cliente desde WSDL en tiempo de compilación:

  • Coloque el WSDL en algún lugar de su src/main/resources
  • Do not prefix the wsdlLocation with classpath:
  • Prefije wsdlLocation con /

Ejemplo:

  • WSDL se almacena en /src/main/resources/foo/bar.wsdl
  • Configure jaxws-maven-plugin con <wsdlDirectory>${basedir}/src/main/resources/foo</wsdlDirectory> y <wsdlLocation>/foo/bar.wsdl</wsdlLocation>
 9
Author: Martin Devillers,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-09-10 11:14:14

¿Es posible que pueda evitar el uso de wsdl2java? Puede usar de inmediato las API de FrontEnd de CXF para invocar su servicio web SOAP. El único problema es que necesita crear su SEI y VOs en el extremo de su cliente. Aquí hay un código de ejemplo.

package com.aranin.weblog4j.client;

import com.aranin.weblog4j.services.BookShelfService;
import com.aranin.weblog4j.vo.BookVO;
import org.apache.cxf.jaxws.JaxWsProxyFactoryBean;

public class DemoClient {
    public static void main(String[] args){
        String serviceUrl = "http://localhost:8080/weblog4jdemo/bookshelfservice";
        JaxWsProxyFactoryBean factory = new JaxWsProxyFactoryBean();
        factory.setServiceClass(BookShelfService.class);
        factory.setAddress(serviceUrl);
        BookShelfService bookService = (BookShelfService) factory.create();

        //insert book
        BookVO bookVO = new BookVO();
        bookVO.setAuthor("Issac Asimov");
        bookVO.setBookName("Foundation and Earth");

        String result = bookService.insertBook(bookVO);

        System.out.println("result : " + result);

        bookVO = new BookVO();
        bookVO.setAuthor("Issac Asimov");
        bookVO.setBookName("Foundation and Empire");

        result = bookService.insertBook(bookVO);

        System.out.println("result : " + result);

        bookVO = new BookVO();
        bookVO.setAuthor("Arthur C Clarke");
        bookVO.setBookName("Rama Revealed");

        result = bookService.insertBook(bookVO);

        System.out.println("result : " + result);

        //retrieve book

        bookVO = bookService.getBook("Foundation and Earth");

        System.out.println("book name : " + bookVO.getBookName());
        System.out.println("book author : " + bookVO.getAuthor());

    }
}

Puedes ver el tutorial completo aquí http://weblog4j.com/2012/05/01/developing-soap-web-service-using-apache-cxf/

 4
Author: Niraj Singh,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-03-29 04:49:31

Fui capaz de generar

static {
    WSDL_LOCATION = null;
}

Configurando el archivo pom para que tenga un null para 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>
 4
Author: raisercostin,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-03-26 22:05:29

Actualización para CXF 3.1.7

En mi caso puse los archivos WSDL en src/main/resources y agregué esta ruta a mis Srouces en Eclipse (Haga clic derecho en Proyecto-> Ruta de compilación -> Configurar ruta de compilación...- >Fuente [Tab] - > Añadir carpeta).

Así es como se ve mi archivo pom y como se puede ver no hay wsdlLocation opción necesaria:

       <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/cxf</sourceRoot>
                        <wsdlOptions>
                            <wsdlOption>
                                <wsdl>classpath:wsdl/FOO_SERVICE.wsdl</wsdl>
                            </wsdlOption>
                        </wsdlOptions>
                    </configuration>
                    <goals>
                        <goal>wsdl2java</goal>
                    </goals>
                </execution>
            </executions>
        </plugin>

Y aquí está el Servicio generado. Como se puede ver, la URL es get de ClassLoader y no del Archivo Absoluto-Path

@WebServiceClient(name = "EventService", 
              wsdlLocation = "classpath:wsdl/FOO_SERVICE.wsdl",
              targetNamespace = "http://www.sas.com/xml/schema/sas-svcs/rtdm-1.1/wsdl/") 
public class EventService extends Service {

public final static URL WSDL_LOCATION;

public final static QName SERVICE = new QName("http://www.sas.com/xml/schema/sas-svcs/rtdm-1.1/wsdl/", "EventService");
public final static QName EventPort = new QName("http://www.sas.com/xml/schema/sas-svcs/rtdm-1.1/wsdl/", "EventPort");
static {
    URL url = EventService.class.getClassLoader().getResource("wsdl/FOO_SERVICE.wsdl");
    if (url == null) {
        java.util.logging.Logger.getLogger(EventService.class.getName())
            .log(java.util.logging.Level.INFO, 
                 "Can not initialize the default wsdl from {0}", "classpath:wsdl/FOO_SERVICE.wsdl");
    }       
    WSDL_LOCATION = url;   
}
 4
Author: Mazy,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-03-26 22:06:20

En serio, la respuesta principal no está funcionando para mí. probé cxf.versión 2.4.1 y 3.0.10. y generar ruta absoluta con wsdlLocation cada vez.

Mi solución es usar el comando wsdl2java en el apache-cxf-3.0.10\bin\ con -wsdlLocation classpath:wsdl/QueryService.wsdl.

Detalle:

    wsdl2java -encoding utf-8 -p com.jeiao.boss.testQueryService -impl -wsdlLocation classpath:wsdl/testQueryService.wsdl http://127.0.0.1:9999/platf/testQueryService?wsdl
 2
Author: jeiao,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-03-26 22:07:48