JUNEAU-177 Allow REST methods at specific paths to be overridden by
methods in child classes.
diff --git a/juneau-rest/juneau-rest-server-utest/src/test/java/org/apache/juneau/rest/annotation/RestMethodPathTest.java b/juneau-rest/juneau-rest-server-utest/src/test/java/org/apache/juneau/rest/annotation/RestMethodPathTest.java
index f944245..4a89ea5 100644
--- a/juneau-rest/juneau-rest-server-utest/src/test/java/org/apache/juneau/rest/annotation/RestMethodPathTest.java
+++ b/juneau-rest/juneau-rest-server-utest/src/test/java/org/apache/juneau/rest/annotation/RestMethodPathTest.java
@@ -84,4 +84,30 @@
 		a.get("/x/foo").execute().assertBody("g");

 		a.get("/x/foo/x").execute().assertBody("h");

 	}

+

+	//=================================================================================================================

+	// Overridden URL patterns

+	//=================================================================================================================

+

+	@Rest

+	public static class B1 {

+		@RestMethod(name=GET, path="/foo")

+		public String b01a() {

+			return "a";

+		}

+	}

+

+	@Rest

+	public static class B2 extends B1 {

+		@RestMethod(name=GET, path="/foo")

+		public String b02a() {  // Overrides method on parent.

+			return "b";

+		}

+	}

+	static MockRest b2 = MockRest.build(B2.class, null);

+

+	@Test

+	public void b01_pathOverriddenByChild() throws Exception {

+		b2.get("/foo").execute().assertBody("b");

+	}

 }

diff --git a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestCallRouter.java b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestCallRouter.java
index 6aa2fe3..45ef6c4 100644
--- a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestCallRouter.java
+++ b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestCallRouter.java
@@ -40,7 +40,6 @@
 	 */
 	static final class Builder {
 		private List<RestMethodContext> childMethods = new ArrayList<>();
-		private Set<String> collisions = new HashSet<>();
 		private String httpMethodName;
 
 		Builder(String httpMethodName) {
@@ -51,13 +50,7 @@
 			return httpMethodName;
 		}
 
-		Builder add(RestMethodContext m) throws RestServletException {
-			if (! m.hasGuardsOrMatchers()) {
-				String p = m.getHttpMethod() + ":" + m.getPathPattern();
-				if (collisions.contains(p))
-					throw new RestServletException("Duplicate Java methods assigned to the same method/pattern:  ''{0}''", p);
-				collisions.add(p);
-			}
+		Builder add(RestMethodContext m) {
 			childMethods.add(m);
 			return this;
 		}
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 cbf42b1..3984786 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
@@ -3936,7 +3936,7 @@
 		}

 	}

 

-	private static void addToRouter(Map<String, RestCallRouter.Builder> routers, String httpMethodName, RestMethodContext cm) throws RestServletException {

+	private static void addToRouter(Map<String, RestCallRouter.Builder> routers, String httpMethodName, RestMethodContext cm) {

 		if (! routers.containsKey(httpMethodName))

 			routers.put(httpMethodName, new RestCallRouter.Builder(httpMethodName));

 		routers.get(httpMethodName).add(cm);

diff --git a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestMethodContext.java b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestMethodContext.java
index fc20866..e0144a1 100644
--- a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestMethodContext.java
+++ b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestMethodContext.java
@@ -580,6 +580,7 @@
 	final ResponseBeanMeta responseMeta;
 
 	final Enablement debug;
+	final int hierarchyDepth;
 
 	@SuppressWarnings("deprecation")
 	RestMethodContext(RestMethodContextBuilder b) throws ServletException {
@@ -593,6 +594,14 @@
 		// Need this to access methods in anonymous inner classes.
 		mi.setAccessible();
 
+		int hd = 0;
+		Class<?> sc = b.method.getDeclaringClass().getSuperclass();
+		while (sc != null) {
+			hd++;
+			sc = sc.getSuperclass();
+		}
+		hierarchyDepth = hd;
+
 		PropertyStore ps = getPropertyStore();
 		ResourceResolver rr = context.getResourceResolver();
 		Object r = context.getResource();
@@ -960,6 +969,10 @@
 		if (c != 0)
 			return c;
 
+		c = compare(o.hierarchyDepth, hierarchyDepth);
+		if (c != 0)
+			return c;
+
 		c = compare(o.requiredMatchers.length, requiredMatchers.length);
 		if (c != 0)
 			return c;
@@ -972,6 +985,10 @@
 		if (c != 0)
 			return c;
 
+		c = compare(method.getName(), o.method.getName());
+		if (c != 0)
+			return c;
+
 		return 0;
 	}