web-dev-qa-db-fra.com

Fourniture d'une version différente de JAXB pour JAX-WS dans Java 1.6

J'ai un pot tiers qui est livré avec un jaxb-impl.jar et l'inclut dans son chemin de classe manifeste. Le problème est qu'il semble que fournir votre propre version de JAXB (quelle que soit la version) semble casser le SoapFaultBuilder dans JAX-WS.

Selon le nofficial JAXB Guide , il semble que Sun ait 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) fourni avec le JDK dépend explicitement du nouveau nom de package interne. Cela provoque son échec lors de la création d'un message d'erreur si vous avez ajouté un fichier JAXB autonome (même s'il s'agit du même numéro de 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 lève simplement une exception. (Étant donné que le problème se produit uniquement dans 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());
    }

}

J'exécute HelloWorldPublisher, puis j'exécute ce client contre lui:

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

    }

}

Cela crache correctement l'exception qui a été levée par le service Web. Cependant, lorsque j'ajoute une version de jaxb-impl.jar, que ce soit sur le chemin de classe ou dans la bibliothèque approuvée, j'obtiens 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 car com.Sun.xml.bind.v2.runtime.JAXBContextImpl de mon jaxb-impl étend com.Sun.xml.bind.api.JAXBRIContext au lieu de com.Sun.xml.internal.bind.api.JAXBRIContext ( notez le sous-package "interne" manquant dans la hiérarchie des packages).

Toujours selon le Guide JAXB non officiel , ils disent que vous devez utiliser la bibliothèque approuvée afin de remplacer correctement la version de JAXB. Il s'avère cependant que SOAPFaultBuilder utilise JAXBContext.newInstance () pour rechercher dans le chemin de classe un fichier nommé /META-INF/services/javax.xml.bind.JAXBContext, puis chargez manuellement (et créez par réflexe) un JAXBContext basé sur le nom de classe spécifié dans le fichier. Donc, cela n'a pas d'importance - classpath ou lib approuvée vous donne le même comportement.

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

31
matt forsythe

J'étais coincé sur ce problème mais j'ai pu utiliser le "contournement" répertorié dans ce forum Q&R en définissant une propriété système comme ceci:

System.setProperty("javax.xml.bind.JAXBContext", 
                   "com.Sun.xml.internal.bind.v2.ContextFactory"); 
40
Frank

Le nœud de ce problème est qu'il y a un changement dans l'API JAXB [~ # ~] [~ # ~] , l'implémentation d'exécution que vous essayez de l'utilisation ne correspond pas à la version de l'API JAXB fournie avec le JDK.

Afin d'utiliser une version différente, vous devez copier les versions correspondantes de jaxb-api.jar et jaxws-api.jar dans une bibliothèque approuvée (par exemple %Java_HOME%\lib\endorsed).

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

C'est une erreur de copier les pots d'implémentation (par exemple jaxb-impl.jar) dans une bibliothèque approuvée, ceux-ci devraient simplement être sur votre chemin de classe.

Notez également que vous pouvez avoir des problèmes si vous essayez d'utiliser une version plus récente de jaxb sans également inclure une version compatible de jaxws. C'est parce que l'ancien jaxws tente de référencer l'ancien jaxb, donc si vous en changez un, assurez-vous de faire les deux. (Stack-trace dans le package com.Sun.xml.internal.ws implique une ancienne implémentation jax-ws. Même la dernière version de Java est toujours livrée avec l'ancienne version 1 jaxb et jaxws apis).

4
gb96

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

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

vous pouvez placer un fichier jaxb.properties à l'intérieur du package de votre classe de modèle.

javax.xml.bind.context.factory=com.Sun.xml.internal.bind.v2.ContextFactory
3
Thomas Bergmann