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 59f6991  REST refactoring.
59f6991 is described below

commit 59f69919df53c78e280fb1f0e27322de08ffb7e0
Author: JamesBognar <[email protected]>
AuthorDate: Sat Jan 16 13:01:15 2021 -0500

    REST refactoring.
---
 .../org/apache/juneau/utils/MethodInvokerTest.java |   2 +-
 .../java/org/apache/juneau/BasicException.java     |  10 +
 .../java/org/apache/juneau/reflect/MethodInfo.java |  13 +-
 .../org/apache/juneau/utils/MethodInvoker.java     |  41 ++-
 .../apache/juneau/rest/mock/MockRestClient.java    |   6 +-
 .../java/org/apache/juneau/rest/Swagger_Test.java  |   4 +-
 .../apache/juneau/rest/testutils/TestUtils.java    |   5 +-
 .../main/java/org/apache/juneau/rest/RestCall.java | 283 ++++++++++++---------
 .../java/org/apache/juneau/rest/RestContext.java   | 268 +++++++++----------
 .../org/apache/juneau/rest/RestMethodContext.java  |   9 +-
 .../java/org/apache/juneau/rest/RestServlet.java   |   2 +-
 11 files changed, 369 insertions(+), 274 deletions(-)

diff --git 
a/juneau-core/juneau-core-utest/src/test/java/org/apache/juneau/utils/MethodInvokerTest.java
 
b/juneau-core/juneau-core-utest/src/test/java/org/apache/juneau/utils/MethodInvokerTest.java
index 200c232..608e808 100644
--- 
a/juneau-core/juneau-core-utest/src/test/java/org/apache/juneau/utils/MethodInvokerTest.java
+++ 
b/juneau-core/juneau-core-utest/src/test/java/org/apache/juneau/utils/MethodInvokerTest.java
@@ -81,7 +81,7 @@ public class MethodInvokerTest {
                MethodExecStats mes = new MethodExecStats(m);
                MethodInvoker mi = new MethodInvoker(m, mes);
 
-               assertEquals(m, mi.inner());
+               assertEquals(m, mi.inner().inner());
                assertEquals("A", mi.getDeclaringClass().getSimpleName());
                assertEquals("foo", mi.getName());
        }
diff --git 
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/BasicException.java
 
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/BasicException.java
index 4e0bc03..39343bc 100644
--- 
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/BasicException.java
+++ 
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/BasicException.java
@@ -66,4 +66,14 @@ public class BasicException extends Exception {
        public <T extends Throwable> T getCause(Class<T> c) {
                return ThrowableUtils.getCause(c, this);
        }
+
+       /**
+        * Returns the caused-by exception if there is one.
+        *
+        * @return The caused-by exception if there is one, or this exception 
if there isn't.
+        */
+       public Throwable unwrap() {
+               Throwable t = getCause();
+               return t == null ? this : t;
+       }
 }
diff --git 
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/reflect/MethodInfo.java
 
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/reflect/MethodInfo.java
index a8de582..7c47ca3 100644
--- 
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/reflect/MethodInfo.java
+++ 
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/reflect/MethodInfo.java
@@ -436,8 +436,10 @@ public final class MethodInfo extends ExecutableInfo 
implements Comparable<Metho
        public <T> T invoke(Object obj, Object...args) throws 
ExecutableException {
                try {
                        return (T)m.invoke(obj, args);
-               } catch (IllegalAccessException | InvocationTargetException e) {
+               } catch (IllegalAccessException e) {
                        throw new ExecutableException(e);
+               } catch (InvocationTargetException e) {
+                       throw new ExecutableException(e.getTargetException());
                }
        }
 
@@ -569,6 +571,15 @@ public final class MethodInfo extends ExecutableInfo 
implements Comparable<Metho
                return m.isBridge();
        }
 
+       /**
+        * Returns the name of this method.
+        *
+        * @return The name of this method
+        */
+       public String getName() {
+               return m.getName();
+       }
+
        @Override
        public int compareTo(MethodInfo o) {
                int i = getSimpleName().compareTo(o.getSimpleName());
diff --git 
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/utils/MethodInvoker.java
 
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/utils/MethodInvoker.java
index d89206a..91006cd 100644
--- 
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/utils/MethodInvoker.java
+++ 
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/utils/MethodInvoker.java
@@ -13,14 +13,19 @@
 package org.apache.juneau.utils;
 
 import java.lang.reflect.*;
+import java.util.*;
+import java.util.stream.*;
 
+import org.apache.juneau.*;
+import org.apache.juneau.cp.*;
 import org.apache.juneau.mstat.*;
+import org.apache.juneau.reflect.*;
 
 /**
  * A wrapper around a {@link Method#invoke(Object, Object...)} method that 
allows for basic instrumentation.
  */
 public class MethodInvoker {
-       private final Method m;
+       private final MethodInfo m;
        private final MethodExecStats stats;
 
        /**
@@ -30,7 +35,7 @@ public class MethodInvoker {
         * @param stats The instrumentor.
         */
        public MethodInvoker(Method m, MethodExecStats stats) {
-               this.m = m;
+               this.m = MethodInfo.of(m);
                this.stats = stats;
        }
 
@@ -39,7 +44,7 @@ public class MethodInvoker {
         *
         * @return The inner method.
         */
-       public Method inner() {
+       public MethodInfo inner() {
                return m;
        }
 
@@ -49,32 +54,46 @@ public class MethodInvoker {
         * @param o  The object the underlying method is invoked from.
         * @param args  The arguments used for the method call.
         * @return  The result of dispatching the method represented by this 
object on {@code obj} with parameters {@code args}
-        * @throws IllegalAccessException Thrown from underlying method.
-        * @throws IllegalArgumentException Thrown from underlying method.
-        * @throws InvocationTargetException Thrown from underlying method.
+        * @throws ExecutableException If error occurred trying to invoke the 
method.
         */
-       public Object invoke(Object o, Object...args) throws 
IllegalAccessException, IllegalArgumentException, InvocationTargetException {
+       public Object invoke(Object o, Object...args) throws 
ExecutableException {
                long startTime = System.nanoTime();
                stats.started();
                try {
-                       return m.invoke(o, args);
+                       return m.inner().invoke(o, args);
                } catch (IllegalAccessException|IllegalArgumentException e) {
                        stats.error(e);
-                       throw e;
+                       throw new ExecutableException(e);
                } catch (InvocationTargetException e) {
                        stats.error(e.getTargetException());
-                       throw e;
+                       throw new ExecutableException(e.getTargetException());
                } finally {
                        stats.finished(System.nanoTime() - startTime);
                }
        }
 
        /**
+        * Invokes the wrapped method using parameters from the specified bean 
factory.
+        *
+        * @param beanFactory The bean factory to use to resolve parameters.
+        * @param o The object to invoke the method on.
+        * @return The result of invoking the method.
+        * @throws ExecutableException If error occurred trying to invoke the 
method.
+        */
+       public Object invokeUsingFactory(BeanFactory beanFactory, Object o) 
throws ExecutableException {
+               List<ClassInfo> missing;
+               missing = beanFactory.getMissingParamTypes(m.getParamTypes());
+               if (missing.isEmpty())
+                       return invoke(o, 
beanFactory.getParams(m.getParamTypes()));
+               throw new ExecutableException("Could not find prerequisites to 
invoke method ''{0}'': {1}", m.getFullName(), 
missing.stream().map(x->x.getSimpleName()).collect(Collectors.joining(",")));
+       }
+
+       /**
         * Convenience method for calling <c>inner().getDeclaringClass()</c>
         *
         * @return The declaring class of the method.
         */
-       public Class<?> getDeclaringClass() {
+       public ClassInfo getDeclaringClass() {
                return m.getDeclaringClass();
        }
 
diff --git 
a/juneau-rest/juneau-rest-mock/src/main/java/org/apache/juneau/rest/mock/MockRestClient.java
 
b/juneau-rest/juneau-rest-mock/src/main/java/org/apache/juneau/rest/mock/MockRestClient.java
index f47d9d5..1948382 100644
--- 
a/juneau-rest/juneau-rest-mock/src/main/java/org/apache/juneau/rest/mock/MockRestClient.java
+++ 
b/juneau-rest/juneau-rest-mock/src/main/java/org/apache/juneau/rest/mock/MockRestClient.java
@@ -48,7 +48,7 @@ import org.apache.juneau.rest.logging.*;
  *     The class itself extends from {@link RestClient} providing it with the 
rich feature set of that API and combines
  *     it with the Apache HttpClient {@link HttpClientConnection} interface 
for processing requests.
  *  The class converts {@link HttpRequest} objects to instances of {@link 
MockServletRequest} and {@link MockServletResponse} which are passed directly
- *  to the call handler on the resource class {@link 
RestContext#execute(HttpServletRequest,HttpServletResponse)}.
+ *  to the call handler on the resource class {@link 
RestContext#execute(Object,HttpServletRequest,HttpServletResponse)}.
  *  In effect, you're fully testing your REST API as if it were running in a 
live servlet container, yet not
  *  actually having to run in a servlet container.
  *  All aspects of the client and server side code are tested, yet no servlet 
container is required.  The actual
@@ -238,6 +238,7 @@ public class MockRestClient extends RestClient implements 
HttpClientConnection {
        
//-------------------------------------------------------------------------------------------------------------------
 
        private final RestContext restBeanCtx;
+       private final Object restObject;
        private final String contextPath, servletPath;
        private final Map<String,String> pathVars;
 
@@ -256,6 +257,7 @@ public class MockRestClient extends RestClient implements 
HttpClientConnection {
        public MockRestClient(PropertyStore ps) {
                super(preInit(ps));
                this.restBeanCtx = 
getInstanceProperty(MOCKRESTCLIENT_restBeanCtx, RestContext.class);
+               this.restObject = restBeanCtx.getResource();
                this.contextPath = 
getStringProperty(MOCKRESTCLIENT_contextPath, "");
                this.servletPath = 
getStringProperty(MOCKRESTCLIENT_servletPath, "");
                this.pathVars = getMapProperty(MOCKRESTCLIENT_pathVars, 
String.class);
@@ -753,7 +755,7 @@ public class MockRestClient extends RestClient implements 
HttpClientConnection {
        public HttpResponse receiveResponseHeader() throws HttpException, 
IOException {
                try {
                        MockServletResponse res = MockServletResponse.create();
-                       restBeanCtx.execute(sreq.get(), res);
+                       restBeanCtx.execute(restObject, sreq.get(), res);
 
                        // If the status isn't set, something's broken.
                        if (res.getStatus() == 0)
diff --git 
a/juneau-rest/juneau-rest-server-utest/src/test/java/org/apache/juneau/rest/Swagger_Test.java
 
b/juneau-rest/juneau-rest-server-utest/src/test/java/org/apache/juneau/rest/Swagger_Test.java
index 560b256..87691f8 100644
--- 
a/juneau-rest/juneau-rest-server-utest/src/test/java/org/apache/juneau/rest/Swagger_Test.java
+++ 
b/juneau-rest/juneau-rest-server-utest/src/test/java/org/apache/juneau/rest/Swagger_Test.java
@@ -44,14 +44,14 @@ public class Swagger_Test {
 
        private Swagger getSwaggerWithFile(Object resource) throws Exception {
                RestContext rc = 
RestContext.create(resource).fileFinder(TestClasspathFileFinder.class).build();
-               RestRequest req = rc.createRequest(new RestCall(rc, new 
MockServletRequest(), null));
+               RestRequest req = rc.createRequest(new RestCall(resource, rc, 
new MockServletRequest(), null));
                RestInfoProvider ip = rc.getInfoProvider();
                return ip.getSwagger(req);
        }
 
        private static Swagger getSwagger(Object resource) throws Exception {
                RestContext rc = RestContext.create(resource).build();
-               RestRequest req = rc.createRequest(new RestCall(rc, new 
MockServletRequest(), null));
+               RestRequest req = rc.createRequest(new RestCall(resource, rc, 
new MockServletRequest(), null));
                RestInfoProvider ip = rc.getInfoProvider();
                return ip.getSwagger(req);
        }
diff --git 
a/juneau-rest/juneau-rest-server-utest/src/test/java/org/apache/juneau/rest/testutils/TestUtils.java
 
b/juneau-rest/juneau-rest-server-utest/src/test/java/org/apache/juneau/rest/testutils/TestUtils.java
index 4db0efa..36a8336 100755
--- 
a/juneau-rest/juneau-rest-server-utest/src/test/java/org/apache/juneau/rest/testutils/TestUtils.java
+++ 
b/juneau-rest/juneau-rest-server-utest/src/test/java/org/apache/juneau/rest/testutils/TestUtils.java
@@ -26,8 +26,9 @@ public class TestUtils extends 
org.apache.juneau.testutils.TestUtils {
         */
        public static Swagger getSwagger(Class<?> c) {
                try {
-                       RestContext rc = 
RestContext.create(c.newInstance()).build();
-                       RestRequest req = rc.createRequest(new RestCall(rc, new 
MockServletRequest(), null));
+                       Object r = c.newInstance();
+                       RestContext rc = RestContext.create(r).build();
+                       RestRequest req = rc.createRequest(new RestCall(r, rc, 
new MockServletRequest(), null));
                        RestInfoProvider ip = rc.getInfoProvider();
                        return ip.getSwagger(req);
                } catch (Exception e) {
diff --git 
a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestCall.java
 
b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestCall.java
index 2fb2d92..79ab9c3 100644
--- 
a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestCall.java
+++ 
b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestCall.java
@@ -18,6 +18,7 @@ import java.util.*;
 
 import javax.servlet.http.*;
 
+import org.apache.juneau.cp.*;
 import org.apache.juneau.httppart.bean.*;
 import org.apache.juneau.rest.logging.*;
 import org.apache.juneau.rest.util.*;
@@ -32,6 +33,7 @@ public class RestCall {
         */
        private static final String REST_PATHVARS_ATTR = "juneau.pathVars";
 
+       private Object resource;
        private HttpServletRequest req;
        private HttpServletResponse res;
        private RestRequest rreq;
@@ -42,56 +44,73 @@ public class RestCall {
        private String pathInfoUndecoded;
        private long startTime = System.currentTimeMillis();
        private RestLogger logger;
+       private BeanFactory beanFactory;
 
        private UrlPathMatch urlPathMatch;
 
        /**
         * Constructor.
         *
+        * @param resource The REST object.
         * @param context The REST context object.
         * @param req The incoming HTTP servlet request object.
         * @param res The incoming HTTP servlet response object.
         */
-       public RestCall(RestContext context, HttpServletRequest req, 
HttpServletResponse res) {
-               context(context).request(req).response(res);
+       public RestCall(Object resource, RestContext context, 
HttpServletRequest req, HttpServletResponse res) {
+               resource(resource).context(context).request(req).response(res);
        }
 
        
//------------------------------------------------------------------------------------------------------------------
-       // Request/response objects.
+       // Fluent setters.
        
//------------------------------------------------------------------------------------------------------------------
 
        /**
         * Overrides the request object on the REST call.
         *
-        * @param req The new HTTP servlet request.
+        * @param value The new HTTP servlet request.
         * @return This object (for method chaining).
         */
-       public RestCall request(HttpServletRequest req) {
-               this.req = req;
-               this.urlPath = null;
-               this.pathInfoUndecoded = null;
+       public RestCall resource(Object value) {
+               resource = value;
+               return this;
+       }
+
+       /**
+        * Overrides the request object on the REST call.
+        *
+        * @param value The new HTTP servlet request.
+        * @return This object (for method chaining).
+        */
+       public RestCall request(HttpServletRequest value) {
+               req = value;
+               urlPath = null;
+               pathInfoUndecoded = null;
+               beanFactory.addBean(HttpServletRequest.class, value);
                return this;
        }
 
        /**
         * Overrides the response object on the REST call.
         *
-        * @param res The new HTTP servlet response.
+        * @param value The new HTTP servlet response.
         * @return This object (for method chaining).
         */
-       public RestCall response(HttpServletResponse res) {
-               this.res = res;
+       public RestCall response(HttpServletResponse value) {
+               res = value;
+               beanFactory.addBean(HttpServletResponse.class, value);
                return this;
        }
 
        /**
         * Overrides the context object on this call.
         *
-        * @param context The context that's creating this call.
+        * @param value The context that's creating this call.
         * @return This object (for method chaining).
         */
-       public RestCall context(RestContext context) {
-               this.context = context;
+       public RestCall context(RestContext value) {
+               context = value;
+               beanFactory = new BeanFactory(value.rootBeanFactory, 
value.getResource());
+               beanFactory.addBean(RestContext.class, value);
                return this;
        }
 
@@ -104,205 +123,223 @@ public class RestCall {
         * @return This object (for method chaining).
         */
        public RestCall restMethodContext(RestMethodContext value) {
-               this.rmethod = value;
+               rmethod = value;
+               beanFactory.addBean(RestMethodContext.class, value);
                return this;
        }
 
        /**
         * Set the {@link RestRequest} object on this REST call.
         *
-        * @param rreq The {@link RestRequest} object on this REST call.
+        * @param value The {@link RestRequest} object on this REST call.
         * @return This object (for method chaining).
         */
-       public RestCall restRequest(RestRequest rreq) {
-               request(rreq);
-               this.rreq = rreq;
+       public RestCall restRequest(RestRequest value) {
+               request(value);
+               rreq = value;
+               beanFactory.addBean(RestRequest.class, value);
                return this;
        }
 
        /**
         * Set the {@link RestResponse} object on this REST call.
         *
-        * @param rres The {@link RestResponse} object on this REST call.
+        * @param value The {@link RestResponse} object on this REST call.
         * @return This object (for method chaining).
         */
-       public RestCall restResponse(RestResponse rres) {
-               response(rres);
-               this.rres = rres;
-               this.rreq.setResponse(rres);
+       public RestCall restResponse(RestResponse value) {
+               response(value);
+               rres = value;
+               rreq.setResponse(value);
+               beanFactory.addBean(RestResponse.class, value);
                return this;
        }
 
        /**
-        * Returns the HTTP servlet request of this REST call.
+        * Sets the logger to use when logging this call.
         *
-        * @return the HTTP servlet request of this REST call.
+        * @param value The logger to use when logging this call.
+        * @return This object (for method chaining).
         */
-       public HttpServletRequest getRequest() {
-               return req;
+       public RestCall logger(RestLogger value) {
+               logger = value;
+               beanFactory.addBean(RestLogger.class, value);
+               return this;
        }
 
+
        /**
-        * Returns the HTTP servlet response of this REST call.
+        * Adds resolved <c><ja>@Resource</ja>(path)</c> variable values to 
this call.
         *
-        * @return the HTTP servlet response of this REST call.
+        * @param value The variables to add to this call.
+        * @return This object (for method chaining).
         */
-       public HttpServletResponse getResponse() {
-               return res;
+       @SuppressWarnings("unchecked")
+       public RestCall pathVars(Map<String,String> value) {
+               if (value != null && ! value.isEmpty()) {
+                       Map<String,String> m = 
(Map<String,String>)req.getAttribute(REST_PATHVARS_ATTR);
+                       if (m == null) {
+                               m = new TreeMap<>();
+                               req.setAttribute(REST_PATHVARS_ATTR, m);
+                       }
+                       m.putAll(value);
+               }
+               return this;
        }
 
        /**
-        * Returns the REST request of this REST call.
+        * Enables or disabled debug mode on this call.
         *
-        * @return the REST request of this REST call.
+        * @param value The debug flag value.
+        * @return This object (for method chaining).
+        * @throws IOException Occurs if request body could not be cached into 
memory.
         */
-       public RestRequest getRestRequest() {
-               return rreq;
+       public RestCall debug(boolean value) throws IOException {
+               if (value) {
+                       req = CachingHttpServletRequest.wrap(req);
+                       res = CachingHttpServletResponse.wrap(res);
+                       req.setAttribute("Debug", true);
+               } else {
+                       req.removeAttribute("Debug");
+               }
+               return this;
        }
 
        /**
-        * Returns the REST response of this REST call.
+        * Sets the HTTP status on this call.
         *
-        * @return the REST response of this REST call.
+        * @param value The status code.
+        * @return This object (for method chaining).
         */
-       public RestResponse getRestResponse() {
-               return rres;
+       public RestCall status(int value) {
+               res.setStatus(value);
+               return this;
        }
 
        /**
-        * Returns the method context of this call.
+        * Identifies that an exception occurred during this call.
         *
-        * @return The method context of this call.
+        * @param value The thrown exception.
+        * @return This object (for method chaining).
         */
-       public RestMethodContext getRestMethodContext() {
-               return rmethod;
+       public RestCall exception(Throwable value) {
+               req.setAttribute("Exception", value);
+               beanFactory.addBean(Throwable.class, value);
+               return this;
        }
 
        /**
-        * Returns the Java method of this call.
+        * Sets metadata about the response.
         *
-        * @return The java method of this call, or <jk>null</jk> if it hasn't 
been determined yet.
+        * @param value The metadata about the response.
+        * @return This object (for method chaining).
         */
-       public Method getJavaMethod() {
-               return rmethod == null ? null : rmethod.method;
+       public RestCall responseMeta(ResponseBeanMeta value) {
+               if (rres != null)
+                       rres.setResponseMeta(value);
+               return this;
        }
 
        /**
-        * Adds resolved <c><ja>@Resource</ja>(path)</c> variable values to 
this call.
+        * Sets the output object to serialize as the response of this call.
         *
-        * @param vars The variables to add to this call.
+        * @param value The response output POJO.
+        * @return This object (for method chaining).
         */
-       @SuppressWarnings("unchecked")
-       public void addPathVars(Map<String,String> vars) {
-               if (vars != null && ! vars.isEmpty()) {
-                       Map<String,String> m = 
(Map<String,String>)req.getAttribute(REST_PATHVARS_ATTR);
-                       if (m == null) {
-                               m = new TreeMap<>();
-                               req.setAttribute(REST_PATHVARS_ATTR, m);
-                       }
-                       m.putAll(vars);
-               }
+       public RestCall output(Object value) {
+               if (rres != null)
+                       rres.setOutput(value);
+               return this;
        }
 
        /**
-        * Returns resolved <c><ja>@Resource</ja>(path)</c> variable values on 
this call.
+        * Sets the URL path pattern match on this call.
         *
-        * @return Resolved <c><ja>@Resource</ja>(path)</c> variable values on 
this call.
+        * @param value The match pattern.
+        * @return This object (for method chaining).
         */
-       @SuppressWarnings("unchecked")
-       public Map<String,String> getPathVars() {
-               Map<String,String> m = 
(Map<String,String>)req.getAttribute(REST_PATHVARS_ATTR);
-               return m == null ? Collections.emptyMap() : m;
+       public RestCall urlPathMatch(UrlPathMatch value) {
+               urlPathMatch = value;
+               beanFactory.addBean(UrlPathMatch.class, value);
+               return this;
        }
 
        
//------------------------------------------------------------------------------------------------------------------
-       // Setters.
+       // Getters.
        
//------------------------------------------------------------------------------------------------------------------
 
        /**
-        * Sets the logger to use when logging this call.
+        * Returns the HTTP servlet request of this REST call.
         *
-        * @param logger The logger to use when logging this call.
-        * @return This object (for method chaining).
+        * @return the HTTP servlet request of this REST call.
         */
-       public RestCall logger(RestLogger logger) {
-               this.logger = logger;
-               return this;
+       public HttpServletRequest getRequest() {
+               return req;
        }
 
        /**
-        * Enables or disabled debug mode on this call.
+        * Returns the HTTP servlet response of this REST call.
         *
-        * @param b The debug flag value.
-        * @return This object (for method chaining).
-        * @throws IOException Occurs if request body could not be cached into 
memory.
+        * @return the HTTP servlet response of this REST call.
         */
-       public RestCall debug(boolean b) throws IOException {
-               if (b) {
-                       req = CachingHttpServletRequest.wrap(req);
-                       res = CachingHttpServletResponse.wrap(res);
-                       req.setAttribute("Debug", true);
-               } else {
-                       req.removeAttribute("Debug");
-               }
-               return this;
+       public HttpServletResponse getResponse() {
+               return res;
        }
 
        /**
-        * Sets the HTTP status on this call.
+        * Returns the REST request of this REST call.
         *
-        * @param code The status code.
-        * @return This object (for method chaining).
+        * @return the REST request of this REST call.
         */
-       public RestCall status(int code) {
-               res.setStatus(code);
-               return this;
+       public RestRequest getRestRequest() {
+               return rreq;
        }
 
        /**
-        * Identifies that an exception occurred during this call.
+        * Returns the REST response of this REST call.
         *
-        * @param e The thrown exception.
-        * @return This object (for method chaining).
+        * @return the REST response of this REST call.
         */
-       public RestCall exception(Throwable e) {
-               req.setAttribute("Exception", e);
-               return this;
+       public RestResponse getRestResponse() {
+               return rres;
        }
 
        /**
-        * Sets metadata about the response.
+        * Returns the method context of this call.
         *
-        * @param meta The metadata about the response.
-        * @return This object (for method chaining).
+        * @return The method context of this call.
         */
-       public RestCall responseMeta(ResponseBeanMeta meta) {
-               if (rres != null)
-                       rres.setResponseMeta(meta);
-               return this;
+       public RestMethodContext getRestMethodContext() {
+               return rmethod;
        }
 
        /**
-        * Sets the output object to serialize as the response of this call.
+        * Returns the bean factory of this call.
         *
-        * @param output The response output POJO.
-        * @return This object (for method chaining).
+        * @return The bean factory of this call.
         */
-       public RestCall output(Object output) {
-               if (rres != null)
-                       rres.setOutput(output);
-               return this;
+       public BeanFactory getBeanFactory() {
+               return beanFactory;
        }
 
        /**
-        * Sets the URL path pattern match on this call.
+        * Returns the Java method of this call.
         *
-        * @param urlPathMatch The match pattern.
-        * @return This object (for method chaining).
+        * @return The java method of this call, or <jk>null</jk> if it hasn't 
been determined yet.
         */
-       public RestCall urlPathMatch(UrlPathMatch urlPathMatch) {
-               this.urlPathMatch = urlPathMatch;
-               return this;
+       public Method getJavaMethod() {
+               return rmethod == null ? null : rmethod.method;
+       }
+
+       /**
+        * Returns resolved <c><ja>@Resource</ja>(path)</c> variable values on 
this call.
+        *
+        * @return Resolved <c><ja>@Resource</ja>(path)</c> variable values on 
this call.
+        */
+       @SuppressWarnings("unchecked")
+       public Map<String,String> getPathVars() {
+               Map<String,String> m = 
(Map<String,String>)req.getAttribute(REST_PATHVARS_ATTR);
+               return m == null ? Collections.emptyMap() : m;
        }
 
        /**
@@ -322,6 +359,7 @@ public class RestCall {
        public Throwable getException() {
                return (Throwable)req.getAttribute("Exception");
        }
+
        
//------------------------------------------------------------------------------------------------------------------
        // Lifecycle methods.
        
//------------------------------------------------------------------------------------------------------------------
@@ -451,4 +489,13 @@ public class RestCall {
        public RestContext getContext() {
                return context;
        }
+
+       /**
+        * Returns the REST object.
+        *
+        * @return The rest object.
+        */
+       public Object getResource() {
+               return resource;
+       }
 }
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 765d9e7..34f9280 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
@@ -19,7 +19,6 @@ import static org.apache.juneau.internal.IOUtils.*;
 import static org.apache.juneau.internal.StringUtils.*;
 import static org.apache.juneau.rest.util.RestUtils.*;
 import static org.apache.juneau.rest.HttpRuntimeException.*;
-import static org.apache.juneau.BasicIllegalArgumentException.*;
 import static org.apache.juneau.Enablement.*;
 import static java.util.Collections.*;
 import static java.util.Arrays.*;
@@ -3223,12 +3222,6 @@ public class RestContext extends BeanContext {
        private final RestMethodParam[][]
                preCallMethodParams,
                postCallMethodParams;
-       private final Class<?>[][]
-               postInitMethodParams,
-               postInitChildFirstMethodParams,
-               startCallMethodParams,
-               endCallMethodParams,
-               destroyMethodParams;
 
        private final FileFinder fileFinder;
        private final StaticFiles staticFiles;
@@ -3407,6 +3400,12 @@ public class RestContext extends BeanContext {
 
                        this.childResources = Collections.synchronizedMap(new 
LinkedHashMap<String,RestContext>());  // Not unmodifiable on purpose so that 
children can be replaced.
 
+                       this.startCallMethods = 
createStartCallMethods(r).stream().map(x->new MethodInvoker(x, 
getMethodExecStats(x))).toArray(MethodInvoker[]::new);
+                       this.endCallMethods = 
createEndCallMethods(r).stream().map(x->new MethodInvoker(x, 
getMethodExecStats(x))).toArray(MethodInvoker[]::new);
+                       this.postInitMethods = 
createPostInitMethods(r).stream().map(x->new MethodInvoker(x, 
getMethodExecStats(x))).toArray(MethodInvoker[]::new);
+                       this.postInitChildFirstMethods = 
createPostInitChildFirstMethods(r).stream().map(x->new MethodInvoker(x, 
getMethodExecStats(x))).toArray(MethodInvoker[]::new);
+                       this.destroyMethods = 
createDestroyMethods(r).stream().map(x->new MethodInvoker(x, 
getMethodExecStats(x))).toArray(MethodInvoker[]::new);
+
                        
//----------------------------------------------------------------------------------------------------
                        // Initialize the child resources.
                        // Done after initializing fields above since we pass 
this object to the child resources.
@@ -3414,22 +3413,11 @@ public class RestContext extends BeanContext {
                        List<String> methodsFound = new LinkedList<>();   // 
Temporary to help debug transient duplicate method issue.
                        MethodMapBuilder methodMapBuilder = new 
MethodMapBuilder();
                        AMap<String,Method>
-                               _startCallMethods = AMap.of(),
                                _preCallMethods = AMap.of(),
-                               _postCallMethods = AMap.of(),
-                               _endCallMethods = AMap.of(),
-                               _postInitMethods = AMap.of(),
-                               _postInitChildFirstMethods = AMap.of(),
-                               _destroyMethods = AMap.of();
+                               _postCallMethods = AMap.of();
                        AList<RestMethodParam[]>
                                _preCallMethodParams = AList.of(),
                                _postCallMethodParams = AList.of();
-                       AList<Class<?>[]>
-                               _startCallMethodParams = AList.of(),
-                               _endCallMethodParams = AList.of(),
-                               _postInitMethodParams = AList.of(),
-                               _postInitChildFirstMethodParams = AList.of(),
-                               _destroyMethodParams = AList.of();
 
                        for (MethodInfo mi : rci.getPublicMethods()) {
                                RestMethod a = 
mi.getLastAnnotation(RestMethod.class);
@@ -3542,51 +3530,6 @@ public class RestContext extends BeanContext {
                                                        }
                                                        break;
                                                }
-                                               case START_CALL: {
-                                                       if (! 
_startCallMethods.containsKey(sig)) {
-                                                               
m.setAccessible();
-                                                               
_startCallMethods.put(sig, m.inner());
-                                                               
_startCallMethodParams.add((Class<?>[])m.getRawParamTypes().toArray());
-                                                               
assertArgsOnlyOfType(m, HttpServletRequest.class, HttpServletResponse.class);
-                                                       }
-                                                       break;
-                                               }
-                                               case END_CALL: {
-                                                       if (! 
_endCallMethods.containsKey(sig)) {
-                                                               
m.setAccessible();
-                                                               
_endCallMethods.put(sig, m.inner());
-                                                               
_endCallMethodParams.add((Class<?>[])m.getRawParamTypes().toArray());
-                                                               
assertArgsOnlyOfType(m, HttpServletRequest.class, HttpServletResponse.class);
-                                                       }
-                                                       break;
-                                               }
-                                               case POST_INIT: {
-                                                       if (! 
_postInitMethods.containsKey(sig)) {
-                                                               
m.setAccessible();
-                                                               
_postInitMethods.put(sig, m.inner());
-                                                               
_postInitMethodParams.add((Class<?>[])m.getRawParamTypes().toArray());
-                                                               
assertArgsOnlyOfType(m, RestContext.class);
-                                                       }
-                                                       break;
-                                               }
-                                               case POST_INIT_CHILD_FIRST: {
-                                                       if (! 
_postInitChildFirstMethods.containsKey(sig)) {
-                                                               
m.setAccessible();
-                                                               
_postInitChildFirstMethods.put(sig, m.inner());
-                                                               
_postInitChildFirstMethodParams.add((Class<?>[])m.getRawParamTypes().toArray());
-                                                               
assertArgsOnlyOfType(m, RestContext.class);
-                                                       }
-                                                       break;
-                                               }
-                                               case DESTROY: {
-                                                       if (! 
_destroyMethods.containsKey(sig)) {
-                                                               
m.setAccessible();
-                                                               
_destroyMethods.put(sig, m.inner());
-                                                               
_destroyMethodParams.add((Class<?>[])m.getRawParamTypes().toArray());
-                                                               
assertArgsOnlyOfType(m, RestContext.class);
-                                                       }
-                                                       break;
-                                               }
                                                default: // Ignore INIT
                                        }
                                }
@@ -3594,18 +3537,8 @@ public class RestContext extends BeanContext {
 
                        this.preCallMethods = 
_preCallMethods.values().stream().map(x->new MethodInvoker(x, 
getMethodExecStats(x))).collect(Collectors.toList()).toArray(new 
MethodInvoker[_preCallMethods.size()]);
                        this.postCallMethods = 
_postCallMethods.values().stream().map(x->new MethodInvoker(x, 
getMethodExecStats(x))).collect(Collectors.toList()).toArray(new 
MethodInvoker[_postCallMethods.size()]);
-                       this.startCallMethods = 
_startCallMethods.values().stream().map(x->new MethodInvoker(x, 
getMethodExecStats(x))).collect(Collectors.toList()).toArray(new 
MethodInvoker[_startCallMethods.size()]);
-                       this.endCallMethods = 
_endCallMethods.values().stream().map(x->new MethodInvoker(x, 
getMethodExecStats(x))).collect(Collectors.toList()).toArray(new 
MethodInvoker[_endCallMethods.size()]);
-                       this.postInitMethods = 
_postInitMethods.values().stream().map(x->new MethodInvoker(x, 
getMethodExecStats(x))).collect(Collectors.toList()).toArray(new 
MethodInvoker[_postInitMethods.size()]);
-                       this.postInitChildFirstMethods = 
_postInitChildFirstMethods.values().stream().map(x->new MethodInvoker(x, 
getMethodExecStats(x))).collect(Collectors.toList()).toArray(new 
MethodInvoker[_postInitChildFirstMethods.size()]);
-                       this.destroyMethods = 
_destroyMethods.values().stream().map(x->new MethodInvoker(x, 
getMethodExecStats(x))).collect(Collectors.toList()).toArray(new 
MethodInvoker[_destroyMethods.size()]);
                        this.preCallMethodParams = 
_preCallMethodParams.toArray(new 
RestMethodParam[_preCallMethodParams.size()][]);
                        this.postCallMethodParams = 
_postCallMethodParams.toArray(new 
RestMethodParam[_postCallMethodParams.size()][]);
-                       this.startCallMethodParams = 
_startCallMethodParams.toArray(new Class[_startCallMethodParams.size()][]);
-                       this.endCallMethodParams = 
_endCallMethodParams.toArray(new Class[_endCallMethodParams.size()][]);
-                       this.postInitMethodParams = 
_postInitMethodParams.toArray(new Class[_postInitMethodParams.size()][]);
-                       this.postInitChildFirstMethodParams = 
_postInitChildFirstMethodParams.toArray(new 
Class[_postInitChildFirstMethodParams.size()][]);
-                       this.destroyMethodParams = 
_destroyMethodParams.toArray(new Class[_destroyMethodParams.size()][]);
 
                        this.methodMap = methodMapBuilder.getMap();
                        this.methods = methodMapBuilder.getList();
@@ -4624,6 +4557,91 @@ public class RestContext extends BeanContext {
        }
 
        /**
+        * Instantiates the list of {@link HookEvent#START_CALL} methods.
+        *
+        * @param resource The REST resource object.
+        * @return The default response headers for this REST object.
+        */
+       protected List<Method> createStartCallMethods(Object resource) {
+               Map<String,Method> x = AMap.of();
+
+               for (MethodInfo m : 
ClassInfo.ofProxy(resource).getAllMethodsParentFirst())
+                       for (RestHook h : m.getAnnotations(RestHook.class))
+                               if (h.value() == HookEvent.START_CALL)
+                                       x.put(m.getSignature(), 
m.accessible().inner());
+
+               return AList.of(x.values());
+       }
+
+       /**
+        * Instantiates the list of {@link HookEvent#END_CALL} methods.
+        *
+        * @param resource The REST resource object.
+        * @return The default response headers for this REST object.
+        */
+       protected List<Method> createEndCallMethods(Object resource) {
+               Map<String,Method> x = AMap.of();
+
+               for (MethodInfo m : 
ClassInfo.ofProxy(resource).getAllMethodsParentFirst())
+                       for (RestHook h : m.getAnnotations(RestHook.class))
+                               if (h.value() == HookEvent.END_CALL)
+                                       x.put(m.getSignature(), 
m.accessible().inner());
+
+               return AList.of(x.values());
+       }
+
+       /**
+        * Instantiates the list of {@link HookEvent#POST_INIT} methods.
+        *
+        * @param resource The REST resource object.
+        * @return The default response headers for this REST object.
+        */
+       protected List<Method> createPostInitMethods(Object resource) {
+               Map<String,Method> x = AMap.of();
+
+               for (MethodInfo m : 
ClassInfo.ofProxy(resource).getAllMethodsParentFirst())
+                       for (RestHook h : m.getAnnotations(RestHook.class))
+                               if (h.value() == HookEvent.POST_INIT)
+                                       x.put(m.getSignature(), 
m.accessible().inner());
+
+               return AList.of(x.values());
+       }
+
+       /**
+        * Instantiates the list of {@link HookEvent#POST_INIT_CHILD_FIRST} 
methods.
+        *
+        * @param resource The REST resource object.
+        * @return The default response headers for this REST object.
+        */
+       protected List<Method> createPostInitChildFirstMethods(Object resource) 
{
+               Map<String,Method> x = AMap.of();
+
+               for (MethodInfo m : 
ClassInfo.ofProxy(resource).getAllMethodsParentFirst())
+                       for (RestHook h : m.getAnnotations(RestHook.class))
+                               if (h.value() == 
HookEvent.POST_INIT_CHILD_FIRST)
+                                       x.put(m.getSignature(), 
m.accessible().inner());
+
+               return AList.of(x.values());
+       }
+
+       /**
+        * Instantiates the list of {@link HookEvent#DESTROY} methods.
+        *
+        * @param resource The REST resource object.
+        * @return The default response headers for this REST object.
+        */
+       protected List<Method> createDestroyMethods(Object resource) {
+               Map<String,Method> x = AMap.of();
+
+               for (MethodInfo m : 
ClassInfo.ofProxy(resource).getAllMethodsParentFirst())
+                       for (RestHook h : m.getAnnotations(RestHook.class))
+                               if (h.value() == HookEvent.DESTROY)
+                                       x.put(m.getSignature(), 
m.accessible().inner());
+
+               return AList.of(x.values());
+       }
+
+       /**
         * Returns the bean factory associated with this context.
         *
         * <p>
@@ -5310,14 +5328,15 @@ public class RestContext extends BeanContext {
         * Wraps an incoming servlet request/response pair into a single {@link 
RestCall} object.
         *
         * <p>
-        * This is the first method called by {@link 
#execute(HttpServletRequest, HttpServletResponse)}.
+        * This is the first method called by {@link #execute(Object, 
HttpServletRequest, HttpServletResponse)}.
         *
+        * @param resource The REST object.
         * @param req The rest request.
         * @param res The rest response.
         * @return The wrapped request/response pair.
         */
-       protected RestCall createCall(HttpServletRequest req, 
HttpServletResponse res) {
-               return new RestCall(this, req, res).logger(getCallLogger());
+       protected RestCall createCall(Object resource, HttpServletRequest req, 
HttpServletResponse res) {
+               return new RestCall(resource, this, req, 
res).logger(getCallLogger());
        }
 
        /**
@@ -5352,14 +5371,15 @@ public class RestContext extends BeanContext {
         * <p>
         * Subclasses can optionally override this method if they want to 
tailor the behavior of requests.
         *
+        * @param resource The REST object.
         * @param r1 The incoming HTTP servlet request object.
         * @param r2 The incoming HTTP servlet response object.
         * @throws ServletException General servlet exception.
         * @throws IOException Thrown by underlying stream.
         */
-       public void execute(HttpServletRequest r1, HttpServletResponse r2) 
throws ServletException, IOException {
+       public void execute(Object resource, HttpServletRequest r1, 
HttpServletResponse r2) throws ServletException, IOException {
 
-               RestCall call = createCall(r1, r2);
+               RestCall call = createCall(resource, r1, r2);
 
                // Must be careful not to bleed thread-locals.
                if (this.call.get() != null)
@@ -5381,7 +5401,7 @@ public class RestContext extends BeanContext {
                                UrlPath upi2 = UrlPath.of(pi == null ? sp : sp 
+ pi);
                                UrlPathMatch uppm = pathMatcher.match(upi2);
                                if (uppm != null && ! uppm.hasEmptyVars()) {
-                                       call.addPathVars(uppm.getVars());
+                                       call.pathVars(uppm.getVars());
                                        call.request(
                                                new 
OverrideableHttpServletRequest(call.getRequest())
                                                        
.pathInfo(nullIfEmpty(urlDecode(uppm.getSuffix())))
@@ -5401,11 +5421,11 @@ public class RestContext extends BeanContext {
                                        UrlPathMatch uppm = 
upp.match(call.getUrlPath());
                                        if (uppm != null) {
                                                if (! uppm.hasEmptyVars()) {
-                                                       
call.addPathVars(uppm.getVars());
+                                                       
call.pathVars(uppm.getVars());
                                                        HttpServletRequest 
childRequest = new OverrideableHttpServletRequest(call.getRequest())
                                                                
.pathInfo(nullIfEmpty(urlDecode(uppm.getSuffix())))
                                                                
.servletPath(call.getServletPath() + uppm.getPrefix());
-                                                       
rc.execute(childRequest, call.getResponse());
+                                                       
rc.execute(rc.getResource(), childRequest, call.getResponse());  // TODO - 
resource needs to be dynamically retrieved.
                                                } else {
                                                        
call.debug(isDebug(call)).status(SC_NOT_FOUND).finish();
                                                }
@@ -5693,10 +5713,19 @@ public class RestContext extends BeanContext {
         * Called at the start of a request to invoke all {@link 
HookEvent#START_CALL} methods.
         *
         * @param call The current request.
+        * @throws HttpException If thrown from call methods.
         */
-       protected void startCall(RestCall call) {
-               for (int i = 0; i < startCallMethods.length; i++)
-                       startOrFinish(getResource(), startCallMethods[i], 
startCallMethodParams[i], call.getRequest(), call.getResponse());
+       protected void startCall(RestCall call) throws HttpException {
+               for (MethodInvoker x : startCallMethods) {
+                       try {
+                               x.invokeUsingFactory(call.getBeanFactory(), 
call.getContext().getResource());
+                       } catch (ExecutableException e) {
+                               Throwable t = e.unwrap();
+                               if (! (t instanceof HttpException))
+                                       t = new InternalServerError(e);
+                               throw (HttpException)t;
+                       }
+               }
        }
 
        /**
@@ -5743,28 +5772,16 @@ public class RestContext extends BeanContext {
         * Called at the end of a request to invoke all {@link 
HookEvent#END_CALL} methods.
         *
         * <p>
-        * This is the very last method called in {@link 
#execute(HttpServletRequest, HttpServletResponse)}.
+        * This is the very last method called in {@link #execute(Object, 
HttpServletRequest, HttpServletResponse)}.
         *
         * @param call The current request.
         */
        protected void finishCall(RestCall call) {
-               for (int i = 0; i < endCallMethods.length; i++)
-                       startOrFinish(getResource(), endCallMethods[i], 
endCallMethodParams[i], call.getRequest(), call.getResponse());
-       }
-
-       private static void startOrFinish(Object resource, MethodInvoker m, 
Class<?>[] p, HttpServletRequest req, HttpServletResponse res) throws 
HttpException, InternalServerError {
-               if (m != null) {
-                       Object[] args = new Object[p.length];
-                       for (int i = 0; i < p.length; i++) {
-                               if (p[i] == HttpServletRequest.class)
-                                       args[i] = req;
-                               else if (p[i] == HttpServletResponse.class)
-                                       args[i] = res;
-                       }
+               for (MethodInvoker x : endCallMethods) {
                        try {
-                               m.invoke(resource, args);
-                       } catch (Exception e) {
-                               throw toHttpException(e, 
InternalServerError.class);
+                               x.invokeUsingFactory(call.getBeanFactory(), 
call.getResource());
+                       } catch (ExecutableException e) {
+                               logger.log(Level.WARNING, e.unwrap(), 
()->format("Error occurred invoking finish-call method ''{0}''.", x.getName()));
                        }
                }
        }
@@ -5784,11 +5801,16 @@ public class RestContext extends BeanContext {
                        try {
                                mi.accessible().invoke(resource, this);
                        } catch (ExecutableException e) {
-                               throw new ServletException(e);
+                               throw new ServletException(e.unwrap());
+                       }
+               }
+               for (MethodInvoker x : postInitMethods) {
+                       try {
+                               x.invokeUsingFactory(beanFactory, 
getResource());
+                       } catch (ExecutableException e) {
+                               throw new ServletException(e.unwrap());
                        }
                }
-               for (int i = 0; i < postInitMethods.length; i++)
-                       postInitOrDestroy(getResource(), postInitMethods[i], 
postInitMethodParams[i]);
                for (RestContext childContext : this.childResources.values())
                        childContext.postInit();
                return this;
@@ -5805,42 +5827,26 @@ public class RestContext extends BeanContext {
                        return this;
                for (RestContext childContext : this.childResources.values())
                        childContext.postInitChildFirst();
-               for (int i = 0; i < postInitChildFirstMethods.length; i++)
-                       postInitOrDestroy(getResource(), 
postInitChildFirstMethods[i], postInitChildFirstMethodParams[i]);
-               initialized.set(true);
-               return this;
-       }
-
-       private void postInitOrDestroy(Object r, MethodInvoker m, Class<?>[] p) 
{
-               if (m != null) {
-                       Object[] args = new Object[p.length];
-                       for (int i = 0; i < p.length; i++) {
-                               if (p[i] == RestContext.class)
-                                       args[i] = this;
-                               else if (p[i] == RestContextBuilder.class)
-                                       args[i] = this.builder;
-                               else if (p[i] == ServletConfig.class)
-                                       args[i] = this.builder.inner;
-                       }
+               for (MethodInvoker x : postInitChildFirstMethods) {
                        try {
-                               m.invoke(r, args);
-                       } catch (Exception e) {
-                               if (e instanceof RuntimeException && 
ClassInfo.of(e).hasAnnotation(Response.class))
-                                       throw (RuntimeException)e;
-                               throw new InternalServerError(e);
+                               x.invokeUsingFactory(beanFactory, 
getResource());
+                       } catch (ExecutableException e) {
+                               throw new ServletException(e.unwrap());
                        }
                }
+               initialized.set(true);
+               return this;
        }
 
        /**
         * Called during servlet initialization to invoke all {@link 
HookEvent#DESTROY} methods.
         */
        protected void destroy() {
-               for (int i = 0; i < destroyMethods.length; i++) {
+               for (MethodInvoker x : destroyMethods) {
                        try {
-                               postInitOrDestroy(getResource(), 
destroyMethods[i], destroyMethodParams[i]);
-                       } catch (Exception e) {
-                               e.printStackTrace();
+                               x.invokeUsingFactory(beanFactory, 
getResource());
+                       } catch (ExecutableException e) {
+                               getLogger().log(Level.WARNING, e.unwrap(), 
()->format("Error occurred invoking servlet-destroy method ''{0}''.", 
x.getName()));
                        }
                }
 
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 f40fa4f..331630c 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
@@ -23,7 +23,6 @@ import static org.apache.juneau.rest.util.RestUtils.*;
 import static org.apache.juneau.rest.HttpRuntimeException.*;
 
 import java.lang.annotation.*;
-import java.lang.reflect.*;
 import java.lang.reflect.Method;
 import java.util.*;
 import java.util.concurrent.*;
@@ -1712,8 +1711,8 @@ public class RestMethodContext extends BeanContext 
implements Comparable<RestMet
                                        if (output != null || ! 
res.getOutputStreamCalled())
                                                res.setOutput(output);
                                }
-                       } catch (InvocationTargetException e) {
-                               Throwable e2 = e.getTargetException();          
// Get the throwable thrown from the doX() method.
+                       } catch (ExecutableException e) {
+                               Throwable e2 = e.unwrap();              // Get 
the throwable thrown from the doX() method.
                                res.setStatus(500);
                                ResponsePartMeta rpm = getResponseBodyMeta(e2);
                                ResponseBeanMeta rbm = getResponseBeanMeta(e2);
@@ -1736,8 +1735,8 @@ public class RestMethodContext extends BeanContext 
implements Comparable<RestMet
                                "Invalid argument type passed to the following 
method: ''{0}''.\n\tArgument types: {1}",
                                mi.toString(), mi.getFullName()
                        );
-               } catch (InvocationTargetException e) {
-                       throw e.getTargetException();
+               } catch (ExecutableException e) {
+                       throw e.unwrap();
                }
        }
 
diff --git 
a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestServlet.java
 
b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestServlet.java
index f9bec8e..05187e2 100644
--- 
a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestServlet.java
+++ 
b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestServlet.java
@@ -129,7 +129,7 @@ public abstract class RestServlet extends HttpServlet {
                                throw initException.get();
                        if (context.get() == null)
                                throw new InternalServerError("Servlet {0} not 
initialized.  init(ServletConfig) was not called.  This can occur if you've 
overridden this method but didn't call super.init(RestConfig).", 
getClass().getName());
-                       getContext().execute(r1, r2);
+                       getContext().execute(this, r1, r2);
 
                } catch (Throwable e) {
                        r2.sendError(SC_INTERNAL_SERVER_ERROR, 
e.getLocalizedMessage());

Reply via email to