diff --git a/src/zutil/net/ws/WSInterface.java b/src/zutil/net/ws/WSInterface.java index c37b013..eead304 100755 --- a/src/zutil/net/ws/WSInterface.java +++ b/src/zutil/net/ws/WSInterface.java @@ -128,14 +128,6 @@ public interface WSInterface { @Target(ElementType.METHOD) @interface WSHeader {} - /** - * Specifies the name space for the method. - */ - @Retention(RetentionPolicy.RUNTIME) - @interface WSNamespace { - String value(); - } - /** * Specifies the request type. */ @@ -146,10 +138,10 @@ public interface WSInterface { } /** - * Sets a specific URL path for the method overriding the auto generated path. + * Sets a specific URL path for the method overriding the auto generated path. This will also be used as the namespace. */ @Retention(RetentionPolicy.RUNTIME) - @Target(ElementType.METHOD) + @Target({ElementType.TYPE, ElementType.METHOD}) @interface WSPath { String value(); } diff --git a/src/zutil/net/ws/WSMethodDef.java b/src/zutil/net/ws/WSMethodDef.java index f246254..b279fbd 100755 --- a/src/zutil/net/ws/WSMethodDef.java +++ b/src/zutil/net/ws/WSMethodDef.java @@ -25,7 +25,6 @@ package zutil.net.ws; import zutil.net.ws.WSInterface.WSDocumentation; -import zutil.net.ws.WSInterface.WSNamespace; import zutil.net.ws.WSInterface.WSPath; import zutil.net.ws.WSInterface.WSRequestType; @@ -50,11 +49,11 @@ public class WSMethodDef { /** * A list of input parameters **/ - private ArrayList inputs; + private ArrayList inputs = new ArrayList<>(); /** * A List of return parameters of the method **/ - private ArrayList outputs; + private ArrayList outputs = new ArrayList<>(); /** * The object type of output object **/ @@ -62,7 +61,7 @@ public class WSMethodDef { /** * A List of exceptions that this method throws **/ - private ArrayList> exceptions; + private ArrayList> exceptions = new ArrayList<>(); /** * The real method that this class represent, can be null if its a remote method **/ @@ -72,9 +71,9 @@ public class WSMethodDef { **/ private String doc; /** - * The namespace of the method + * The URL path of the method **/ - private String namespace; + private String path; /** * The type of request required to execute the method **/ @@ -83,38 +82,34 @@ public class WSMethodDef { * The published name of the method **/ private String name; - /** - * The endpoint location - **/ - private String path; /** - * @param wsDef is the parent web service defining interface - * @param me is a method in a class that implements WSInterface + * @param wsDef is the parent web service defining interface + * @param method is a method in a class that implements WSInterface */ - protected WSMethodDef(WebServiceDef wsDef, Method me) { - if (!WSInterface.class.isAssignableFrom(me.getDeclaringClass())) + protected WSMethodDef(WebServiceDef wsDef, Method method) { + if (!WSInterface.class.isAssignableFrom(method.getDeclaringClass())) throw new ClassCastException("Declaring class does not implement WSInterface!"); this.wsDef = wsDef; - this.method = me; - this.inputs = new ArrayList<>(); - this.outputs = new ArrayList<>(); - this.exceptions = new ArrayList<>(); + this.method = method; this.name = method.getName(); // Handle documentation and namespace - WSDocumentation docAnnotation = method.getAnnotation(WSDocumentation.class); + WSDocumentation docAnnotation = this.method.getAnnotation(WSDocumentation.class); if (docAnnotation != null) doc = docAnnotation.value(); - WSNamespace namespaceAnnotation = method.getAnnotation(WSNamespace.class); + WSPath namespaceAnnotation = this.method.getAnnotation(WSPath.class); if (namespaceAnnotation != null) - namespace = namespaceAnnotation.value(); + path = namespaceAnnotation.value(); else - namespace = wsDef.getNamespace() + "?#" + name; + path = name; + + if (path.startsWith("/")) + path = path.substring(1); // ------------------------------------------------ // Handle inputs @@ -137,7 +132,7 @@ public class WSMethodDef { // Handle outputs // ------------------------------------------------ - this.outputClass = method.getReturnType(); + this.outputClass = this.method.getReturnType(); if (WSReturnObject.class.isAssignableFrom(outputClass)) { Field[] fields = outputClass.getFields(); @@ -150,8 +145,8 @@ public class WSMethodDef { outputs.add(ret_param); } } else if (outputClass != void.class) { - WSInterface.WSReturnName returnNameAnnotation = method.getAnnotation(WSInterface.WSReturnName.class); - WSParameterDef ret_param = new WSParameterDef(this, method.getReturnType(), new Annotation[]{returnNameAnnotation}); + WSInterface.WSReturnName returnNameAnnotation = this.method.getAnnotation(WSInterface.WSReturnName.class); + WSParameterDef ret_param = new WSParameterDef(this, this.method.getReturnType(), new Annotation[]{returnNameAnnotation}); if (ret_param.getName() == null) ret_param.setName("return"); @@ -163,13 +158,13 @@ public class WSMethodDef { // Handle Exceptions // ------------------------------------------------ - Collections.addAll(exceptions, method.getExceptionTypes()); + Collections.addAll(exceptions, this.method.getExceptionTypes()); // ------------------------------------------------ // Handle the request type // ------------------------------------------------ - WSRequestType requestTypeAnnotation = method.getAnnotation(WSRequestType.class); + WSRequestType requestTypeAnnotation = this.method.getAnnotation(WSRequestType.class); if (requestTypeAnnotation != null) { this.requestType = requestTypeAnnotation.value(); } else { @@ -186,19 +181,6 @@ public class WSMethodDef { else this.requestType = WSInterface.RequestType.GET; } - - // ------------------------------------------------ - // Handle endpoint path - // ------------------------------------------------ - - WSPath pathAnnotation = method.getAnnotation(WSPath.class); - if (pathAnnotation != null) - path = pathAnnotation.value(); - else - path = this.name; - - if (!path.startsWith("/")) - path = '/' + path; } /** @@ -212,7 +194,7 @@ public class WSMethodDef { * @return the path to the WS method endpoint */ public String getPath() { - return path; + return wsDef.getPath() + "/" + path; } /** @@ -257,19 +239,12 @@ public class WSMethodDef { return requestType; } - /** - * @return the namespace or endpoint url of the method - */ - public String getNamespace() { - return namespace; - } - /** * Invokes a specified method * - * @param params a vector with arguments - * @param obj the object the method will called on + * @param params a vector with arguments + * @param obj the object the method will called on */ public Object invoke(Object obj, Object[] params) throws Exception { return this.method.invoke(obj, params); diff --git a/src/zutil/net/ws/WebServiceDef.java b/src/zutil/net/ws/WebServiceDef.java index 9d1baeb..28e72d4 100755 --- a/src/zutil/net/ws/WebServiceDef.java +++ b/src/zutil/net/ws/WebServiceDef.java @@ -38,24 +38,27 @@ import java.util.Set; public class WebServiceDef { /** This is the WSInterface class **/ private Class intf; - /** Namespace of the service **/ - private String namespace; /** Name of the web service **/ private String name; + /** Path or namespace of the service **/ + private String path = ""; /** Human readable description of the service **/ private String documentation = ""; /** A map of methods in this Service **/ private HashMap methods = new HashMap<>(); - public WebServiceDef(Class intf){ this.intf = intf; name = intf.getSimpleName(); - WSInterface.WSNamespace namespaceAnnotation = intf.getAnnotation(WSInterface.WSNamespace.class); - if (namespaceAnnotation != null) - this.namespace = namespaceAnnotation.value(); + WSInterface.WSPath pathAnnotation = intf.getAnnotation(WSInterface.WSPath.class); + if (pathAnnotation != null) { + this.path = pathAnnotation.value(); + + if (path.endsWith("/")) // remove last backslash + path = path.substring(0, path.length()-1); + } WSInterface.WSDocumentation documentationAnnotation = intf.getAnnotation(WSInterface.WSDocumentation.class); if (documentationAnnotation != null) @@ -63,14 +66,14 @@ public class WebServiceDef { for(Method m : intf.getDeclaredMethods()){ // Check for public methods - if ((m.getModifiers() & Modifier.PUBLIC) > 0 && - !m.isAnnotationPresent(WSInterface.WSIgnore.class)){ + if ((m.getModifiers() & Modifier.PUBLIC) > 0 && !m.isAnnotationPresent(WSInterface.WSIgnore.class)){ WSMethodDef method = new WSMethodDef(this, m); methods.put(method.getName(), method); } } } + /** * @return the class that defines this web service */ @@ -93,16 +96,16 @@ public class WebServiceDef { } /** - * @param name is the name of the method - * @return if there is a method by the given name + * @param name is the name of the method + * @return if there is a method by the given name */ public boolean hasMethod( String name ){ return methods.containsKey( name ); } /** - * @param name is the name of the method - * @return the method or null if there is no such method + * @param name is the name of the method + * @return the method or null if there is no such method */ public WSMethodDef getMethod( String name ){ return methods.get( name ); @@ -125,8 +128,8 @@ public class WebServiceDef { /** * @return the namespace of this web service ( usually the URL of the service ) */ - public String getNamespace(){ - return namespace; + public String getPath(){ + return path; } public WSInterface newInstance() throws InstantiationException, IllegalAccessException { diff --git a/src/zutil/net/ws/soap/SOAPClientInvocationHandler.java b/src/zutil/net/ws/soap/SOAPClientInvocationHandler.java index ebdcd4b..081c5a0 100755 --- a/src/zutil/net/ws/soap/SOAPClientInvocationHandler.java +++ b/src/zutil/net/ws/soap/SOAPClientInvocationHandler.java @@ -107,7 +107,7 @@ public class SOAPClientInvocationHandler implements InvocationHandler { Element body = envelope.addElement("soap:Body"); Element method = body.addElement(""); - method.addNamespace("m", methodDef.getNamespace()); + method.addNamespace("m", methodDef.getPath()); method.setName("m:" + methodDef.getName() + "Request"); List outputParamDefs = methodDef.getOutputs(); diff --git a/src/zutil/net/ws/soap/SOAPHttpPage.java b/src/zutil/net/ws/soap/SOAPHttpPage.java index c5b1e74..3c2d3ea 100755 --- a/src/zutil/net/ws/soap/SOAPHttpPage.java +++ b/src/zutil/net/ws/soap/SOAPHttpPage.java @@ -291,7 +291,7 @@ public class SOAPHttpPage implements HttpPage{ // generate response XML if (outputParamDefs.size() > 0) { Element response = responseRoot.addElement(""); - response.addNamespace("m", methodDef.getNamespace() ); + response.addNamespace("m", methodDef.getPath() ); response.setName("m:" + methodDef.getName() + "Response"); if (outputParams instanceof WSReturnObject) { diff --git a/src/zutil/net/ws/wsdl/WSDLServiceSOAP.java b/src/zutil/net/ws/wsdl/WSDLServiceSOAP.java index b749c65..cf9a906 100644 --- a/src/zutil/net/ws/wsdl/WSDLServiceSOAP.java +++ b/src/zutil/net/ws/wsdl/WSDLServiceSOAP.java @@ -56,7 +56,7 @@ public class WSDLServiceSOAP extends WSDLService{ // definitions -> binding -> operation -> soap:operation Element soap_operation = operation.addElement("soap:operation"); - soap_operation.addAttribute("soapAction", method.getNamespace()); + soap_operation.addAttribute("soapAction", method.getPath()); // ------------------------------------------------ // Input @@ -67,7 +67,7 @@ public class WSDLServiceSOAP extends WSDLService{ // definitions -> binding -> operation -> input -> body Element input_body = input.addElement("soap:body"); input_body.addAttribute("use", "literal"); - input_body.addAttribute("namespace", method.getNamespace()); + input_body.addAttribute("namespace", method.getPath()); // ------------------------------------------------ // Output @@ -79,7 +79,7 @@ public class WSDLServiceSOAP extends WSDLService{ // definitions -> binding -> operation -> input -> body Element output_body = output.addElement("soap:body"); output_body.addAttribute("use", "literal"); - output_body.addAttribute("namespace", method.getNamespace()); + output_body.addAttribute("namespace", method.getPath()); } } } diff --git a/src/zutil/net/ws/wsdl/WSDLWriter.java b/src/zutil/net/ws/wsdl/WSDLWriter.java index 2d946ac..f7dc7e4 100644 --- a/src/zutil/net/ws/wsdl/WSDLWriter.java +++ b/src/zutil/net/ws/wsdl/WSDLWriter.java @@ -107,8 +107,8 @@ public class WSDLWriter { definitions.addNamespace("http", "http://schemas.xmlsoap.org/wsdl/http/"); definitions.addNamespace("xsd", "http://www.w3.org/2001/XMLSchema"); definitions.addNamespace("soap-enc", "http://schemas.xmlsoap.org/soap/encoding/"); - definitions.addNamespace("tns", ws.getNamespace() + "?type"); - definitions.addAttribute("targetNamespace", ws.getNamespace()); + definitions.addNamespace("tns", ws.getPath() + "/type"); + definitions.addAttribute("targetNamespace", ws.getPath()); generateType(definitions); generateMessages(definitions); @@ -306,7 +306,7 @@ public class WSDLWriter { // definitions -> types Element typeE = definitions.addElement("wsdl:types"); Element schema = typeE.addElement("xsd:schema"); - schema.addAttribute("targetNamespace", ws.getNamespace() + "?type"); + schema.addAttribute("targetNamespace", ws.getPath() + "/type"); // empty type Element empty = schema.addElement("xsd:complexType"); @@ -316,7 +316,10 @@ public class WSDLWriter { for (int i=0; i c = types.get(i); + // -------------------------------------------- // Generate Array type + // -------------------------------------------- + if (c.isArray()) { Class ctmp = ClassUtil.getArrayClass(c); @@ -338,7 +341,11 @@ public class WSDLWriter { if (!types.contains(ctmp)) types.add(ctmp); } + + // -------------------------------------------- // Generate SOAPObject type + // -------------------------------------------- + else if (WSReturnObject.class.isAssignableFrom(c)) { Element type = schema.addElement("xsd:complexType"); type.addAttribute("name", SOAPHttpPage.getSOAPClassName(c)); diff --git a/test/zutil/net/ws/rest/RESTClientTest.java b/test/zutil/net/ws/rest/RESTClientTest.java index 448de4a..84017cc 100755 --- a/test/zutil/net/ws/rest/RESTClientTest.java +++ b/test/zutil/net/ws/rest/RESTClientTest.java @@ -24,13 +24,10 @@ package zutil.net.ws.rest; -import org.junit.Test; import zutil.net.ws.WSInterface; -import zutil.net.ws.WebServiceDef; import java.net.MalformedURLException; import java.net.URL; -import java.util.HashMap; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; @@ -42,7 +39,7 @@ public class RESTClientTest { public interface OpenWeartherMap extends WSInterface { - @WSNamespace("") + @WSPath("") int weather(@WSParamName("q") String city); } diff --git a/test/zutil/net/ws/soap/SOAPTest.java b/test/zutil/net/ws/soap/SOAPTest.java index 52c338c..4fa676e 100755 --- a/test/zutil/net/ws/soap/SOAPTest.java +++ b/test/zutil/net/ws/soap/SOAPTest.java @@ -28,7 +28,7 @@ import org.dom4j.Document; import org.dom4j.io.OutputFormat; import org.dom4j.io.XMLWriter; import zutil.net.ws.WSInterface; -import zutil.net.ws.WSInterface.WSNamespace; +import zutil.net.ws.WSInterface.WSPath; import zutil.net.ws.WSInterface.WSParamName; import zutil.net.ws.WSReturnObject; import zutil.net.ws.WebServiceDef; @@ -85,7 +85,7 @@ public class SOAPTest { // ---------------------------------------------------- @SuppressWarnings("unused") - @WSNamespace("http://test.se:8080/") + @WSPath("http://test.se:8080/") public static class MainSOAPClass implements WSInterface{ public MainSOAPClass(){} diff --git a/test/zutil/net/ws/wsdl/WSDLWriterTest.java b/test/zutil/net/ws/wsdl/WSDLWriterTest.java index 1078378..c3c5da9 100644 --- a/test/zutil/net/ws/wsdl/WSDLWriterTest.java +++ b/test/zutil/net/ws/wsdl/WSDLWriterTest.java @@ -39,9 +39,9 @@ public class WSDLWriterTest { assertEquals("\n" + "\n" + - "\n" + + "\n" + " \n" + - " \n" + + " \n" + " \n" + " \n" + " \n" + @@ -125,42 +125,42 @@ public class WSDLWriterTest { " \n" + " \n" + " \n" + - " \n" + + " \n" + " \n" + - " \n" + + " \n" + " \n" + " \n" + - " \n" + + " \n" + " \n" + " \n" + " \n" + - " \n" + + " \n" + " \n" + - " \n" + + " \n" + " \n" + " \n" + - " \n" + + " \n" + " \n" + " \n" + " \n" + - " \n" + + " \n" + " \n" + - " \n" + + " \n" + " \n" + " \n" + " \n" + - " \n" + + " \n" + " \n" + - " \n" + + " \n" + " \n" + " \n" + - " \n" + + " \n" + " \n" + " \n" + " \n" + - " \n" + + " \n" + " \n" + - " \n" + + " \n" + " \n" + " \n" + " \n" +