REST refactoring.
diff --git a/juneau-rest/juneau-rest-server-utest/src/test/java/org/apache/juneau/rest/annotation/RestMethodAnnotation_Test.java b/juneau-rest/juneau-rest-server-utest/src/test/java/org/apache/juneau/rest/annotation/RestMethodAnnotation_Test.java
index 5ecf817..3e46c26 100644
--- a/juneau-rest/juneau-rest-server-utest/src/test/java/org/apache/juneau/rest/annotation/RestMethodAnnotation_Test.java
+++ b/juneau-rest/juneau-rest-server-utest/src/test/java/org/apache/juneau/rest/annotation/RestMethodAnnotation_Test.java
@@ -36,6 +36,7 @@
 	RestMethod a1 = RestMethodAnnotation.create()
 		.clientVersion("clientVersion")
 		.consumes("consumes")
+		.context(RestMethodContext.class)
 		.converters(RestConverter.class)
 		.debug("debug")
 		.defaultAccept("defaultAccept")
@@ -68,6 +69,7 @@
 	RestMethod a2 = RestMethodAnnotation.create()
 		.clientVersion("clientVersion")
 		.consumes("consumes")
+		.context(RestMethodContext.class)
 		.converters(RestConverter.class)
 		.debug("debug")
 		.defaultAccept("defaultAccept")
@@ -103,6 +105,7 @@
 			+ "{"
 				+ "clientVersion:'clientVersion',"
 				+ "consumes:['consumes'],"
+				+ "context:'org.apache.juneau.rest.RestMethodContext',"
 				+ "converters:['org.apache.juneau.rest.RestConverter'],"
 				+ "debug:'debug',"
 				+ "defaultAccept:'defaultAccept',"
@@ -178,6 +181,7 @@
 	@RestMethod(
 		clientVersion="clientVersion",
 		consumes="consumes",
+		context=RestMethodContext.class,
 		converters=RestConverter.class,
 		debug="debug",
 		defaultAccept="defaultAccept",
@@ -212,6 +216,7 @@
 	@RestMethod(
 		clientVersion="clientVersion",
 		consumes="consumes",
+		context=RestMethodContext.class,
 		converters=RestConverter.class,
 		debug="debug",
 		defaultAccept="defaultAccept",
diff --git a/juneau-rest/juneau-rest-server-utest/src/test/java/org/apache/juneau/rest/annotation/Rest_Context_Test.java b/juneau-rest/juneau-rest-server-utest/src/test/java/org/apache/juneau/rest/annotation/Rest_Context_Test.java
index e09b6ce..cba61b1 100644
--- a/juneau-rest/juneau-rest-server-utest/src/test/java/org/apache/juneau/rest/annotation/Rest_Context_Test.java
+++ b/juneau-rest/juneau-rest-server-utest/src/test/java/org/apache/juneau/rest/annotation/Rest_Context_Test.java
@@ -91,7 +91,7 @@
 
 	@Test
 	public void a05_invalidConstructor() throws Exception {
-		assertThrown(()->client(A5.class)).contains("Invalid class specified for REST_context");
+		assertThrown(()->client(A5.class)).contains("Could not create instance");
 	}
 
 	//------------------------------------------------------------------------------------------------------------------
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 4863d25..5c3212a 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
@@ -4575,7 +4575,7 @@
 					if (mi.isNotPublic())

 						throw new RestServletException("@RestMethod method {0}.{1} must be defined as public.", rci.inner().getName(), mi.getSimpleName());

 

-					RestMethodContextBuilder rmcb = new RestMethodContextBuilder(resource, mi.inner(), this);

+					RestMethodContextBuilder rmcb = new RestMethodContextBuilder(mi.inner(), this);

 					RestMethodContext rmc = rmcb.build();

 					String httpMethod = rmc.getHttpMethod();

 

@@ -4584,11 +4584,13 @@
 					// We override the CallMethod.invoke() method to insert our logic.

 					if ("RRPC".equals(httpMethod)) {

 

-						RestMethodContextBuilder smb = new RestMethodContextBuilder(resource, mi.inner(), this);

-						smb.dotAll();

+						RestMethodContext smb = new RestMethodContextBuilder(mi.inner(), this)

+							.dotAll()

+							.context(RrpcRestMethodContext.class)

+							.build();

 						x

-							.add("GET", smb.build(RrpcRestMethodContext.class))

-							.add("POST", smb.build(RrpcRestMethodContext.class));

+							.add("GET", smb)

+							.add("POST", smb);

 

 					} else {

 						x.add(rmc);

diff --git a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestContextBuilder.java b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestContextBuilder.java
index 9079e9d..5b60ff0 100644
--- a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestContextBuilder.java
+++ b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestContextBuilder.java
@@ -185,10 +185,9 @@
 		try {
 			PropertyStore ps = getPropertyStore();
 			Class<? extends RestContext> c = ps.getClassProperty(REST_context, RestContext.class, RestContext.class);
-			ConstructorInfo ci = ClassInfo.of(c).getConstructor(Visibility.PUBLIC, RestContextBuilder.class);
-			if (ci == null)
-				throw new InternalServerError("Invalid class specified for REST_context.  Must extend from RestContext and provide a public constructor of the form T(RestContextBuilder).");
-			return ci.invoke(this);
+			BeanFactory bf = new BeanFactory(beanFactory, resource);
+			bf.addBean(RestContextBuilder.class, this);
+			return bf.createBean(c);
 		} catch (Exception e) {
 			throw toHttpException(e, InternalServerError.class);
 		}
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 0a68e4d..1f1d218 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
@@ -65,6 +65,14 @@
 @ConfigurableContext(nocache=true)
 public class RestMethodContext extends BeanContext implements Comparable<RestMethodContext>  {
 
+	/** Represents a null value for the {@link RestMethod#context()} annotation.*/
+	@SuppressWarnings("javadoc")
+	public static final class Null extends RestMethodContext {
+		public Null(RestMethodContextBuilder builder) throws Exception {
+			super(builder);
+		}
+	}
+
 	//-------------------------------------------------------------------------------------------------------------------
 	// Configurable properties
 	//-------------------------------------------------------------------------------------------------------------------
@@ -157,6 +165,37 @@
 	public static final String RESTMETHOD_clientVersion = PREFIX + ".clientVersion.s";
 
 	/**
+	 * Configuration property:  REST method context class.
+	 *
+	 * <ul class='spaced-list'>
+	 * 	<li><b>ID:</b>  {@link org.apache.juneau.rest.RestMethodContext#RESTMETHOD_context RESTMETHOD_context}
+	 * 	<li><b>Name:</b>  <js>"RestMethodContext.context.c"</js>
+	 * 	<li><b>Data type:</b>  <c>Class&lt;? extends {@link org.apache.juneau.rest.RestMethodContext}&gt;</c>
+	 * 	<li><b>Default:</b>  {@link org.apache.juneau.rest.RestMethodContext}
+	 * 	<li><b>Session property:</b>  <jk>false</jk>
+	 * 	<li><b>Annotations:</b>
+	 * 		<ul>
+	 * 			<li class='ja'>{@link org.apache.juneau.rest.annotation.RestMethod#context()}
+	 * 		</ul>
+	 * 	<li><b>Methods:</b>
+	 * 		<ul>
+	 * 			<li class='jm'>{@link org.apache.juneau.rest.RestMethodContextBuilder#context(Class)}
+	 * 		</ul>
+	 * </ul>
+	 *
+	 * <h5 class='section'>Description:</h5>
+	 * <p>
+	 * Allows you to extend the {@link RestMethodContext} class to modify how any of the functions are implemented.
+	 *
+	 * <p>
+	 * The subclass must provide the following:
+	 * <ul>
+	 * 	<li>A public constructor that takes in one parameter that should be passed to the super constructor:  {@link RestMethodContextBuilder}.
+	 * </ul>
+	 */
+	public static final String RESTMETHOD_context = PREFIX + ".context.c";
+
+	/**
 	 * Configuration property:  Debug mode.
 	 *
 	 * <h5 class='section'>Property:</h5>
@@ -638,16 +677,17 @@
 	/**
 	 * Context constructor.
 	 *
-	 * @param ps The property store with settings.
+	 * @param builder The builder for this object.
 	 * @throws ServletException If context could not be created.
 	 */
-	public RestMethodContext(PropertyStore ps) throws ServletException {
-		super(ps);
+	public RestMethodContext(RestMethodContextBuilder builder) throws ServletException {
+		super(builder.getPropertyStore());
 
 		try {
-			context = getInstanceProperty("RestMethodContext.restContext.o", RestContext.class);
-			method = getInstanceProperty("RestMethodContext.restMethod.o", Method.class);
-			boolean dotAll = getBooleanProperty("RestMethodContext.dotAll.b", false);
+			context = builder.restContext;
+			method = builder.restMethod;
+
+			PropertyStore ps = getPropertyStore();
 
 			methodInvoker = new MethodInvoker(method, context.getMethodExecStats(method));
 			mi = MethodInfo.of(method).accessible();
@@ -681,7 +721,7 @@
  			requiredMatchers = matchers.stream().filter(x -> x.required()).toArray(RestMatcher[]::new);
 			optionalMatchers = matchers.stream().filter(x -> ! x.required()).toArray(RestMatcher[]::new);
 
-			pathMatchers = createPathMatchers(r, beanFactory, dotAll).asArray();
+			pathMatchers = createPathMatchers(r, beanFactory).asArray();
 			beanFactory.addBean(UrlPathMatcher[].class, pathMatchers);
 			beanFactory.addBean(UrlPathMatcher.class, pathMatchers.length > 0 ? pathMatchers[0] : null);
 
@@ -1223,14 +1263,14 @@
 	 *
 	 * @param resource The REST resource object.
 	 * @param beanFactory The bean factory to use for retrieving and creating beans.
-	 * @param dotAll If {@link RestMethodContextBuilder#dotAll()} was specified.
 	 * @return The HTTP part parser for this REST resource.
 	 * @throws Exception If parser could not be instantiated.
 	 * @seealso #RESTMETHOD_paths
 	 */
-	protected UrlPathMatcherList createPathMatchers(Object resource, BeanFactory beanFactory, boolean dotAll) throws Exception {
+	protected UrlPathMatcherList createPathMatchers(Object resource, BeanFactory beanFactory) throws Exception {
 
 		UrlPathMatcherList x = UrlPathMatcherList.create();
+		boolean dotAll = getBooleanProperty("RestMethodContext.dotAll.b", false);
 
 		for (String p : getArrayProperty(RESTMETHOD_path, String.class)) {
 			if (dotAll && ! p.endsWith("/*"))
diff --git a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestMethodContextBuilder.java b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestMethodContextBuilder.java
index bd3dbda..02824cd 100644
--- a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestMethodContextBuilder.java
+++ b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestMethodContextBuilder.java
@@ -13,17 +13,18 @@
 package org.apache.juneau.rest;
 
 import static java.util.Arrays.*;
+import static org.apache.juneau.rest.HttpRuntimeException.*;
 import static org.apache.juneau.rest.RestMethodContext.*;
 
 import java.lang.annotation.*;
 import java.util.*;
 import java.util.function.*;
 
-import javax.servlet.*;
-
 import org.apache.http.*;
 import org.apache.juneau.*;
+import org.apache.juneau.cp.*;
 import org.apache.juneau.http.*;
+import org.apache.juneau.http.exception.*;
 import org.apache.juneau.internal.*;
 import org.apache.juneau.reflect.*;
 import org.apache.juneau.rest.annotation.*;
@@ -35,22 +36,29 @@
  */
 public class RestMethodContextBuilder extends BeanContextBuilder {
 
-	@Override
+	RestContext restContext;
+	Method restMethod;
+
+	@Override /* BeanContextBuilder */
 	public RestMethodContext build() {
 		try {
-			return new RestMethodContext(getPropertyStore());
-		} catch (ServletException e) {
-			throw new RuntimeException(e);
+			PropertyStore ps = getPropertyStore();
+			Class<? extends RestMethodContext> c = ps.getClassProperty(RESTMETHOD_context, RestMethodContext.class, RestMethodContext.class);
+			BeanFactory bf = new BeanFactory(restContext.rootBeanFactory, restContext.getResource());
+			bf.addBean(RestMethodContextBuilder.class, this);
+			return bf.createBean(c);
+		} catch (Exception e) {
+			throw toHttpException(e, InternalServerError.class);
 		}
 	}
 
-	RestMethodContextBuilder(Object servlet, java.lang.reflect.Method method, RestContext context) throws RestServletException {
-		set("RestMethodContext.restContext.o", context);
-		set("RestMethodContext.restMethod.o", method);
-		set("RestMethodContext.restObject.o", context.getResource());  // Added to force a new cache hash.
+	RestMethodContextBuilder(java.lang.reflect.Method method, RestContext context) throws RestServletException {
+
+		this.restContext = context;
+		this.restMethod = method;
 
 		String sig = method.getDeclaringClass().getName() + '.' + method.getName();
-		MethodInfo mi = MethodInfo.of(servlet.getClass(), method);
+		MethodInfo mi = MethodInfo.of(context.getResource().getClass(), method);
 
 		try {
 
@@ -113,6 +121,25 @@
 	}
 
 	/**
+	 * <i><l>RestMethodContext</l> configuration property:&emsp;</i>  REST method context class.
+	 *
+	 * Allows you to extend the {@link RestMethodContext} class to modify how any of the methods are implemented.
+	 *
+	 * <p>
+	 * The subclass must provide the following:
+	 * <ul>
+	 * 	<li>A public constructor that takes in one parameter that should be passed to the super constructor:  {@link RestMethodContextBuilder}.
+	 * </ul>
+	 *
+	 * @param value The new value for this setting.
+	 * @return This object (for method chaining).
+	 */
+	@FluentSetter
+	public RestMethodContextBuilder context(Class<? extends RestMethodContext> value) {
+		return set(RESTMETHOD_context, value);
+	}
+
+	/**
 	 * <i><l>RestMethodContext</l> configuration property:&emsp;</i>  Debug mode.
 	 *
 	 * <p>
diff --git a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RrpcRestMethodContext.java b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RrpcRestMethodContext.java
index accaafe..8d0c591 100644
--- a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RrpcRestMethodContext.java
+++ b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RrpcRestMethodContext.java
@@ -35,11 +35,11 @@
 	/**
 	 * Constructor.
 	 *
-	 * @param ps The property store containing the settings for this context.
+	 * @param builder The builder for this method context.
 	 * @throws ServletException Problem with metadata was detected.
 	 */
-	public RrpcRestMethodContext(PropertyStore ps) throws ServletException {
-		super(ps);
+	public RrpcRestMethodContext(RestMethodContextBuilder builder) throws ServletException {
+		super(builder);
 
 		ClassMeta<?> interfaceClass = getClassMeta(mi.inner().getGenericReturnType());
 		meta = new RrpcInterfaceMeta(interfaceClass.getInnerClass(), null);
diff --git a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/annotation/RestMethod.java b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/annotation/RestMethod.java
index b88cccb..7f0ed4a 100644
--- a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/annotation/RestMethod.java
+++ b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/annotation/RestMethod.java
@@ -117,6 +117,21 @@
 	String[] consumes() default {};

 

 	/**

+	 * Allows you to extend the {@link RestContext} class to modify how any of the methods are implemented.

+	 *

+	 * <p>

+	 * The subclass must provide the following:

+	 * <ul>

+	 * 	<li>A public constructor that takes in one parameter that should be passed to the super constructor:  {@link RestMethodContextBuilder}.

+	 * </ul>

+	 *

+	 * <ul class='seealso'>

+	 * 	<li class='jm'>{@link RestMethodContextBuilder#context(Class)}

+	 * </ul>

+	 */

+	Class<? extends RestMethodContext> context() default RestMethodContext.Null.class;

+

+	/**

 	 * Class-level response converters.

 	 *

 	 * <p>

diff --git a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/annotation/RestMethodAnnotation.java b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/annotation/RestMethodAnnotation.java
index e7f899f..db221bf 100644
--- a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/annotation/RestMethodAnnotation.java
+++ b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/annotation/RestMethodAnnotation.java
@@ -61,6 +61,7 @@
 		Class<? extends RestConverter>[] converters = new Class[0];
 		Class<? extends RestGuard>[] guards = new Class[0];
 		Class<? extends RestMatcher>[] matchers = new Class[0];
+		Class<? extends RestMethodContext> context = RestMethodContext.Null.class;
 		Class<?>[] encoders=new Class<?>[0], parsers=new Class<?>[0], serializers=new Class<?>[0];
 		int priority = 0;
 		MethodSwagger swagger = MethodSwaggerAnnotation.DEFAULT;
@@ -106,6 +107,17 @@
 		}
 
 		/**
+		 * Sets the {@link RestMethod#context()} property on this annotation.
+		 *
+		 * @param value The new value for this property.
+		 * @return This object (for method chaining).
+		 */
+		public Builder context(Class<? extends RestMethodContext> value) {
+			this.context = value;
+			return this;
+		}
+
+		/**
 		 * Sets the {@link RestMethod#converters()} property on this annotation.
 		 *
 		 * @param value The new value for this property.
@@ -413,6 +425,7 @@
 		private final Class<? extends RestConverter>[] converters;
 		private final Class<? extends RestGuard>[] guards;
 		private final Class<? extends RestMatcher>[] matchers;
+		private final Class<? extends RestMethodContext> context;
 		private final Class<?>[] encoders, parsers, serializers;
 		private final int priority;
 		private final MethodSwagger swagger;
@@ -423,6 +436,7 @@
 			super(b);
 			this.clientVersion = b.clientVersion;
 			this.consumes = copyOf(b.consumes);
+			this.context = b.context;
 			this.converters = copyOf(b.converters);
 			this.debug = b.debug;
 			this.defaultAccept = b.defaultAccept;
@@ -463,6 +477,11 @@
 		}
 
 		@Override /* RestMethod */
+		public Class<? extends RestMethodContext> context() {
+			return context;
+		}
+
+		@Override /* RestMethod */
 		public Class<? extends RestConverter>[] converters() {
 			return converters;
 		}
@@ -615,6 +634,7 @@
 			psb.set(REST_serializers, merge(ConverterUtils.toType(psb.peek(REST_serializers), Object[].class), a.serializers()));
 			psb.set(REST_parsers, merge(ConverterUtils.toType(psb.peek(REST_parsers), Object[].class), a.parsers()));
 			psb.set(REST_encoders, merge(ConverterUtils.toType(psb.peek(REST_encoders), Object[].class), a.encoders()));
+			psb.setIf(a.context() != RestMethodContext.Null.class, RESTMETHOD_context, a.context());
 			psb.setIfNotEmpty(REST_produces, stringList(a.produces()));
 			psb.setIfNotEmpty(REST_consumes, stringList(a.consumes()));
 			stringStream(a.defaultRequestHeaders()).map(x -> BasicHeader.ofPair(x)).forEach(x -> psb.appendTo(RESTMETHOD_defaultRequestHeaders, x));