JAX-WS-Client: Wie lautet der richtige Pfad für den Zugriff auf die lokale WSDL?

84

Das Problem ist, dass ich einen Webdienst-Client aus einer Datei erstellen muss, die mir bereitgestellt wurde. Ich habe diese Datei im lokalen Dateisystem gespeichert und während ich die WSDL-Datei im richtigen Dateisystemordner behalte, ist alles in Ordnung. Wenn ich es auf einem Server bereitstelle oder die WSDL aus dem Dateisystemordner entferne, kann der Proxy die WSDL nicht finden und es tritt ein Fehler auf. Ich habe das Web durchsucht und die folgenden Beiträge gefunden, aber ich konnte es nicht zum Laufen bringen:
JAX-WS Laden von WSDL aus dem Jar
http://www.java.net/forum/topic/glassfish/metro -and-jaxb / client-jar-cant-find-local-wsdl-0
http://blog.vinodsingh.com/2008/12/locally-packaged-wsdl.html

Ich verwende NetBeans 6.1 (dies ist eine Legacy-Anwendung, die ich mit diesem neuen Webdienst-Client aktualisieren muss). Unten finden Sie die JAX-WS-Proxy-Klasse:

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

}


Dies ist mein Code zur Verwendung des Proxys:

   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 hat eine Kopie der WSDL in web-inf / wsdl / client / SOAService abgelegt , daher möchte ich sie nicht auch zu META-INF hinzufügen . Serviceklassen sind in WEB-INF / classes / com / ibm / eci / soaservice / und die Variable baseurl enthält den vollständigen Pfad des Dateisystems (c: \ path \ to \ the \ project ... \ soaservice). Der obige Code löst den Fehler aus:

javax.xml.ws.WebServiceException: Zugriff auf die WSDL fehlgeschlagen unter: file: /WEB-INF/wsdl/client/SOAService.wsdl. Es ist fehlgeschlagen mit: \ WEB-INF \ wsdl \ client \ SOAService.wsdl (Pfad kann nicht gefunden werden)

Soll ich also zuerst die wsdllocation der Proxy-Klasse aktualisieren? Wie kann ich dann die SOAService-Klasse in WEB-INF / classes / com / ibm / eci / soaservice anweisen, in \ WEB-INF \ wsdl \ client \ SOAService.wsdl nach der WSDL zu suchen?

BEARBEITET : Ich habe diesen anderen Link gefunden - http://jianmingli.com/wp/?cat=41 , der besagt , dass die WSDL in den Klassenpfad eingefügt werden soll. Ich schäme mich zu fragen: Wie füge ich es in den Klassenpfad der Webanwendung ein?

ROMANIA_engineer
quelle
Ähnliche Frage: JAX-WS Laden von WSDL aus jar
sleske

Antworten:

116

Die beste Option ist die Verwendung von jax-ws-catalog.xml

Wenn Sie die lokale WSDL-Datei kompilieren, überschreiben Sie den WSDL-Speicherort und setzen Sie ihn auf so etwas wie

http: //localhost/wsdl/SOAService.wsdl

Machen Sie sich keine Sorgen, dies ist nur eine URI und keine URL, dh Sie müssen die WSDL nicht an dieser Adresse verfügbar haben.
Sie können dies tun, indem Sie die Option wsdllocation an wsdl an den Java-Compiler übergeben.

Dadurch wird Ihr Proxy-Code von geändert

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

zu

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

Hinweisdatei: // im URL-Konstruktor in http: // geändert.

Jetzt kommt in jax-ws-catalog.xml. Ohne jax-ws-catalog.xml wird jax-ws tatsächlich versuchen, die WSDL vom Speicherort zu laden

http: //localhost/wsdl/SOAService.wsdl
und scheitern, da keine solche WSDL verfügbar sein wird.

Mit jax-ws-catalog.xml können Sie jax-ws jedoch zu einer lokal gepackten WSDL umleiten, wenn versucht wird, auf die WSDL @ zuzugreifen

http: //localhost/wsdl/SOAService.wsdl
.

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

Was Sie tun, ist jax-ws mitzuteilen, dass WSDL von wann immer geladen werden muss

http: //localhost/wsdl/SOAService.wsdl
sollte es vom lokalen Pfad wsdl / SOAService.wsdl geladen werden.

Wo sollten Sie nun wsdl / SOAService.wsdl und jax-ws-catalog.xml ablegen? Das ist die Millionen-Dollar-Frage, nicht wahr?
Es sollte sich im META-INF-Verzeichnis Ihrer Anwendungs-JAR befinden.

so etwas wie das

ABCD.jar  
| __ META-INF    
    | __ jax-ws-catalog.xml  
    | __ wsdl  
        | __ SOAService.wsdl  

Auf diese Weise müssen Sie nicht einmal die URL in Ihrem Client überschreiben, die auf den Proxy zugreift. Die WSDL wird aus Ihrer JAR abgerufen, und Sie müssen keine fest codierten Dateisystempfade in Ihrem Code haben.

Weitere Informationen unter jax-ws-catalog.xml http://jax-ws.java.net/nonav/2.1.2m1/docs/catalog-support.html

hoffentlich hilft das


quelle
ok, ich konnte das Problem in der Webanwendung nicht auf diese Weise lösen: Ich habe versucht, wsdl erfolglos in web-inf zu integrieren, wahrscheinlich aus Mangel an Wissen. Wie auch immer, es funktioniert mit einem Glas, also mache ich eine Wrapper-Bibliothek, wie es von Anfang an hätte gemacht werden sollen. Vielen Dank für Ihre Unterstützung
Ich konnte diese Antwort erfolgreich verwenden und glaube, dass dies eine bessere Lösung ist als alle anderen Alternativen, die in anderen Artikeln und Tutorials dokumentiert sind. Für mich ist dies also eine bewährte Methode. Ich frage mich nur, warum diese Lösung nicht in den anderen offiziellen Artikeln und Tutorials zum Thema JAX-WS dokumentiert ist.
Rahul Khimasia
19

Ein anderer Ansatz, den wir erfolgreich gewählt haben, besteht darin, den WS-Client-Proxy-Code mit wsimport (von Ant als Ant-Task) zu generieren und das Attribut wsdlLocation anzugeben.

<wsimport debug="true" keep="true" verbose="false" target="2.1" sourcedestdir="${generated.client}" wsdl="${src}${wsdl.file}" wsdlLocation="${wsdl.file}">
</wsimport>

Da wir dies für ein Projekt mit mehreren WSDLs ausführen, löst das Skript den Wert $ (wsdl.file} dynamisch auf, der als /META-INF/wsdl/YourWebServiceName.wsdl relativ zum JavaSource-Speicherort (oder / src,) eingerichtet ist. Abhängig davon, wie Sie Ihr Projekt eingerichtet haben.) Während des Erstellungsprozesses werden die WSDL- und XSDs-Dateien an diesen Speicherort kopiert und in die JAR-Datei gepackt (ähnlich der oben von Bhasakar beschriebenen Lösung).

MyApp.jar
|__META-INF
   |__wsdl
      |__YourWebServiceName.wsdl
      |__YourWebServiceName_schema1.xsd
      |__YourWebServiceName_schmea2.xsd

Hinweis: Stellen Sie sicher, dass die WSDL-Dateien relative Referenzen für importierte XSDs und keine http-URLs verwenden:

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

Im generierten Code finden wir Folgendes:

/**
 * 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;
    }

}

Vielleicht könnte das auch helfen. Es ist nur ein anderer Ansatz, der nicht den "Katalog" -Ansatz verwendet.

Kennzeichen
quelle
Ich mag diesen Ansatz ... aber warum das META-INF-Verzeichnis?
IcedDante
1
Bitte beachten Sie, dass dies die Verwendung von JAX-WS RI 2.2 erfordert, nicht von 2.1, das standardmäßig mit JDK 6
geliefert wird
4

Vielen Dank für die Antwort von Bhaskar Karambelkar, die mein Problem ausführlich erklärt und behoben hat. Aber ich möchte auch die Antwort in drei einfachen Schritten für jemanden umformulieren, der es eilig hat, sie zu reparieren

  1. Machen Sie Ihre wsdl lokale Standortreferenz als wsdlLocation= "http://localhost/wsdl/yourwsdlname.wsdl"
  2. Erstellen Sie einen META-INF-Ordner direkt unter dem src. Legen Sie Ihre wsdl-Datei (en) in einem Ordner unter META-INF ab, z. B. META-INF / wsdl
  3. Erstellen Sie eine XML-Datei jax-ws-catalog.xml unter META-INF wie folgt

    <catalog xmlns="urn:oasis:names:tc:entity:xmlns:xml:catalog" prefer="system"> <system systemId="http://localhost/wsdl/yourwsdlname.wsdl" uri="wsdl/yourwsdlname.wsdl" /> </catalog>

Verpacken Sie jetzt Ihr Glas. Kein Verweis mehr auf das lokale Verzeichnis, es ist alles gepackt und referenziert

Hemus7
quelle
2

Für diejenigen unter Ihnen, die Spring verwenden, können Sie einfach mit dem Klassenpfadprotokoll auf eine beliebige Klassenpfadressource verweisen. Im Fall von wsdlLocation wird dies also:

<wsdlLocation>classpath:META-INF/webservice.wsdl</wsdlLocation>

Beachten Sie, dass dies kein Standardverhalten von Java ist. Siehe auch: http://docs.spring.io/spring/docs/current/spring-framework-reference/html/resources.html

Martin Devillers
quelle
2

Für diejenigen, die hier noch nach einer Lösung suchen, wäre die einfachste Lösung, sie zu verwenden <wsdlLocation>, ohne Code zu ändern. Arbeitsschritte sind unten angegeben:

  1. Legen Sie Ihre WSDL in ein Ressourcenverzeichnis wie: src/main/resource
  2. Fügen Sie in der POM-Datei sowohl wsdlDirectory als auch wsdlLocation hinzu (nicht verpassen / am Anfang von wsdlLocation), wie unten. Während wsdlDirectory zum Generieren von Code verwendet wird und wsdlLocation zur Laufzeit zum Erstellen eines dynamischen Proxys verwendet wird.

    <wsdlDirectory>src/main/resources/mydir</wsdlDirectory>
    <wsdlLocation>/mydir/my.wsdl</wsdlLocation>
  3. Dann in Ihrem Java-Code (mit No-Arg-Konstruktor):

    MyPort myPort = new MyPortService().getMyPort();
  4. Der Vollständigkeit halber stelle ich hier einen vollständigen Teil der Codegenerierung mit einer fließenden API für generierten Code bereit.

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

Shafiul
quelle
0

Hatte genau das gleiche Problem, das hier beschrieben wird. Unabhängig davon, was ich gemäß den obigen Beispielen getan habe, um den Speicherort meiner WSDL-Datei (in unserem Fall von einem Webserver) zu ändern, wurde immer noch auf den ursprünglichen Speicherort verwiesen, der in den Quellbaum des Serverprozesses eingebettet ist.

Nach VIELEN Stunden beim Versuch, dies zu debuggen, bemerkte ich, dass die Ausnahme immer aus genau derselben Zeile ausgelöst wurde (in meinem Fall 41). Schließlich habe ich heute Morgen beschlossen, meinen Quell-Client-Code einfach an unseren Handelspartner zu senden, damit dieser zumindest verstehen kann, wie der Code aussieht, aber vielleicht seinen eigenen erstellen kann. Zu meinem Schock und Entsetzen fand ich eine Reihe von Klassendateien, die mit meinen .java-Dateien in meinem Client-Quellbaum gemischt waren. Wie bizarr !! Ich vermute, dass dies ein Nebenprodukt des JAX-WS-Client-Builder-Tools war.

Sobald ich diese albernen .class-Dateien gezappt und eine vollständige Bereinigung und Neuerstellung des Client-Codes durchgeführt habe, funktioniert alles perfekt !! Redonculous !!

YMMV, Andrew

Piko
quelle