Fournir une version différente de JAXB pour JAX-WS en Java 1.6

j'ai un tiers pot est livré avec un jaxb-impl.jar et l'inclut dans son manifeste classpath. Le problème est, il semble que fournir votre propre version de JAXB (quelle que soit la version qu'elle soit) semble briser le constructeur de savon en JAX-WS.

Selon Unofficial JAXB Guide, il semble que Sun a délibérément changé le nom du paquet quand il a plié JAXB dans le JDK afin d'éviter les conflits avec la version autonome. Cependant, le SoapFaultBuilder (qui fait partie de JAX-WS je crois) que les bateaux avec le JDK dépendent explicitement du nouveau nom de paquet interne. Si vous avez ajouté un JAXB jar autonome (même si c'est la même version de JAXB).

Voici mon petit cas de test: je fais un service 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);

}

et une implémentation qui jette simplement une exception. (Puisque le problème se produit uniquement dans le 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);
    }

}

et une classe pour publier le service 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());
    }

}

je lance le HelloWorldPublisher, puis exécuter ce client contre elle:

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"));

    }

}

ceci crache correctement l'exception qui a été jetée par le Service Web. Cependant, quand j'ajoute n'importe quelle version de JAXB-impl.jar, que ce soit sur le classpath ou dans le lib endossé, je reçois cette trace de pile:

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

L'exception se produit parce que COM.soleil.XML.lier.v2.Runtime.JAXBContextImpl de mon JAXB-impl étend com.soleil.XML.lier.API.JAXBRIContext au lieu de com.soleil.XML.interne.lier.API.JAXBRIContext (notez l'absence du sous-paquet "interne" dans la hiérarchie du paquet).

selon le même Unofficial JAXB Guide, ils disent que vous devez utiliser la lib endossée afin de remplacer correctement la version de JAXB. Comme il s'avère cependant, SOAPFaultBuilder utilise JAXBContext.newInstance () pour rechercher classpath un fichier nommé /META-INF/services/javax.xml.bind.JAXBContext, puis charger manuellement (et créer de manière réflexive) un JAXBContext basé sur le nom de classe spécifié dans le fichier. Donc ça n'a pas d'importance - classpath ou lib endossé te donne le même comportement.

Une solution consiste à ajouter -Djavax.xml.bind.JAXBContext=com.sun.xml.internal.bind.v2.ContextFactory à la ligne de commande, qui provoque JAXBContext.newInstance() pour ignorer le /META-INF/services/javax.xml.bind.JAXBContext fichier sur classpath et spécifie manuellement la version intégrée de JAXB. L'autre solution est de ne pas spécifier votre propre JAXB et d'utiliser la version intégré dans le JDK, mais il semble d'après le guide non officiel de JAXB, que Sun a conçu ce système pour être en mesure de gérer la fourniture de votre propre implémentation JAXB. Quelqu'un a-t-il pu fournir avec succès une version de JAXB tout en étant capable de capturer des messages de défauts? (Tout se passe bien pour moi tant qu'il n'y a pas de défauts générés par le service Web).

31
demandé sur matt forsythe 2013-01-04 21:46:24

3 réponses

j'étais bloqué sur ce problème mais j'ai pu utiliser le "work around" indiqué dans ce forum Q&A par la fixation d'un système de propriété comme suit:

System.setProperty("javax.xml.bind.JAXBContext", 
                   "com.sun.xml.internal.bind.v2.ContextFactory"); 
39
répondu Frank 2013-07-01 16:22:59

Le point crucial de cette question est qu'il ya un changement dans la JAXB API, l'implémentation d'exécution que vous tentez d'utiliser ne correspond pas à la version de L'API JAXB fournie avec le JDK.

pour utiliser une version différente, vous devez copier les versions correspondantes de JAXB-api.jar et jaxws-api.jar dans une FRV approuvée (p. ex. %JAVA_HOME%\lib\endorsed).

une liste complète des options est donnée dans la section 7.1.2 de la non officiel Guide JAXB

c'est une erreur de copier les jarres d'implémentation (par exemple jaxb-impl.jar) en lib approuvé, ceux-ci devraient simplement être sur votre chemin de classe.

notez aussi que vous pouvez avoir des problèmes si vous tentez d'utiliser une nouvelle version de jaxb sans inclure également une version compatible de jaxws. C'est parce que l'ancien jaxws tente de faire référence à l'ancien jaxb, donc si vous êtes de changer un assurez-vous de faire les deux. (Stack-trace dans le paquet com.sun.xml.internal.ws implique un ancien jax-ws application. Même la dernière version de Java still ships avec l'ancienne version 1 JAXB et jaxws API).

4
répondu gb96 2013-04-22 00:39:30

une autre solution possible sans modifier les propriétés du système est décrite à API docu

https://docs.oracle.com/cd/E17802_01/webservices/webservices/docs/1.6/api/javax/xml/bind/JAXBContext.html

vous pouvez placer un jaxb.fichier de propriétés à l'intérieur du paquet de votre classe model.

javax.xml.bind.context.factory=com.sun.xml.internal.bind.v2.ContextFactory
3
répondu Thomas Bergmann 2016-12-21 13:06:26