El problema es que necesito crear un cliente de servicio web a partir de un archivo que me han proporcionado. He almacenado este archivo en el sistema de archivos local y, aunque guardo el archivo WSDL en la carpeta del sistema de archivos correcta, todo está bien. Cuando lo implemento en un servidor o elimino el WSDL de la carpeta del sistema de archivos, el proxy no puede encontrar el WSDL y aparece un error. Busqué en la web y encontré las siguientes publicaciones todavía no he podido hacer que funcione:
JAX-WS Cargando WSDL desde jar
http://www.java.net/forum/topic/glassfish/metro -y-jaxb / client-jar-cant-find-local-wsdl-0
http://blog.vinodsingh.com/2008/12/locally-packaged-wsdl.html
Estoy usando NetBeans 6.1 (esta es una aplicación heredada que debo actualizar con este nuevo cliente de servicio web). A continuación se muestra la clase de proxy JAX-WS:
@WebServiceClient(name = "SOAService", targetNamespace = "http://soaservice.eci.ibm.com/", wsdlLocation = "file:/C:/local/path/to/wsdl/SOAService.wsdl")
public class SOAService
extends Service
{
private final static URL SOASERVICE_WSDL_LOCATION;
private final static Logger logger = Logger.getLogger(com.ibm.eci.soaservice.SOAService.class.getName());
static {
URL url = null;
try {
URL baseUrl;
baseUrl = com.ibm.eci.soaservice.SOAService.class.getResource(".");
url = new URL(baseUrl, "file:/C:/local/path/to/wsdl/SOAService.wsdl");
} catch (MalformedURLException e) {
logger.warning("Failed to create URL for the wsdl Location: 'file:/C:/local/path/to/wsdl/SOAService.wsdl', retrying as a local file");
logger.warning(e.getMessage());
}
SOASERVICE_WSDL_LOCATION = url;
}
public SOAService(URL wsdlLocation, QName serviceName) {
super(wsdlLocation, serviceName);
}
public SOAService() {
super(SOASERVICE_WSDL_LOCATION, new QName("http://soaservice.eci.ibm.com/", "SOAService"));
}
/**
* @return
* returns SOAServiceSoap
*/
@WebEndpoint(name = "SOAServiceSOAP")
public SOAServiceSoap getSOAServiceSOAP() {
return super.getPort(new QName("http://soaservice.eci.ibm.com/", "SOAServiceSOAP"), SOAServiceSoap.class);
}
/**
* @param features
* A list of {@link javax.xml.ws.WebServiceFeature} to configure on the proxy. Supported features not in the <code>features</code> parameter will have their default values.
* @return
* returns SOAServiceSoap
*/
@WebEndpoint(name = "SOAServiceSOAP")
public SOAServiceSoap getSOAServiceSOAP(WebServiceFeature... features) {
return super.getPort(new QName("http://soaservice.eci.ibm.com/", "SOAServiceSOAP"), SOAServiceSoap.class, features);
}
}
Este es mi código para usar el proxy:
WebServiceClient annotation = SOAService.class.getAnnotation(WebServiceClient.class);
// trying to replicate proxy settings
URL baseUrl = com.ibm.eci.soaservice.SOAService.class.getResource("");//note : proxy uses "."
URL url = new URL(baseUrl, "/WEB-INF/wsdl/client/SOAService.wsdl");
//URL wsdlUrl = this.getClass().getResource("/META-INF/wsdl/SOAService.wsdl");
SOAService serviceObj = new SOAService(url, new QName(annotation.targetNamespace(), annotation.name()));
proxy = serviceObj.getSOAServiceSOAP();
/* baseUrl;
//classes\com\ibm\eci\soaservice
//URL url = new URL(baseUrl, "../../../../wsdl/SOAService.wsdl");
proxy = new SOAService().getSOAServiceSOAP();*/
//updating service endpoint
Map<String, Object> ctxt = ((BindingProvider)proxy ).getRequestContext();
ctxt.put(JAXWSProperties.HTTP_CLIENT_STREAMING_CHUNK_SIZE, 8192);
ctxt.put(BindingProvider.ENDPOINT_ADDRESS_PROPERTY, WebServiceUrl);
NetBeans colocó una copia del WSDL en web-inf / wsdl / client / SOAService , así que no quiero agregarlo también a META-INF . Las clases de servicio están en WEB-INF / classes / com / ibm / eci / soaservice / y la variable baseurl contiene la ruta completa del sistema de archivos (c: \ path \ to \ the \ project ... \ soaservice). El código anterior genera el error:
javax.xml.ws.WebServiceException: no se pudo acceder al WSDL en: archivo: /WEB-INF/wsdl/client/SOAService.wsdl. Falló con: \ WEB-INF \ wsdl \ client \ SOAService.wsdl (no se puede encontrar la ruta)
Entonces, en primer lugar, ¿debo actualizar la ubicación wsd de la clase de proxy? Entonces, ¿cómo le digo a la clase SOAService en WEB-INF / classes / com / ibm / eci / soaservice que busque el WSDL en \ WEB-INF \ wsdl \ client \ SOAService.wsdl?
EDITADO : Encontré este otro enlace: http://jianmingli.com/wp/?cat=41 , que dice poner el WSDL en el classpath. Me avergüenza preguntar: ¿cómo lo coloco en la ruta de clases de la aplicación web?
Respuestas:
La mejor opción es usar jax-ws-catalog.xml
Cuando compile el archivo WSDL local, anule la ubicación WSDL y configúrelo en algo como
No se preocupe, esto es solo un URI y no una URL, lo que significa que no tiene que tener el WSDL disponible en esa dirección.
Puede hacer esto pasando la opción wsdllocation al compilador wsdl to java.
Hacerlo cambiará su código proxy de
static { URL url = null; try { URL baseUrl; baseUrl = com.ibm.eci.soaservice.SOAService.class.getResource("."); url = new URL(baseUrl, "file:/C:/local/path/to/wsdl/SOAService.wsdl"); } catch (MalformedURLException e) { logger.warning("Failed to create URL for the wsdl Location: 'file:/C:/local/path/to/wsdl/SOAService.wsdl', retrying as a local file"); logger.warning(e.getMessage()); } SOASERVICE_WSDL_LOCATION = url; }
a
static { URL url = null; try { URL baseUrl; baseUrl = com.ibm.eci.soaservice.SOAService.class.getResource("."); url = new URL(baseUrl, "http://localhost/wsdl/SOAService.wsdl"); } catch (MalformedURLException e) { logger.warning("Failed to create URL for the wsdl Location: 'http://localhost/wsdl/SOAService.wsdl', retrying as a local file"); logger.warning(e.getMessage()); } SOASERVICE_WSDL_LOCATION = url; }
Archivo de aviso: // cambiado a http: // en el constructor de URL.
Ahora viene en jax-ws-catalog.xml. Sin jax-ws-catalog.xml, jax-ws intentará cargar el WSDL desde la ubicación
y fallar, ya que tal WSDL no estará disponible.Pero con jax-ws-catalog.xml puede redirigir jax-ws a un WSDL empaquetado localmente siempre que intente acceder al WSDL @
.Aquí está jax-ws-catalog.xml
<catalog xmlns="urn:oasis:names:tc:entity:xmlns:xml:catalog" prefer="system"> <system systemId="http://localhost/wsdl/SOAService.wsdl" uri="wsdl/SOAService.wsdl"/> </catalog>
Lo que está haciendo es decirle a jax-ws que siempre que necesite cargar WSDL desde
, debería cargarlo desde la ruta local wsdl / SOAService.wsdl.Ahora, ¿dónde debería poner wsdl / SOAService.wsdl y jax-ws-catalog.xml? Esa es la pregunta del millón de dólares, ¿no?
Debe estar en el directorio META-INF de su aplicación jar.
entonces algo como esto
De esta manera, ni siquiera tiene que anular la URL en su cliente que accede al proxy. El WSDL se obtiene de su JAR y evita tener que tener rutas de sistema de archivos codificadas en su código.
Más información en jax-ws-catalog.xml http://jax-ws.java.net/nonav/2.1.2m1/docs/catalog-support.html
Espero que ayude
fuente
Otro enfoque que hemos adoptado con éxito es generar el código proxy del cliente WS usando wsimport (de Ant, como una tarea Ant) y especificar el atributo wsdlLocation.
<wsimport debug="true" keep="true" verbose="false" target="2.1" sourcedestdir="${generated.client}" wsdl="${src}${wsdl.file}" wsdlLocation="${wsdl.file}"> </wsimport>
Dado que ejecutamos esto para un proyecto con múltiples WSDL, el script resuelve el valor $ (wsdl.file} dinámicamente que está configurado para ser /META-INF/wsdl/YourWebServiceName.wsdl relativo a la ubicación de JavaSource (o / src, dependiendo de cómo haya configurado su proyecto). Durante el proceso de compilación, los archivos WSDL y XSDs se copian en esta ubicación y se empaquetan en el archivo JAR. (similar a la solución descrita por Bhasakar anteriormente)
Nota: asegúrese de que los archivos WSDL utilicen referencias relativas a los XSD importados y no a las URL http:
<types> <xsd:schema> <xsd:import namespace="http://valueobject.common.services.xyz.com/" schemaLocation="YourWebService_schema1.xsd"/> </xsd:schema> <xsd:schema> <xsd:import namespace="http://exceptions.util.xyz.com/" schemaLocation="YourWebService_schema2.xsd"/> </xsd:schema> </types>
En el código generado , encontramos esto:
/** * This class was generated by the JAX-WS RI. * JAX-WS RI 2.2-b05- * Generated source version: 2.1 * */ @WebServiceClient(name = "YourService", targetNamespace = "http://test.webservice.services.xyz.com/", wsdlLocation = "/META-INF/wsdl/YourService.wsdl") public class YourService_Service extends Service { private final static URL YOURWEBSERVICE_WSDL_LOCATION; private final static WebServiceException YOURWEBSERVICE_EXCEPTION; private final static QName YOURWEBSERVICE_QNAME = new QName("http://test.webservice.services.xyz.com/", "YourService"); static { YOURWEBSERVICE_WSDL_LOCATION = com.xyz.services.webservice.test.YourService_Service.class.getResource("/META-INF/wsdl/YourService.wsdl"); WebServiceException e = null; if (YOURWEBSERVICE_WSDL_LOCATION == null) { e = new WebServiceException("Cannot find '/META-INF/wsdl/YourService.wsdl' wsdl. Place the resource correctly in the classpath."); } YOURWEBSERVICE_EXCEPTION = e; } public YourService_Service() { super(__getWsdlLocation(), YOURWEBSERVICE_QNAME); } public YourService_Service(URL wsdlLocation, QName serviceName) { super(wsdlLocation, serviceName); } /** * * @return * returns YourService */ @WebEndpoint(name = "YourServicePort") public YourService getYourServicePort() { return super.getPort(new QName("http://test.webservice.services.xyz.com/", "YourServicePort"), YourService.class); } /** * * @param features * A list of {@link javax.xml.ws.WebServiceFeature} to configure on the proxy. Supported features not in the <code>features</code> parameter will have their default values. * @return * returns YourService */ @WebEndpoint(name = "YourServicePort") public YourService getYourServicePort(WebServiceFeature... features) { return super.getPort(new QName("http://test.webservice.services.xyz.com/", "YourServicePort"), YourService.class, features); } private static URL __getWsdlLocation() { if (YOURWEBSERVICE_EXCEPTION!= null) { throw YOURWEBSERVICE_EXCEPTION; } return YOURWEBSERVICE_WSDL_LOCATION; } }
Quizás esto también pueda ayudar. Es simplemente un enfoque diferente que no utiliza el enfoque de "catálogo".
fuente
Muchas gracias por la respuesta de Bhaskar Karambelkar, que explica en detalle y solucionó mi problema. Pero también me gustaría reformular la respuesta en tres sencillos pasos para alguien que tiene prisa por arreglar
wsdlLocation= "http://localhost/wsdl/yourwsdlname.wsdl"
Cree un archivo xml jax-ws-catalog.xml en META-INF como se muestra a continuación
<catalog xmlns="urn:oasis:names:tc:entity:xmlns:xml:catalog" prefer="system"> <system systemId="http://localhost/wsdl/yourwsdlname.wsdl" uri="wsdl/yourwsdlname.wsdl" /> </catalog>
Ahora empaqueta tu frasco. No más referencias al directorio local, todo está empaquetado y referenciado dentro
fuente
Para aquellos que todavía están buscando una solución aquí, la solución más fácil sería usarla
<wsdlLocation>
, sin cambiar ningún código. Los pasos de trabajo se dan a continuación:src/main/resource
En el archivo pom, agregue wsdlDirectory y wsdlLocation (no se pierda / al comienzo de wsdlLocation), como se muestra a continuación. Mientras que wsdlDirectory se usa para generar código y wsdlLocation se usa en tiempo de ejecución para crear un proxy dinámico.
Luego, en su código java (con un constructor sin argumentos):
MyPort myPort = new MyPortService().getMyPort();
Para completar, proporciono aquí la parte de generación de código completa, con una API fluida en el código generado.
<plugin> <groupId>org.codehaus.mojo</groupId> <artifactId>jaxws-maven-plugin</artifactId> <version>2.5</version> <dependencies> <dependency> <groupId>org.jvnet.jaxb2_commons</groupId> <artifactId>jaxb2-fluent-api</artifactId> <version>3.0</version> </dependency> <dependency> <groupId>com.sun.xml.ws</groupId> <artifactId>jaxws-tools</artifactId> <version>2.3.0</version> </dependency> </dependencies> <executions> <execution> <id>wsdl-to-java-generator</id> <goals> <goal>wsimport</goal> </goals> <configuration> <xjcArgs> <xjcArg>-Xfluent-api</xjcArg> </xjcArgs> <keep>true</keep> <wsdlDirectory>src/main/resources/package</wsdlDirectory> <wsdlLocation>/package/my.wsdl</wsdlLocation> <sourceDestDir>${project.build.directory}/generated-sources/annotations/jaxb</sourceDestDir> <packageName>full.package.here</packageName> </configuration> </execution> </executions>
fuente
Para aquellos de ustedes que usan Spring, simplemente pueden hacer referencia a cualquier recurso classpath usando el protocolo classpath. Entonces, en el caso de wsdlLocation, esto se convierte en:
Tenga en cuenta que no es un comportamiento estándar de Java. Véase también: http://docs.spring.io/spring/docs/current/spring-framework-reference/html/resources.html
fuente
Tuvo exactamente el mismo problema que se describe aquí. No importa lo que hice, siguiendo los ejemplos anteriores, para cambiar la ubicación de mi archivo WSDL (en nuestro caso desde un servidor web), todavía estaba haciendo referencia a la ubicación original incrustada dentro del árbol de origen del proceso del servidor.
Después de MUCHAS horas tratando de depurar esto, noté que la Excepción siempre se lanzaba desde la misma línea exacta (en mi caso 41). Finalmente, esta mañana, decidí enviar mi código de cliente fuente a nuestro socio comercial para que al menos puedan entender cómo se ve el código, pero tal vez construir el suyo propio. Para mi sorpresa y horror , encontré un montón de archivos de clase mezclados con mis archivos .java dentro de mi árbol de origen del cliente. ¡¡Qué extraño !! Sospecho que estos fueron un subproducto de la herramienta de creación de clientes JAX-WS.
Una vez que eliminé esos tontos archivos .class y realicé una limpieza completa y una reconstrucción del código del cliente, ¡todo funciona perfectamente! Redonculous !!
YMMV, Andrew
fuente