You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@juneau.apache.org by ja...@apache.org on 2018/08/16 20:16:53 UTC
[juneau] branch master updated: Improve method naming in remoteable
proxies.
This is an automated email from the ASF dual-hosted git repository.
jamesbognar pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/juneau.git
The following commit(s) were added to refs/heads/master by this push:
new 3c2cc7c Improve method naming in remoteable proxies.
3c2cc7c is described below
commit 3c2cc7ced1b9788b8dfffe346e71a0e6bc80b84e
Author: JamesBognar <ja...@apache.org>
AuthorDate: Thu Aug 16 16:16:40 2018 -0400
Improve method naming in remoteable proxies.
---
.../org/apache/juneau/utils/HttpUtilsTest.java | 170 +++++++++++++++++++++
.../src/main/java/org/apache/juneau/ClassMeta.java | 48 +-----
.../java/org/apache/juneau/internal/HttpUtils.java | 92 +++++++++++
.../org/apache/juneau/remoteable/RemoteMethod.java | 12 +-
.../org/apache/juneau/remoteable/Remoteable.java | 63 ++++++--
.../apache/juneau/remoteable/RemoteableMeta.java | 80 +++++++++-
.../juneau/remoteable/RemoteableMethodMeta.java | 68 ++++++---
.../juneau/examples/addressbook/IAddressBook.java | 3 -
.../org/apache/juneau/rest/client/RestClient.java | 8 +-
.../java/org/apache/juneau/rest/RestContext.java | 12 +-
.../org/apache/juneau/rest/RestJavaMethod.java | 33 +---
.../juneau/rest/remoteable/RemoteableServlet.java | 51 +++----
.../apache/juneau/rest/widget/PoweredByJuneau.java | 2 +-
13 files changed, 485 insertions(+), 157 deletions(-)
diff --git a/juneau-core/juneau-core-test/src/test/java/org/apache/juneau/utils/HttpUtilsTest.java b/juneau-core/juneau-core-test/src/test/java/org/apache/juneau/utils/HttpUtilsTest.java
new file mode 100644
index 0000000..607c8d1
--- /dev/null
+++ b/juneau-core/juneau-core-test/src/test/java/org/apache/juneau/utils/HttpUtilsTest.java
@@ -0,0 +1,170 @@
+// ***************************************************************************************************************************
+// * Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file *
+// * distributed with this work for additional information regarding copyright ownership. The ASF licenses this file *
+// * to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance *
+// * with the License. You may obtain a copy of the License at *
+// * *
+// * http://www.apache.org/licenses/LICENSE-2.0 *
+// * *
+// * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an *
+// * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the *
+// * specific language governing permissions and limitations under the License. *
+// ***************************************************************************************************************************
+package org.apache.juneau.utils;
+
+import static org.junit.Assert.*;
+
+import static org.apache.juneau.internal.HttpUtils.*;
+
+import org.junit.*;
+
+public class HttpUtilsTest {
+
+ public interface A {
+ void doGet();
+ void doGET();
+ void doPOST();
+ void doFOO();
+ void getFoo();
+ void postFoo();
+ void get();
+ void post();
+ void createFoo();
+ }
+
+ //====================================================================================================
+ // getHttpMethod()
+ //====================================================================================================
+
+ @Test
+ public void testGetHttpMethod_detect_nodefault() throws Exception {
+ assertEquals("GET", detectHttpMethod(A.class.getMethod("doGet"), true, null));
+ assertEquals("GET", detectHttpMethod(A.class.getMethod("doGET"), true, null));
+ assertEquals("POST", detectHttpMethod(A.class.getMethod("doPOST"), true, null));
+ assertEquals(null, detectHttpMethod(A.class.getMethod("doFOO"), true, null));
+ assertEquals("GET", detectHttpMethod(A.class.getMethod("getFoo"), true, null));
+ assertEquals("POST", detectHttpMethod(A.class.getMethod("postFoo"), true, null));
+ assertEquals("GET", detectHttpMethod(A.class.getMethod("get"), true, null));
+ assertEquals("POST", detectHttpMethod(A.class.getMethod("post"), true, null));
+ assertEquals(null, detectHttpMethod(A.class.getMethod("createFoo"), true, null));
+ }
+
+ @Test
+ public void testGetHttpMethod_detect_default() throws Exception {
+ assertEquals("GET", detectHttpMethod(A.class.getMethod("doGet"), true, "DELETE"));
+ assertEquals("GET", detectHttpMethod(A.class.getMethod("doGET"), true, "DELETE"));
+ assertEquals("POST", detectHttpMethod(A.class.getMethod("doPOST"), true, "DELETE"));
+ assertEquals("DELETE", detectHttpMethod(A.class.getMethod("doFOO"), true, "DELETE"));
+ assertEquals("GET", detectHttpMethod(A.class.getMethod("getFoo"), true, "DELETE"));
+ assertEquals("POST", detectHttpMethod(A.class.getMethod("postFoo"), true, "DELETE"));
+ assertEquals("GET", detectHttpMethod(A.class.getMethod("get"), true, "DELETE"));
+ assertEquals("POST", detectHttpMethod(A.class.getMethod("post"), true, "DELETE"));
+ assertEquals("DELETE", detectHttpMethod(A.class.getMethod("createFoo"), true, "DELETE"));
+ }
+
+ @Test
+ public void testGetHttpMethod_nodetect_nodefault() throws Exception {
+ assertEquals(null, detectHttpMethod(A.class.getMethod("doGet"), false, null));
+ assertEquals(null, detectHttpMethod(A.class.getMethod("doGET"), false, null));
+ assertEquals(null, detectHttpMethod(A.class.getMethod("doPOST"), false, null));
+ assertEquals(null, detectHttpMethod(A.class.getMethod("doFOO"), false, null));
+ assertEquals(null, detectHttpMethod(A.class.getMethod("getFoo"), false, null));
+ assertEquals(null, detectHttpMethod(A.class.getMethod("postFoo"), false, null));
+ assertEquals(null, detectHttpMethod(A.class.getMethod("get"), false, null));
+ assertEquals(null, detectHttpMethod(A.class.getMethod("post"), false, null));
+ assertEquals(null, detectHttpMethod(A.class.getMethod("createFoo"), false, null));
+ }
+
+ @Test
+ public void testGetHttpMethod_nodetect_default() throws Exception {
+ assertEquals("DELETE", detectHttpMethod(A.class.getMethod("doGet"), false, "DELETE"));
+ assertEquals("DELETE", detectHttpMethod(A.class.getMethod("doGET"), false, "DELETE"));
+ assertEquals("DELETE", detectHttpMethod(A.class.getMethod("doPOST"), false, "DELETE"));
+ assertEquals("DELETE", detectHttpMethod(A.class.getMethod("doFOO"), false, "DELETE"));
+ assertEquals("DELETE", detectHttpMethod(A.class.getMethod("getFoo"), false, "DELETE"));
+ assertEquals("DELETE", detectHttpMethod(A.class.getMethod("postFoo"), false, "DELETE"));
+ assertEquals("DELETE", detectHttpMethod(A.class.getMethod("get"), false, "DELETE"));
+ assertEquals("DELETE", detectHttpMethod(A.class.getMethod("post"), false, "DELETE"));
+ assertEquals("DELETE", detectHttpMethod(A.class.getMethod("createFoo"), false, "DELETE"));
+ }
+
+ //====================================================================================================
+ // getRestPath()
+ //====================================================================================================
+
+ public interface B1 {
+ void doGet();
+ void doGET();
+ void doPOST();
+ void doFOO();
+ void getFoo();
+ void postFoo();
+ void get();
+ void post();
+ void createFoo();
+ }
+
+ public interface B2 {
+ void doGet(int x, A y);
+ void doGET(int x, A y);
+ void doPOST(int x, A y);
+ void doFOO(int x, A y);
+ void getFoo(int x, A y);
+ void postFoo(int x, A y);
+ void get(int x, A y);
+ void post(int x, A y);
+ void createFoo(int x, A y);
+ }
+
+ @Test
+ public void testGetHttpPath_noargs_detect() throws Exception {
+ assertEquals("/", detectHttpPath(B1.class.getMethod("doGet"), true));
+ assertEquals("/", detectHttpPath(B1.class.getMethod("doGET"), true));
+ assertEquals("/", detectHttpPath(B1.class.getMethod("doPOST"), true));
+ assertEquals("/doFOO", detectHttpPath(B1.class.getMethod("doFOO"), true));
+ assertEquals("/foo", detectHttpPath(B1.class.getMethod("getFoo"), true));
+ assertEquals("/foo", detectHttpPath(B1.class.getMethod("postFoo"), true));
+ assertEquals("/", detectHttpPath(B1.class.getMethod("get"), true));
+ assertEquals("/", detectHttpPath(B1.class.getMethod("post"), true));
+ assertEquals("/createFoo", detectHttpPath(B1.class.getMethod("createFoo"), true));
+ }
+
+ @Test
+ public void testGetHttpPath_noargs_nodetect() throws Exception {
+ assertEquals("/doGet", detectHttpPath(B1.class.getMethod("doGet"), false));
+ assertEquals("/doGET", detectHttpPath(B1.class.getMethod("doGET"), false));
+ assertEquals("/doPOST", detectHttpPath(B1.class.getMethod("doPOST"), false));
+ assertEquals("/doFOO", detectHttpPath(B1.class.getMethod("doFOO"), false));
+ assertEquals("/getFoo", detectHttpPath(B1.class.getMethod("getFoo"), false));
+ assertEquals("/postFoo", detectHttpPath(B1.class.getMethod("postFoo"), false));
+ assertEquals("/get", detectHttpPath(B1.class.getMethod("get"), false));
+ assertEquals("/post", detectHttpPath(B1.class.getMethod("post"), false));
+ assertEquals("/createFoo", detectHttpPath(B1.class.getMethod("createFoo"), false));
+ }
+
+ @Test
+ public void testGetHttpPath_args_detect() throws Exception {
+ assertEquals("/", detectHttpPath(B2.class.getMethod("doGet",int.class,A.class), true));
+ assertEquals("/", detectHttpPath(B2.class.getMethod("doGET",int.class,A.class), true));
+ assertEquals("/", detectHttpPath(B2.class.getMethod("doPOST",int.class,A.class), true));
+ assertEquals("/doFOO", detectHttpPath(B2.class.getMethod("doFOO",int.class,A.class), true));
+ assertEquals("/foo", detectHttpPath(B2.class.getMethod("getFoo",int.class,A.class), true));
+ assertEquals("/foo", detectHttpPath(B2.class.getMethod("postFoo",int.class,A.class), true));
+ assertEquals("/", detectHttpPath(B2.class.getMethod("get",int.class,A.class), true));
+ assertEquals("/", detectHttpPath(B2.class.getMethod("post",int.class,A.class), true));
+ assertEquals("/createFoo", detectHttpPath(B2.class.getMethod("createFoo",int.class,A.class), true));
+ }
+
+ @Test
+ public void testGetHttpPath_args_nodetect() throws Exception {
+ assertEquals("/doGet", detectHttpPath(B2.class.getMethod("doGet",int.class,A.class), false));
+ assertEquals("/doGET", detectHttpPath(B2.class.getMethod("doGET",int.class,A.class), false));
+ assertEquals("/doPOST", detectHttpPath(B2.class.getMethod("doPOST",int.class,A.class), false));
+ assertEquals("/doFOO", detectHttpPath(B2.class.getMethod("doFOO",int.class,A.class), false));
+ assertEquals("/getFoo", detectHttpPath(B2.class.getMethod("getFoo",int.class,A.class), false));
+ assertEquals("/postFoo", detectHttpPath(B2.class.getMethod("postFoo",int.class,A.class), false));
+ assertEquals("/get", detectHttpPath(B2.class.getMethod("get",int.class,A.class), false));
+ assertEquals("/post", detectHttpPath(B2.class.getMethod("post",int.class,A.class), false));
+ assertEquals("/createFoo", detectHttpPath(B2.class.getMethod("createFoo",int.class,A.class), false));
+ }
+}
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/ClassMeta.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/ClassMeta.java
index 3aa73d6..9254624 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/ClassMeta.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/ClassMeta.java
@@ -31,7 +31,6 @@ import org.apache.juneau.http.*;
import org.apache.juneau.internal.*;
import org.apache.juneau.json.*;
import org.apache.juneau.parser.*;
-import org.apache.juneau.remoteable.*;
import org.apache.juneau.serializer.*;
import org.apache.juneau.transform.*;
import org.apache.juneau.utils.*;
@@ -93,7 +92,6 @@ public final class ClassMeta<T> implements Type {
isMemberClass; // True if this is a non-static member class.
private final Object primitiveDefault; // Default value for primitive type classes.
private final Map<String,Method>
- remoteableMethods, // Methods annotated with @RemoteMethod.
publicMethods; // All public methods, including static methods.
private final PojoSwap<?,?>[] childPojoSwaps; // Any PojoSwaps where the normal type is a subclass of this class.
private final ConcurrentHashMap<Class<?>,PojoSwap<?,?>>
@@ -177,7 +175,6 @@ public final class ClassMeta<T> implements Type {
this.numberConstructorType = builder.numberConstructorType;
this.primitiveDefault = builder.primitiveDefault;
this.publicMethods = builder.publicMethods;
- this.remoteableMethods = builder.remoteableMethods;
this.beanFilter = beanFilter;
this.pojoSwaps = builder.pojoSwaps.isEmpty() ? null : builder.pojoSwaps.toArray(new PojoSwap[builder.pojoSwaps.size()]);
this.builderSwap = builder.builderSwap;
@@ -246,7 +243,6 @@ public final class ClassMeta<T> implements Type {
this.isAbstract = mainType.isAbstract;
this.isMemberClass = mainType.isMemberClass;
this.primitiveDefault = mainType.primitiveDefault;
- this.remoteableMethods = mainType.remoteableMethods;
this.publicMethods = mainType.publicMethods;
this.beanContext = mainType.beanContext;
this.elementType = elementType;
@@ -299,7 +295,6 @@ public final class ClassMeta<T> implements Type {
this.isAbstract = false;
this.isMemberClass = false;
this.primitiveDefault = null;
- this.remoteableMethods = null;
this.publicMethods = null;
this.beanContext = null;
this.elementType = null;
@@ -351,8 +346,7 @@ public final class ClassMeta<T> implements Type {
numberConstructorType = null;
Object primitiveDefault = null;
Map<String,Method>
- publicMethods = new LinkedHashMap<>(),
- remoteableMethods = new LinkedHashMap<>();
+ publicMethods = new LinkedHashMap<>();
ClassMeta<?>
keyType = null,
valueType = null,
@@ -575,24 +569,6 @@ public final class ClassMeta<T> implements Type {
if (isAll(m, PUBLIC, NOT_DEPRECATED))
publicMethods.put(getMethodSignature(m), m);
- Map<Class<?>,Remoteable> remoteableMap = getAnnotationsMap(Remoteable.class, c);
- if (! remoteableMap.isEmpty()) {
- Map.Entry<Class<?>,Remoteable> e = remoteableMap.entrySet().iterator().next(); // Grab the first one.
- Class<?> ic = e.getKey();
- Remoteable r = e.getValue();
- String methodPaths = r.methodPaths();
- String expose = r.expose();
- for (Method m : "DECLARED".equals(expose) ? ic.getDeclaredMethods() : ic.getMethods()) {
- if (isPublic(m)) {
- RemoteMethod rm = m.getAnnotation(RemoteMethod.class);
- if (rm != null || ! "ANNOTATED".equals(expose)) {
- String path = "NAME".equals(methodPaths) ? m.getName() : getMethodSignature(m);
- remoteableMethods.put(path, m);
- }
- }
- }
- }
-
if (innerClass != Object.class) {
noArgConstructor = (Constructor<T>)findNoArgConstructor(implClass == null ? innerClass : implClass, Visibility.PUBLIC);
}
@@ -1484,15 +1460,6 @@ public final class ClassMeta<T> implements Type {
}
/**
- * Returns <jk>true</jk> if this class or one of it's methods are annotated with {@link Remoteable @Remotable}.
- *
- * @return <jk>true</jk> if this class is remoteable.
- */
- public boolean isRemoteable() {
- return remoteableMethods != null;
- }
-
- /**
* Returns <jk>true</jk> if this class is abstract.
*
* @return <jk>true</jk> if this class is abstract.
@@ -1511,19 +1478,6 @@ public final class ClassMeta<T> implements Type {
}
/**
- * All methods on this class annotated with {@link Remoteable @Remotable}, or all public methods if class is
- * annotated.
- *
- * <p>
- * Keys are method signatures.
- *
- * @return All remoteable methods on this class.
- */
- public Map<String,Method> getRemoteableMethods() {
- return remoteableMethods;
- }
-
- /**
* All public methods on this class including static methods.
*
* <p>
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/internal/HttpUtils.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/internal/HttpUtils.java
new file mode 100644
index 0000000..22b9c59
--- /dev/null
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/internal/HttpUtils.java
@@ -0,0 +1,92 @@
+// ***************************************************************************************************************************
+// * Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file *
+// * distributed with this work for additional information regarding copyright ownership. The ASF licenses this file *
+// * to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance *
+// * with the License. You may obtain a copy of the License at *
+// * *
+// * http://www.apache.org/licenses/LICENSE-2.0 *
+// * *
+// * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an *
+// * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the *
+// * specific language governing permissions and limitations under the License. *
+// ***************************************************************************************************************************
+package org.apache.juneau.internal;
+
+import static org.apache.juneau.internal.StringUtils.*;
+
+import java.lang.reflect.*;
+
+/**
+ * Utilities.
+ */
+public class HttpUtils {
+
+ /**
+ * Given a method name, infers the REST method name.
+ *
+ * @param m The Java method.
+ * @param detectMethod Whether we should auto-detect the HTTP method name from the Java method name.
+ * @param def The default HTTP method if not detected.
+ * @return The REST method name, or the default value if not found.
+ */
+ public static String detectHttpMethod(Method m, boolean detectMethod, String def) {
+ String n = m.getName();
+ if (detectMethod) {
+ if (n.startsWith("do") && n.length() > 2) {
+ String n2 = n.substring(2).toUpperCase();
+ if (isOneOf(n2, "GET","PUT","POST","DELETE","OPTIONS","HEAD","CONNECT","TRACE","PATCH"))
+ return n2;
+ }
+ for (String t : new String[]{"get","put","post","delete","options","head","connect","trace","patch"})
+ if (n.startsWith(t) && (n.length() == t.length() || Character.isUpperCase(n.charAt(t.length()))))
+ return t.toUpperCase();
+ }
+ return def;
+ }
+
+ /**
+ * Given a Java method, infers the REST path.
+ *
+ * @param m The Java method.
+ * @param detectMethod Whether we should auto-detect the HTTP method name from the Java method name.
+ * @return The REST path or <jk>null</jk> if not detected.
+ */
+ public static String detectHttpPath(Method m, boolean detectMethod) {
+ String n = m.getName();
+ if (detectMethod) {
+ if (n.startsWith("do") && n.length() > 2) {
+ String n2 = n.substring(2).toUpperCase();
+ if (isOneOf(n2, "GET","PUT","POST","DELETE","OPTIONS","HEAD","CONNECT","TRACE","PATCH"))
+ return "/";
+ }
+ for (String t : new String[]{"get","put","post","delete","options","head","connect","trace","patch"}) {
+ if (n.startsWith(t) && (n.length() == t.length() || Character.isUpperCase(n.charAt(t.length())))) {
+ return '/' + java.beans.Introspector.decapitalize(n.substring(t.length()));
+ }
+ }
+ }
+ return '/' + n;
+ }
+
+ /**
+ * Given a Java method, returns the arguments signature.
+ *
+ * @param m The Java method.
+ * @param full Whether fully-qualified names should be used for arguments.
+ * @return The arguments signature for the specified method.
+ */
+ public static String getMethodArgsSignature(Method m, boolean full) {
+ StringBuilder sb = new StringBuilder();
+ Class<?>[] pt = m.getParameterTypes();
+ if (pt.length == 0)
+ return "";
+ sb.append('(');
+ for (int i = 0; i < pt.length; i++) {
+ if (i > 0)
+ sb.append(',');
+ sb.append(full ? ClassUtils.getReadableClassName(pt[i]) : ClassUtils.getSimpleName(pt[i]));
+ }
+ sb.append(')');
+ return sb.toString();
+ }
+}
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/remoteable/RemoteMethod.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/remoteable/RemoteMethod.java
index a8cadfb..3b36de8 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/remoteable/RemoteMethod.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/remoteable/RemoteMethod.java
@@ -49,10 +49,12 @@ public @interface RemoteMethod {
* The path to the REST service for this Java method relative to the parent proxy interface URL.
*
* <p>
- * The default value is the Java method name (e.g. <js>"http://localhost/root-url/org.foo.MyInterface/myMethod"</js>)
- * if {@link Remoteable#methodPaths() @Remoteable.methodPaths()} is <js>"NAME"</js>, or the Java method signature
- * (e.g. <js>"http://localhost/root-url/org.foo.MyInterface/myMethod(int,boolean,java.lang.String)"</js>) if
- * it's <js>"SIGNATURE"</js>.
+ * If you do not specify a value, then the path is inferred from the Java method name.
+ *
+ * <h5 class='section'>See Also:</h5>
+ * <ul class='doctree'>
+ * <li class='link'><a class='doclink' href='../../../../overview-summary.html#juneau-rest-client.3rdPartyProxies.MethodNames'>Overview > juneau-rest-client > Interface Proxies Against 3rd-party REST Interfaces > Method Names</a>
+ * </ul>
*/
String path() default "";
@@ -69,7 +71,7 @@ public @interface RemoteMethod {
* <p>
* The default value is <js>"POST"</js>.
*/
- String httpMethod() default "POST";
+ String httpMethod() default "";
/**
* The value the remoteable method returns.
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/remoteable/Remoteable.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/remoteable/Remoteable.java
index a1b7afc..6815afe 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/remoteable/Remoteable.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/remoteable/Remoteable.java
@@ -57,20 +57,63 @@ public @interface Remoteable {
* <li><js>"ALL"</js> - All methods defined on the interface or class are exposed.
* </ul>
*/
- String expose() default "DECLARED";
+ String expose() default "";
/**
- * Defines the methodology to use for the path names of the methods when not explicitly defined via
- * {@link RemoteMethod#path() @RemoteMethod.path()}.
+ * Enable method signature paths.
*
* <p>
- * The options are:
- * <ul>
- * <li><js>"NAME"</js> (default) - Use the method name (e.g. "myMethod").
- * <li><js>"SIGNATURE"</js> - Use the method signature (e.g. "myMethod(int,boolean,java.lang.String,int[][][])").
- * </ul>
+ * When enabled, the HTTP paths for Java methods will default to the full method signature when not specified via {@link RemoteMethod#path() @RemoteMethod(path)}.
+ *
+ * <p>
+ * For example, the HTTP path for the <code>createPerson</code> method below is <js>"createPerson(org.apache.addressbook.CreatePerson)"</js>.
+ *
+ * <p class='bcode w800'>
+ * <jk>package</jk> org.apache.addressbook;
+ *
+ * <ja>@Remoteable</ja>(useMethodSignatures=<jk>true</jk>)
+ * <jk>public interface</jk> IAddressBook {
+ * Person createPerson(CreatePerson cp) <jk>throws</jk> Exception;
+ * }
+ *
+ * <jk>public class</jk> CreatePerson {...}
+ * </p>
+ *
* <p>
- * Note that if you use <js>"NAME"</js>, method names must be unique in the interface.
+ * By default, if you do not specify a <ja>@Remoteable</ja> annotation on your class, the default value for this setting is <jk>true</jk>.
+ * <br>So the path for the <code>createPerson</code> method shown is the same as above:
+ *
+ * <p class='bcode w800'>
+ * <jk>public interface</jk> IAddressBook {
+ * Person createPerson(CreatePerson cp) <jk>throws</jk> Exception;
+ * }
+ * </p>
+ *
+ * <p>
+ * The path can always be overridden using the {@link RemoteMethod#path() @RemoteMethod(path)} setting like so:
+ *
+ * <p class='bcode w800'>
+ * <jk>public interface</jk> IAddressBook {
+ * <ja>@RemoteMethod</ja>(path=<jk>"/people"</jk>)
+ * Person createPerson(CreatePerson cp) <jk>throws</jk> Exception;
+ * }
+ * </p>
+ *
+ * <p>
+ * If this setting is NOT enabled, then we infer the HTTP method and path from the Java method name.
+ * <br>In the example below, the HTTP method is detected as <js>"POST"</js> and the path is <js>"/person"</js>.
+ *
+ * <p class='bcode w800'>
+ * <ja>@Remoteable</ja>
+ * <jk>public interface</jk> IAddressBook {
+ * Person postPerson(CreatePerson cp) <jk>throws</jk> Exception;
+ * }
+ * </p>
+ *
+ * <h5 class='section'>See Also:</h5>
+ * <ul class='doctree'>
+ * <li class='link'><a class='doclink' href='../../../../overview-summary.html#juneau-rest-client.3rdPartyProxies.MethodNames'>Overview > juneau-rest-client > Interface Proxies Against 3rd-party REST Interfaces > Method Names</a>
+ * </ul>
*/
- String methodPaths() default "NAME";
+ boolean useMethodSignatures() default false;
}
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/remoteable/RemoteableMeta.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/remoteable/RemoteableMeta.java
index 89969fa..770a600 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/remoteable/RemoteableMeta.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/remoteable/RemoteableMeta.java
@@ -34,6 +34,9 @@ import java.util.*;
public class RemoteableMeta {
private final Map<Method,RemoteableMethodMeta> methods;
+ private final Map<String,RemoteableMethodMeta> methodsByPath;
+ private final String path;
+ private final Class<?> c;
/**
* Constructor.
@@ -42,31 +45,94 @@ public class RemoteableMeta {
* @param restUrl The absolute URL of the remote REST interface that implements this proxy interface.
*/
public RemoteableMeta(Class<?> c, String restUrl) {
- Remoteable r = getAnnotation(Remoteable.class, c);
+ this.c = c;
+ String expose = "DECLARED";
+ boolean useSigs = false;
+ String path = "";
+ List<Remoteable> rr = getAnnotationsParentFirst(Remoteable.class, c);
+ if (rr.isEmpty()) {
+ useSigs = true;
+ } else for (Remoteable r : rr) {
+ if (! r.expose().isEmpty())
+ expose = r.expose();
+ if (! r.path().isEmpty())
+ path = trimSlashes(r.path());
+ useSigs |= r.useMethodSignatures();
+ }
- String expose = r == null ? "DECLARED" : r.expose();
if (! isOneOf(expose, "ALL", "DECLARED", "ANNOTATED"))
throw new RemoteableMetadataException(c, "Invalid value specified for ''expose'' annotation. Valid values are [ALL,ANNOTATED,DECLARED].");
- Map<Method,RemoteableMethodMeta> _methods = new LinkedHashMap<>();
+ Map<Method,RemoteableMethodMeta> methods = new LinkedHashMap<>();
+ Map<String,RemoteableMethodMeta> methodsByPath = new LinkedHashMap<>();
for (Method m : expose.equals("DECLARED") ? c.getDeclaredMethods() : c.getMethods()) {
if (isPublic(m)) {
RemoteMethod rm = c.getAnnotation(RemoteMethod.class);
- if (rm != null || ! expose.equals("ANNOTATED"))
- _methods.put(m, new RemoteableMethodMeta(restUrl, m));
+ if (rm != null || ! expose.equals("ANNOTATED")) {
+ RemoteableMethodMeta rmm = new RemoteableMethodMeta(restUrl, m, useSigs);
+ methods.put(m, rmm);
+ methodsByPath.put(rmm.getPath(), rmm);
+ }
}
}
- this.methods = unmodifiableMap(_methods);
+ this.methods = unmodifiableMap(methods);
+ this.methodsByPath = unmodifiableMap(methodsByPath);
+ this.path = path;
+ }
+
+ /**
+ * Returns a map of all methods on this interface proxy keyed by HTTP path.
+ *
+ * @return
+ * A map of all methods on this remoteable interface keyed by HTTP path.
+ * <br>The keys never have leading slashes.
+ * <br>The map is never <jk>null</jk>.
+ */
+ public Map<String,RemoteableMethodMeta> getMethodsByPath() {
+ return methodsByPath;
}
/**
* Returns the metadata about the specified method on this interface proxy.
*
* @param m The method to look up.
- * @return Metadata about the method, or <jk>null</jk> if no metadata was found.
+ * @return Metadata about the method or <jk>null</jk> if no metadata was found.
*/
public RemoteableMethodMeta getMethodMeta(Method m) {
return methods.get(m);
}
+
+ /**
+ * Returns the metadata about the specified method on this interface proxy by the path defined on the method.
+ *
+ * @param p The HTTP path to look for.
+ * @return Metadata about the method or <jk>null</jk> if no metadata was found.
+ */
+ public RemoteableMethodMeta getMethodMetaByPath(String p) {
+ return methodsByPath.get(p);
+ }
+
+ /**
+ * Returns the Java class of this interface.
+ *
+ * @return
+ * The Java class of this interface.
+ * <br>Never <jk>null</jk>.
+ */
+ public Class<?> getJavaClass() {
+ return c;
+ }
+
+ /**
+ * Returns the HTTP path of this interface.
+ *
+ * @return
+ * The HTTP path of this interface.
+ * <br>Never <jk>null</jk>.
+ * <br>Never has leading or trailing slashes.
+ */
+ public String getPath() {
+ return path;
+ }
}
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/remoteable/RemoteableMethodMeta.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/remoteable/RemoteableMethodMeta.java
index e3ed3df..96bd0d4 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/remoteable/RemoteableMethodMeta.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/remoteable/RemoteableMethodMeta.java
@@ -12,7 +12,6 @@
// ***************************************************************************************************************************
package org.apache.juneau.remoteable;
-import static org.apache.juneau.internal.ClassUtils.*;
import static org.apache.juneau.internal.StringUtils.*;
import static org.apache.juneau.httppart.HttpPartType.*;
@@ -23,6 +22,7 @@ import org.apache.juneau.*;
import org.apache.juneau.http.annotation.*;
import org.apache.juneau.httppart.*;
import org.apache.juneau.httppart.bean.*;
+import org.apache.juneau.internal.*;
/**
* Contains the meta-data about a Java method on a remoteable interface.
@@ -38,21 +38,25 @@ import org.apache.juneau.httppart.bean.*;
public class RemoteableMethodMeta {
private final String httpMethod;
- private final String url;
+ private final String url, path;
private final RemoteMethodArg[] pathArgs, queryArgs, headerArgs, formDataArgs, otherArgs;
private final RemoteMethodBeanArg[] requestArgs;
private final RemoteMethodArg bodyArg;
private final RemoteMethodReturn methodReturn;
+ private final Method method;
/**
* Constructor.
*
* @param restUrl The absolute URL of the REST interface backing the interface proxy.
* @param m The Java method.
+ * @param useMethodSignatures If <jk>true</jk> then the default path for the method should be the full method signature.
*/
- public RemoteableMethodMeta(final String restUrl, Method m) {
- Builder b = new Builder(restUrl, m);
+ public RemoteableMethodMeta(final String restUrl, Method m, boolean useMethodSignatures) {
+ Builder b = new Builder(restUrl, m, useMethodSignatures);
+ this.method = m;
this.httpMethod = b.httpMethod;
+ this.path = b.path;
this.url = b.url;
this.pathArgs = b.pathArgs.toArray(new RemoteMethodArg[b.pathArgs.size()]);
this.queryArgs = b.queryArgs.toArray(new RemoteMethodArg[b.queryArgs.size()]);
@@ -65,7 +69,7 @@ public class RemoteableMethodMeta {
}
private static final class Builder {
- String httpMethod, url;
+ String httpMethod, url, path;
List<RemoteMethodArg>
pathArgs = new LinkedList<>(),
queryArgs = new LinkedList<>(),
@@ -77,30 +81,33 @@ public class RemoteableMethodMeta {
RemoteMethodArg bodyArg;
RemoteMethodReturn methodReturn;
- Builder(String restUrl, Method m) {
- Remoteable r = m.getDeclaringClass().getAnnotation(Remoteable.class);
+ Builder(String restUrl, Method m, boolean useMethodSignatures) {
+
RemoteMethod rm = m.getAnnotation(RemoteMethod.class);
- httpMethod = rm == null ? "POST" : rm.httpMethod();
- if (! isOneOf(httpMethod, "DELETE", "GET", "POST", "PUT"))
- throw new RemoteableMetadataException(m,
- "Invalid value specified for @RemoteMethod.httpMethod() annotation. Valid values are [DELTE,GET,POST,PUT].");
+ httpMethod = rm == null ? "" : rm.httpMethod();
+ path = rm == null ? "" : rm.path();
+
+ if (path.isEmpty()) {
+ path = HttpUtils.detectHttpPath(m, ! useMethodSignatures);
+ if (useMethodSignatures)
+ path += HttpUtils.getMethodArgsSignature(m, true);
+ }
+ if (httpMethod.isEmpty())
+ httpMethod = HttpUtils.detectHttpMethod(m, ! useMethodSignatures, "POST");
- String path = rm == null || rm.path().isEmpty() ? null : rm.path();
- String methodPaths = r == null ? "NAME" : r.methodPaths();
+ if (path.startsWith("/"))
+ path = path.substring(1);
- if (! isOneOf(methodPaths, "NAME", "SIGNATURE"))
+ if (! isOneOf(httpMethod, "DELETE", "GET", "POST", "PUT", "OPTIONS", "HEAD", "CONNECT", "TRACE", "PATCH"))
throw new RemoteableMetadataException(m,
- "Invalid value specified for @Remoteable.methodPaths() annotation. Valid values are [NAME,SIGNATURE].");
+ "Invalid value specified for @RemoteMethod.httpMethod() annotation. Valid values are [DELTE,GET,POST,PUT].");
ReturnValue rv = m.getReturnType() == void.class ? ReturnValue.NONE : rm == null ? ReturnValue.BODY : rm.returns();
methodReturn = new RemoteMethodReturn(m, rv);
- url =
- trimSlashes(restUrl)
- + '/'
- + (path != null ? trimSlashes(path) : urlEncode("NAME".equals(methodPaths) ? m.getName() : getMethodSignature(m)));
+ url = trimSlashes(restUrl) + '/' + urlEncode(path);
for (int i = 0; i < m.getParameterTypes().length; i++) {
RemoteMethodArg rma = RemoteMethodArg.create(m, i);
@@ -222,4 +229,27 @@ public class RemoteableMethodMeta {
public RemoteMethodReturn getReturns() {
return methodReturn;
}
+
+ /**
+ * Returns the HTTP path of this method.
+ *
+ * @return
+ * The HTTP path of this method relative to the parent interface.
+ * <br>Never <jk>null</jk>.
+ * <br>Never has leading or trailing slashes.
+ */
+ public String getPath() {
+ return path;
+ }
+
+ /**
+ * Returns the underlying Java method that this metadata is about.
+ *
+ * @return
+ * The underlying Java method that this metadata is about.
+ * <br>Never <jk>null</jk>.
+ */
+ public Method getJavaMethod() {
+ return method;
+ }
}
diff --git a/juneau-examples/juneau-examples-rest/src/main/java/org/apache/juneau/examples/addressbook/IAddressBook.java b/juneau-examples/juneau-examples-rest/src/main/java/org/apache/juneau/examples/addressbook/IAddressBook.java
index 80dba47..4f68025 100755
--- a/juneau-examples/juneau-examples-rest/src/main/java/org/apache/juneau/examples/addressbook/IAddressBook.java
+++ b/juneau-examples/juneau-examples-rest/src/main/java/org/apache/juneau/examples/addressbook/IAddressBook.java
@@ -14,12 +14,9 @@ package org.apache.juneau.examples.addressbook;
import java.util.*;
-import org.apache.juneau.remoteable.*;
-
/**
* Interface used to help illustrate proxy interfaces.
*/
-@Remoteable
public interface IAddressBook {
/** Initialize this address book with preset entries */
diff --git a/juneau-rest/juneau-rest-client/src/main/java/org/apache/juneau/rest/client/RestClient.java b/juneau-rest/juneau-rest-client/src/main/java/org/apache/juneau/rest/client/RestClient.java
index d102e32..09a5944 100644
--- a/juneau-rest/juneau-rest-client/src/main/java/org/apache/juneau/rest/client/RestClient.java
+++ b/juneau-rest/juneau-rest-client/src/main/java/org/apache/juneau/rest/client/RestClient.java
@@ -12,7 +12,6 @@
// ***************************************************************************************************************************
package org.apache.juneau.rest.client;
-import static org.apache.juneau.internal.ClassUtils.*;
import static org.apache.juneau.internal.StringUtils.*;
import static org.apache.juneau.httppart.HttpPartType.*;
import static org.apache.juneau.remoteable.ReturnValue.*;
@@ -1020,9 +1019,8 @@ public class RestClient extends BeanContext implements Closeable {
public <T> T getRemoteableProxy(final Class<T> interfaceClass, Object restUrl, final Serializer serializer, final Parser parser) {
if (restUrl == null) {
- Remoteable r = getAnnotation(Remoteable.class, interfaceClass);
-
- String path = r == null ? "" : trimSlashes(r.path());
+ RemoteableMeta rm = new RemoteableMeta(interfaceClass, asString(restUrl));
+ String path = rm.getPath();
if (path.indexOf("://") == -1) {
if (rootUrl == null)
throw new RemoteableMetadataException(interfaceClass, "Root URI has not been specified. Cannot construct absolute path to remoteable proxy.");
@@ -1085,7 +1083,7 @@ public class RestClient extends BeanContext implements Closeable {
if (pt == PATH)
rc.path(pn, val, p.getSerializer(s), schema);
else if (val != null) {
- if (pt == QUERY)
+ if (pt == QUERY)
rc.query(pn, val, sie, ps, schema);
else if (pt == FORMDATA)
rc.formData(pn, val, sie, ps, schema);
diff --git a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestContext.java b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestContext.java
index 161b7ad..701f8f9 100644
--- a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestContext.java
+++ b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestContext.java
@@ -45,6 +45,7 @@ import org.apache.juneau.jsonschema.*;
import org.apache.juneau.msgpack.*;
import org.apache.juneau.parser.*;
import org.apache.juneau.plaintext.*;
+import org.apache.juneau.remoteable.*;
import org.apache.juneau.rest.annotation.*;
import org.apache.juneau.rest.converters.*;
import org.apache.juneau.rest.exception.*;
@@ -3234,8 +3235,8 @@ public final class RestContext extends BeanContext {
if ("PROXY".equals(httpMethod)) {
final ClassMeta<?> interfaceClass = beanContext.getClassMeta(method.getGenericReturnType());
- final Map<String,Method> remoteableMethods = interfaceClass.getRemoteableMethods();
- if (remoteableMethods.isEmpty())
+ final RemoteableMeta rm = new RemoteableMeta(interfaceClass.getInnerClass(), "/foo");
+ if (rm.getMethodsByPath().isEmpty())
throw new RestException(SC_INTERNAL_SERVER_ERROR, "Method {0} returns an interface {1} that doesn't define any remoteable methods.", getMethodSignature(method), interfaceClass.getReadableName());
sm = new RestJavaMethod(resource, method, this) {
@@ -3250,15 +3251,16 @@ public final class RestContext extends BeanContext {
final Object o = res.getOutput();
if ("GET".equals(req.getMethod())) {
- res.setOutput(getMethodInfo(remoteableMethods.values()));
+ res.setOutput(rm.getMethodsByPath().keySet());
return SC_OK;
} else if ("POST".equals(req.getMethod())) {
if (pathInfo.indexOf('/') != -1)
pathInfo = pathInfo.substring(pathInfo.lastIndexOf('/')+1);
pathInfo = urlDecode(pathInfo);
- java.lang.reflect.Method m = remoteableMethods.get(pathInfo);
- if (m != null) {
+ RemoteableMethodMeta rmm = rm.getMethodMetaByPath(pathInfo);
+ if (rmm != null) {
+ Method m = rmm.getJavaMethod();
try {
// Parse the args and invoke the method.
Parser p = req.getBody().getParser();
diff --git a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestJavaMethod.java b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestJavaMethod.java
index 297dcc6..94f9131 100644
--- a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestJavaMethod.java
+++ b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestJavaMethod.java
@@ -22,7 +22,6 @@ import static org.apache.juneau.rest.RestContext.*;
import static org.apache.juneau.rest.util.RestUtils.*;
import static org.apache.juneau.httppart.HttpPartType.*;
-import java.beans.*;
import java.lang.annotation.*;
import java.lang.reflect.*;
import java.util.*;
@@ -37,6 +36,7 @@ import org.apache.juneau.http.annotation.*;
import org.apache.juneau.httppart.*;
import org.apache.juneau.httppart.bean.*;
import org.apache.juneau.internal.*;
+import org.apache.juneau.internal.HttpUtils;
import org.apache.juneau.parser.*;
import org.apache.juneau.rest.annotation.*;
import org.apache.juneau.rest.exception.*;
@@ -195,34 +195,13 @@ public class RestJavaMethod implements Comparable<RestJavaMethod> {
}
String p = m.path();
- if (isEmpty(p)) {
- p = method.getName();
- if (m.name().equals("")) {
- for (String t : new String[]{"get","put","post","delete","options","head","connect","trace","patch"}) {
- if (p.startsWith(t) && (p.length() == t.length() || Character.isUpperCase(p.charAt(t.length())))) {
- p = Introspector.decapitalize(p.substring(t.length()));
- break;
- }
- }
- if (! p.startsWith("/"))
- p = "/" + p;
- }
- }
+ if (isEmpty(p))
+ p = HttpUtils.detectHttpPath(method, true);
httpMethod = m.name().toUpperCase(Locale.ENGLISH);
- if (httpMethod.equals("") && method.getName().startsWith("do"))
- httpMethod = method.getName().substring(2).toUpperCase(Locale.ENGLISH);
- if (httpMethod.equals("")) {
- String mn = method.getName();
- httpMethod = "GET";
- for (String t : new String[]{"get","put","post","delete","options","head","connect","trace","patch"}) {
- if (mn.startsWith(t) && (mn.length() == t.length() || Character.isUpperCase(mn.charAt(t.length())))) {
- httpMethod = t.toUpperCase();
- break;
- }
- }
- }
- if (httpMethod.equals("METHOD"))
+ if (httpMethod.isEmpty())
+ httpMethod = HttpUtils.detectHttpMethod(method, true, "GET");
+ if ("METHOD".equals(httpMethod))
httpMethod = "*";
priority = m.priority();
diff --git a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/remoteable/RemoteableServlet.java b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/remoteable/RemoteableServlet.java
index b44364a..7a2493d 100644
--- a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/remoteable/RemoteableServlet.java
+++ b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/remoteable/RemoteableServlet.java
@@ -22,7 +22,6 @@ import java.util.*;
import java.util.Map;
import java.util.concurrent.*;
-import org.apache.juneau.*;
import org.apache.juneau.dto.*;
import org.apache.juneau.dto.html5.*;
import org.apache.juneau.http.*;
@@ -30,6 +29,7 @@ import org.apache.juneau.http.annotation.*;
import org.apache.juneau.http.annotation.Header;
import org.apache.juneau.internal.*;
import org.apache.juneau.parser.*;
+import org.apache.juneau.remoteable.*;
import org.apache.juneau.rest.*;
import org.apache.juneau.rest.annotation.*;
import org.apache.juneau.rest.exception.*;
@@ -52,7 +52,7 @@ import org.apache.juneau.rest.exception.*;
@SuppressWarnings({"serial","javadoc"})
public abstract class RemoteableServlet extends BasicRestServlet {
- private final Map<String,Class<?>> classNameMap = new ConcurrentHashMap<>();
+ private final Map<String,RemoteableMeta> serviceMap = new ConcurrentHashMap<>();
//--------------------------------------------------------------------------------
// Abstract methods
@@ -81,10 +81,8 @@ public abstract class RemoteableServlet extends BasicRestServlet {
)
public List<LinkString> getInterfaces() throws Exception {
List<LinkString> l = new LinkedList<>();
- boolean useAll = ! useOnlyAnnotated();
for (Class<?> c : getServiceMap().keySet())
- if (useAll || getContext().getBeanContext().getClassMeta(c).isRemoteable())
- l.add(new LinkString(c.getName(), "servlet:/{0}", urlEncode(c.getName())));
+ l.add(new LinkString(c.getName(), "servlet:/{0}", urlEncode(c.getName())));
return l;
}
@@ -125,13 +123,13 @@ public abstract class RemoteableServlet extends BasicRestServlet {
) throws NotFound, Exception {
// Find the method.
- java.lang.reflect.Method m = getMethods(javaInterface).get(javaMethod);
- if (m == null)
+ RemoteableMethodMeta rmm = getMethods(javaInterface).get(javaMethod);
+ if (rmm == null)
throw new NotFound("Method not found");
Table t = table();
- Type[] types = m.getGenericParameterTypes();
+ Type[] types = rmm.getJavaMethod().getGenericParameterTypes();
if (types.length == 0) {
t.child(tr(td("No arguments").colspan(3).style("text-align:center")));
} else {
@@ -195,19 +193,20 @@ public abstract class RemoteableServlet extends BasicRestServlet {
// Find the parser.
if (p == null)
throw new UnsupportedMediaType("Could not find parser for media type ''{0}''", contentType);
- Class<?> c = getInterfaceClass(javaInterface);
+ RemoteableMeta c = getInterfaceClass(javaInterface);
// Find the service.
- Object service = getServiceMap().get(c);
+ Object service = getServiceMap().get(c.getJavaClass());
if (service == null)
throw new NotFound("Service not found");
// Find the method.
- java.lang.reflect.Method m = getMethods(javaInterface).get(javaMethod);
- if (m == null)
+ RemoteableMethodMeta rmm = getMethods(javaInterface).get(javaMethod);
+ if (rmm == null)
throw new NotFound("Method not found");
// Parse the args and invoke the method.
+ java.lang.reflect.Method m = rmm.getJavaMethod();
Object[] params = p.parseArgs(r, m.getGenericParameterTypes());
return m.invoke(service, params);
}
@@ -217,29 +216,25 @@ public abstract class RemoteableServlet extends BasicRestServlet {
// Other methods
//--------------------------------------------------------------------------------
- private boolean useOnlyAnnotated() {
- return getContext().getProperties().getBoolean(RemoteableServiceProperties.REMOTEABLE_includeOnlyRemotableMethods, false);
- }
-
- private Map<String,java.lang.reflect.Method> getMethods(String javaInterface) throws Exception {
- Class<?> c = getInterfaceClass(javaInterface);
- ClassMeta<?> cm = getContext().getBeanContext().getClassMeta(c);
- return (useOnlyAnnotated() ? cm.getRemoteableMethods() : cm.getPublicMethods());
+ private Map<String,RemoteableMethodMeta> getMethods(String javaInterface) throws Exception {
+ return getInterfaceClass(javaInterface).getMethodsByPath();
}
/**
* Return the <code>Class</code> given it's name if it exists in the services map.
*/
- private Class<?> getInterfaceClass(String javaInterface) throws NotFound, Exception {
- Class<?> c = classNameMap.get(javaInterface);
- if (c == null) {
- for (Class<?> c2 : getServiceMap().keySet())
- if (c2.getName().equals(javaInterface)) {
- classNameMap.put(javaInterface, c2);
- return c2;
+ private RemoteableMeta getInterfaceClass(String javaInterface) throws NotFound, Exception {
+ RemoteableMeta rm = serviceMap.get(javaInterface);
+ if (rm == null) {
+ for (Class<?> c : getServiceMap().keySet()) {
+ if (c.getName().equals(javaInterface)) {
+ rm = new RemoteableMeta(c, null);
+ serviceMap.put(javaInterface, rm);
+ return rm;
}
+ }
throw new NotFound("Interface class not found");
}
- return c;
+ return rm;
}
}
diff --git a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/widget/PoweredByJuneau.java b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/widget/PoweredByJuneau.java
index f581635..e399d76 100644
--- a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/widget/PoweredByJuneau.java
+++ b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/widget/PoweredByJuneau.java
@@ -54,7 +54,7 @@ public class PoweredByJuneau extends Widget {
@Override /* Widget */
public String getHtml(RestRequest req) throws Exception {
UriResolver r = req.getUriResolver();
- return "<a href='http://juneau.apache.org'><img style='float:right;padding-right:20px;height:32px' src='"+r.resolve("servlet:/htdocs/juneau.png")+"'>";
+ return "<a href='http://juneau.apache.org'><img style='float:right;padding-right:20px;height:32px' src='"+r.resolve("servlet:/htdocs/images/juneau.png")+"'>";
}
}