Was ich so treibe...

Uli's IT-Blog - Konzeption, Entwicklung, Betrieb

WSGEN - Wie man's mit Interfaces macht

Erzeugen einer WSDL-Datei für ein JAXWS-Webservice-Interface

Vorab – unser Webservice

Ausgangspunkt ist dieses Interface für unseren Webservice:

(SampleWebService.java) download
1
2
3
4
5
6
7
8
9
10
11
import javax.jws.WebService;
import javax.jws.WebMethod;
import javax.jws.WebParam;

@WebService(name = "sampleWebService", targetNamespace = "http:/sample.de/sample-web-service/")
public interface SampleWebService {
   @WebMethod
   public String echo(
            @WebParam(name = "msg", mode = WebParam.Mode.IN) String msg
   );
}

Zusätzlich gibt’s auch schon eine Implementierung dafür, nämlich diese:

(SampleWebServiceImpl.java) download
1
2
3
4
5
6
7
8
import javax.jws.WebService;

@WebService(endpointInterface = "SampleWebService", serviceName = "SampleWebService", targetNamespace = "http:/sample.de/sample-web-service/")
public class SampleWebServiceImpl implements SampleWebService {
   public String echo(String msg) {
       return "Echo: "+msg;
   }
}

Da wir nur zwei Quelldateien haben, können wir die schnell manuell durchkompilieren:

Kompilieren der Quelldateien
1
2
3
4
$ javac SampleWebServiceImpl.java  # ... kompiliert beide Dateien
$ ls
SampleWebService.class      SampleWebServiceImpl.java
SampleWebServiceImpl.class  SampleWebService.java

WSGEN – das übliche Vorgehen

Das übliche Vorgehen basiert auf dem Tool wsgen, welches dem JDK beiliegt:

Vorgehen mit WSGEN
1
2
3
4
$ wsgen -cp . SampleWebServiceImpl -wsdl -inlineSchemas
$ ls
jaxws                   SampleWebServiceImpl.class  SampleWebService.java
SampleWebService.class  SampleWebServiceImpl.java   SampleWebService.wsdl

Da haben wir sie, die WSDL-Datei mit dem Namen “SampleWebService.wsdl”.

WSGEN – das Problem

Manchmal steht nur das Interface für den Webservice zur Verfügung, also nur die Datei SampleWebService.java. Wenn wir versuchen, daraus eine WSDL-Datei zu erzeugen, erscheint so eine Fehlermeldung:

WSGEN und ServiceInterface
1
2
3
4
5
6
7
8
9
10
11
$ wsgen -cp . SampleWebService -wsdl -inlineSchemas
The class "SampleWebService" is not an endpoint implementation class.

Usage: WSGEN [options] <SEI>

where [options] include:
  -classpath <path>          specify where to find input class files
...
Examples:
  wsgen -cp . example.Stock
  wsgen -cp . example.Stock -wsdl -servicename {http://mynamespace}MyService

Wie’s aussieht funktioniert WSGEN also nicht mit Interface-Klassen, es wird eine Implementierungsklasse benötigt:

Ein erster Versuch mit abstrakter Klasse

Hier eine abstrakte Implementierungsklasse:

(AbstractSampleWebServiceImpl.java) download
1
2
3
4
5
import javax.jws.WebService;

@WebService(endpointInterface = "SampleWebService", serviceName = "SampleWebService", targetNamespace = "http:/sample.de/sample-web-service/")
abstract public class AbstractSampleWebServiceImpl implements SampleWebService {
}

Leider klappt’s auch nicht:

WSGEN mit abstrakter Implementierungsklasse
1
2
3
4
5
$ javac AbstractSampleWebServiceImpl.java
$ wsgen -cp . AbstractSampleWebServiceImpl -wsdl -inlineSchemas
...
com.sun.tools.internal.ws.processor.modeler.ModelerException: modeler error: Classes annotated with @javax.jws.WebService must not be abstract. Class: AbstractSampleWebServiceImpl
...

Dynamische Erstellung einer Implementierungsklasse

Der nächste Versuch sieht so aus:

  • ich lade das Interface und untersuche alle seine Methoden
  • daraus erzeuge ich den Quelltext für eine Implementierungsklasse
  • die Implementierungsklasse kompiliere ich mit dem JavaCompiler
  • auf die dabei erstellte .class-Datei lasse ich dann wsgen los

Den Versuch habe ich in einem GITHUB-Projekt plattformübergreifend umgesetzt. Er scheint grundsätzlich zu funktionieren, ich kann in meinem aktuellen Projekt auf die manuelle Erstellung von Dummy-Implementierungsklassen verzichten.

Beispielaufruf: ./uli-wsgen.sh -c myproject.jar -f sample.wsdl SampleWebService

Comments