Suministro de una versión diferente de JAXB para JAX-WS en Java 1.6
web-services (3)
El quid de esta cuestión es que hay un cambio en la API JAXB, la implementación en tiempo de ejecución que está intentando usar no coincide con la versión de la API JAXB incluida con el JDK.
Para utilizar una versión diferente, debe copiar las versiones correspondientes de jaxb-api.jar y jaxws-api.jar en una lib jaxws-api.jar (por ejemplo, %JAVA_HOME%/lib/endorsed
).
Se proporciona una lista completa de opciones en la sección 7.1.2 de la Guía no oficial de JAXB
Es un error copiar los archivos jar de implementación (por ejemplo, jaxb-impl.jar) en lib endorsed, estos deberían estar simplemente en su classpath.
También tenga en cuenta que puede tener problemas si intenta utilizar una versión más nueva de jaxb sin incluir también una versión compatible de jaxws. Esto se debe a que el antiguo jaxws intenta hacer referencia al antiguo jaxb, por lo que si está cambiando uno, asegúrese de hacer ambas cosas. (Stack-trace en el paquete com.sun.xml.internal.ws
implica una implementación anterior de jax-ws. Incluso la última versión de Java todavía se envía con la versión 1 anterior, jaxb y jaxws apis).
Tengo un jar de terceros que se envía con un jaxb-impl.jar y lo incluye en su classpath de manifiesto. El problema es que parece que el suministro de su propia versión de JAXB (independientemente de la versión que tenga) parece romper el SoapFaultBuilder en JAX-WS.
De acuerdo con la Guía no oficial JAXB , parece que Sun cambió deliberadamente el nombre del paquete cuando plegó JAXB en el JDK para evitar conflictos con la versión independiente. Sin embargo, el SoapFaultBuilder (parte de JAX-WS, creo) que se envía con el JDK depende explícitamente del nuevo nombre de paquete interno. Esto hace que falle al generar un mensaje de error si ha agregado un jar JAXB independiente (incluso si es el mismo número de versión de JAXB).
Aquí está mi pequeño caso de prueba: hago un servicio web trivial:
package wstest;
import javax.jws.WebMethod;
import javax.jws.WebService;
import javax.jws.soap.SOAPBinding;
import javax.jws.soap.SOAPBinding.Style;
//Service Endpoint Interface
@WebService
@SOAPBinding(style = Style.RPC)
public interface HelloWorld{
@WebMethod String getHelloWorldAsString(String name);
}
Y una implementación que simplemente arroja una excepción. (Dado que el problema solo ocurre en SOAPFaultBuilder):
package wstest;
import javax.jws.WebService;
//Service Implementation
@WebService(endpointInterface = "wstest.HelloWorld")
public class HelloWorldImpl implements HelloWorld{
@Override
public String getHelloWorldAsString(String name) {
//return "Hello World JAX-WS " + name;
throw new RuntimeException("Exception for: " + name);
}
}
Y una clase para publicar el servicio web:
package wstest;
import javax.xml.ws.Endpoint;
//Endpoint publisher
public class HelloWorldPublisher{
public static void main(String[] args) {
Endpoint.publish("http://localhost:9999/ws/hello", new HelloWorldImpl());
}
}
Ejecuto el HelloWorldPublisher y luego ejecuto este cliente contra él:
package wstest;
import java.net.URL;
import javax.xml.namespace.QName;
import javax.xml.ws.Service;
public class HelloWorldClient{
public static void main(String[] args) throws Exception {
URL url = new URL("http://localhost:9999/ws/hello?wsdl");
//1st argument service URI, refer to wsdl document above
//2nd argument is service name, refer to wsdl document above
QName qname = new QName("http://wstest/", "HelloWorldImplService");
Service service = Service.create(url, qname);
HelloWorld hello = service.getPort(HelloWorld.class);
System.out.println(hello.getHelloWorldAsString("Matt"));
}
}
Esto arroja correctamente la excepción lanzada por el servicio web. Sin embargo, cuando agrego cualquier versión de jaxb-impl.jar, ya sea en el classpath o en el endorsed lib, obtengo este rastro de pila:
Exception in thread "main" java.lang.ExceptionInInitializerError
at com.sun.xml.internal.ws.client.sei.SyncMethodHandler.invoke(SyncMethodHandler.java:107)
at com.sun.xml.internal.ws.client.sei.SyncMethodHandler.invoke(SyncMethodHandler.java:78)
at com.sun.xml.internal.ws.client.sei.SEIStub.invoke(SEIStub.java:107)
at $Proxy19.getHelloWorldAsString(Unknown Source)
at wstest.HelloWorldClient.main(HelloWorldClient.java:21)
Caused by: java.lang.ClassCastException: com.sun.xml.bind.v2.runtime.JAXBContextImpl cannot be cast to com.sun.xml.internal.bind.api.JAXBRIContext
at com.sun.xml.internal.ws.fault.SOAPFaultBuilder.<clinit>(SOAPFaultBuilder.java:533)
... 5 more
La excepción se produce porque com.sun.xml.bind.v2.runtime.JAXBContextImpl de mi jaxb-impl extiende com.sun.xml.bind.api.JAXBRIContext en lugar de com.sun.xml.internal.bind.api.JAXBRIContext ( nótese el subpaquete ''interno'' que falta en la jerarquía del paquete).
También de acuerdo con la Guía no oficial de JAXB , dicen que necesita usar lib endosado para anular correctamente la versión de JAXB. Aunque resulta que SOAPFaultBuilder usa JAXBContext.newInstance () para buscar en classpath un archivo llamado /META-INF/services/javax.xml.bind.JAXBContext
, luego carga manualmente (y crea reflexivamente) un JAXBContext basado en la clase nombre especificado en el archivo. Entonces no importa - classpath o endorsed lib te da el mismo comportamiento.
Una solución consiste en agregar -Djavax.xml.bind.JAXBContext=com.sun.xml.internal.bind.v2.ContextFactory
a la línea de comandos, lo que hace que JAXBContext.newInstance () ignore /META-INF/services/javax.xml.bind.JAXBContext
archivo /META-INF/services/javax.xml.bind.JAXBContext
en classpath y especifica manualmente la versión incorporada de JAXB. La otra solución es simplemente no especificar su propia JAXB y usar la versión incorporada en el JDK, pero parece que, a partir de la Guía no oficial de JAXB, Sun diseñó este sistema para poder administrar su propia implementación de JAXB. ¿Alguien ha podido proporcionar con éxito una versión de JAXB y aún así poder capturar mensajes de error con éxito? (Todo funciona bien para mí siempre que no haya fallas generadas por el servicio web).
Estuve atascado en este problema, pero pude usar el "problema" enumerado en este foro de preguntas y respuestas al establecer una propiedad del sistema como esta:
System.setProperty("javax.xml.bind.JAXBContext",
"com.sun.xml.internal.bind.v2.ContextFactory");
otra solución posible sin modificar las propiedades del sistema se describe en API docu
puede colocar un archivo jaxb.properties dentro del paquete de su clase de modelo.
javax.xml.bind.context.factory=com.sun.xml.internal.bind.v2.ContextFactory