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 0cf73e8  New @Rest(context) setting.
0cf73e8 is described below

commit 0cf73e8b23212f1e90ba70bbc8a65fe50331e262
Author: JamesBognar <[email protected]>
AuthorDate: Wed Jul 29 10:58:15 2020 -0400

    New @Rest(context) setting.
---
 juneau-doc/docs/ReleaseNotes/8.1.4.html            |   3 +
 juneau-doc/src/main/javadoc/overview.html          | 113 +++++++++++++++------
 .../src/main/javadoc/resources/juneau-doc.css      |  12 ++-
 .../juneau/rest/RestContext_context_Test.java      | 104 +++++++++++++++++++
 .../java/org/apache/juneau/rest/BasicRest.java     |   4 +
 .../apache/juneau/rest/BasicRestCallHandler.java   |   2 +-
 .../java/org/apache/juneau/rest/RestContext.java   |  91 +++++++++++++----
 .../org/apache/juneau/rest/RestContextBuilder.java |  47 ++++++++-
 .../org/apache/juneau/rest/annotation/Rest.java    |  35 +++++++
 .../juneau/rest/annotation/RestConfigApply.java    |   4 +
 10 files changed, 364 insertions(+), 51 deletions(-)

diff --git a/juneau-doc/docs/ReleaseNotes/8.1.4.html 
b/juneau-doc/docs/ReleaseNotes/8.1.4.html
index d0ac1a9..7330b58 100644
--- a/juneau-doc/docs/ReleaseNotes/8.1.4.html
+++ b/juneau-doc/docs/ReleaseNotes/8.1.4.html
@@ -253,6 +253,9 @@
 <h5 class='topic w800'>juneau-rest-server</h5>
 <ul class='spaced-list'>
        <li>
+               New {@link oajr.RestContent#REST_context REST_context}/{@link 
oajr.annotation.Rest#context() @Rest(context)} setting to allow you to extend 
the {@link oajr.RestContext}
+               class.
+       <li>
                {@link oajr.annotation.Rest}-annotated classes can now 
implement the following interfaces directly instead of having
                to define secondary classes and hook them up through 
annotations:
                <ul>
diff --git a/juneau-doc/src/main/javadoc/overview.html 
b/juneau-doc/src/main/javadoc/overview.html
index a45d501..d589129 100644
--- a/juneau-doc/src/main/javadoc/overview.html
+++ b/juneau-doc/src/main/javadoc/overview.html
@@ -406,7 +406,7 @@
                <li><p><a class='doclink' 
href='#juneau-rest-server.Guards'>Guards</a></p>
                <li><p><a class='doclink' 
href='#juneau-rest-server.RoleGuards'>Role guards</a><span 
class='update'>8.1.0-new</span></p>
                <li><p><a class='doclink' 
href='#juneau-rest-server.Converters'>Converters</a></p>
-               <li><p><a class='doclink' 
href='#juneau-rest-server.Messages'>Messages</a></p>
+               <li><p><a class='doclink' 
href='#juneau-rest-server.Messages'>Messages</a><span 
class='update'><b>8.1.4-updated</b></span></p>
                <li><p><a class='doclink' 
href='#juneau-rest-server.Encoders'>Encoders</a></p>
                <li><p><a class='doclink' 
href='#juneau-rest-server.SvlVariables'>SVL Variables</a></p>
                <li><p><a class='doclink' 
href='#juneau-rest-server.ConfigurationFiles'>Configuration Files</a></p>
@@ -18731,50 +18731,97 @@
 
 <!-- 
====================================================================================================
 -->
 
-<h3 class='topic' onclick='toggle(this)'><a 
href='#juneau-rest-server.Messages' id='juneau-rest-server.Messages'>6.22 - 
Messages</a></h3>
+<h3 class='topic' onclick='toggle(this)'><a 
href='#juneau-rest-server.Messages' id='juneau-rest-server.Messages'>6.22 - 
Messages</a><span class='update'><b>8.1.4-updated</b></span></h3>
 <div class='topic'><!-- START: 6.22 - juneau-rest-server.Messages -->
 <p>
-       The {@link org.apache.juneau.rest.annotation.Rest#messages 
@Rest(messages)} annotation is used to associate a resource bundle with a 
servlet class.
+       The {@link org.apache.juneau.rest.annotation.Rest#messages 
@Rest(messages)} annotation identifies the location of the resource bundle 
+       for a <ja>@Rest</ja>-annotated class if it's different from the class 
name.
 </p>
-<p class='bpcode w800'>
-       <jc>// Servlet with associated resource bundle</jc>
-       <ja>@Rest</ja>(messages=<js>"nls/MyMessages"</js>)
-       <jk>public</jk> MyRestServlet <jk>extends</jk> BasicRestServlet {
-
-               <jc>// Returns the localized greeting from the "greeting" key 
in MyMessages.properties</jc>
-               <ja>@RestMethod</ja>(name=<jsf>GET</jsf>, path=<js>"/"</js>)
-               <jk>public</jk> String printLocalizedGreeting(RestRequest req) {
-                       <jk>return</jk> req.getMessage(<js>"greeting"</js>);
-               }
+<p>
+       By default, the resource bundle name is assumed to match the class 
name.  For example, given the class
+       <c>MyClass.java</c>, the resource bundle is assumed to be 
<c>MyClass.properties</c>.  This property
+       allows you to override this setting to specify a different location 
such as <c>MyMessages.properties</c> by
+       specifying a value of <js>"MyMessages"</js>.
 </p>
-<p>    
-       The resource bundle can also be passed into the method by simply 
specifying a parameter
-       of type {@link java.util.ResourceBundle} or {@link 
org.apache.juneau.utils.MessageBundle}:
+<p>
+Resource bundles are searched using the following base name patterns:
 </p>
-<p class='bpcode w800'>
-       <ja>@RestMethod</ja>(name=<jsf>GET</jsf>)
-       <jk>public</jk> String printLocalizedGreeting(MessageBundle messages) {
-               <jk>return</jk> messages.getString(<js>"greeting"</js>);
-       }
+<ul>
+       <li><js>"{package}.{name}"</js>
+       <li><js>"{package}.i18n.{name}"</js>
+       <li><js>"{package}.nls.{name}"</js>
+       <li><js>"{package}.messages.{name}"</js>
+</ul>
+
+<p>
+       This annotation is used to provide request-localized (based on 
<c>Accept-Language</c>) messages for the following methods:
+</p>
+<ul class='javatree'>
+       <li class='jm'>{@link RestRequest#getMessage(String, Object...)}
+       <li class='jm'>{@link RestContext#getMessages() 
RestContext.getMessages()}
+</ul>
+
+<p>
+       Request-localized messages are also available by passing either of the 
following parameter types into your Java method:
 </p>
+<ul class='javatree'>
+       <li class='jc'>{@link ResourceBundle} - Basic Java resource bundle.
+       <li class='jc'>{@link Messages} - Extended resource bundle with several 
convenience methods.
+</ul>
 <p>
-       If a resource bundle is shared by multiple servlets, the label and 
description can be prefixed by the class 
-       name:
+       The value can be a relative path like <js>"nls/Messages"</js>, 
indicating to look for the resource bundle
+       <js>"com.foo.sample.nls.Messages"</js> if the resource class is in 
<js>"com.foo.sample"</js>, or it can be an
+       absolute path like <js>"com.foo.sample.nls.Messages"</js>
 </p>
+
+<h5 class='figure'>Examples:</h5>
 <p class='bpcode w800'>
        
<cc>#--------------------------------------------------------------------------------
-       # Contents of MyMessages.properties
+       # Contents of org/apache/foo/nls/MyMessages.properties
        
#--------------------------------------------------------------------------------</cc>
-       <ck>greeting</ck> = Hello!
-</p>           
+       <ck>HelloMessage</ck> = <cv>Hello {0}!</cv>
+</p>
+<p class='bpcode w800'>
+       <jc>// Contents of org/apache/foo/MyResource.java</jc>
+
+       <ja>@Rest</ja>(messages=<js>"nls/MyMessages"</js>)
+       <jk>public class</jk> MyResource {...}
+
+               <ja>@RestMethod</ja>(name=<js>"GET"</js>, 
path=<js>"/hello/{you}"</js>)
+               <jk>public</jk> Object helloYou(RestRequest <jv>req</jv>, 
Messages <jv>messages</jv>, <ja>@Path</ja>(<js>"name"</js>) String 
<jv>you</jv>) {
+                       String <jv>s</jv>;
+
+                       <jc>// Get it from the RestRequest object.</jc>
+                       <jv>s</jv> = 
<jv>req</jv>.getMessage(<js>"HelloMessage"</js>, <jv>you</jv>);
+
+                       <jc>// Or get it from the method parameter.</jc>
+                       <jv>s</jv> = 
<jv>messages</jv>.getString(<js>"HelloMessage"</js>, <jv>you</jv>);
+
+                       <jc>// Or get the message in a locale different from 
the request.</jc>
+                       <jv>s</jv> = 
<jv>messages</jv>.forLocale(Locale.<jsf>UK</jsf>).getString(<js>"HelloMessage"</js>,
 <jv>you</jv>);
+
+                       <jk>return</jk> <jv>s</jv>;
+               }
+       }
+</p>
+<p>
+       When using shared resource bundles, keys can be prefixed by class names 
like so and still retrieve by simple
+       key names:
+</p>
 <p class='bpcode w800'>
        
<cc>#--------------------------------------------------------------------------------
-       # Contents of shared MyMessages.properties
+       # Contents of shared org/apache/foo/nls/MyMessages.properties
        
#--------------------------------------------------------------------------------</cc>
-       <ck>MyRestServlet.greeting</ck> = Hello!
+       <ck>MyResource.HelloMessage</ck> = <cv>Hello {0}!</cv>
+</p>
+
+<p>
+       Messages are automatically inherited from super classes.  If a string 
cannot be found in the bundle of the current
+       class, it will be searched for up the class hierarchy.
 </p>
 
 <ul class='seealso'>
+       <li class='jc'>{@link org.apache.juneau.cp.Messages}
        <li class='jf'>{@link org.apache.juneau.rest.RestContext#REST_messages}
 </ul>
 </div><!-- END: 6.22 - juneau-rest-server.Messages -->
@@ -30936,6 +30983,12 @@
        </tr>
        <tr>
                <td></td>
+               <td>{@link org.apache.juneau.rest.RestContext#REST_context 
REST_context}</td>
+               <td>REST context class.</td>
+               <td style='max-width:250px;overflow:hidden'><c>Class&lt;? 
extends {@link org.apache.juneau.rest.RestContext}&gt;</c></td>
+       </tr>
+       <tr>
+               <td></td>
                <td>{@link org.apache.juneau.rest.RestContext#REST_converters 
REST_converters}</td>
                <td>Class-level response converters.</td>
                <td style='max-width:250px;overflow:hidden'><c>List&lt;{@link 
org.apache.juneau.rest.RestConverter}|Class&lt;{@link 
org.apache.juneau.rest.RestConverter}&gt;&gt;</c></td>
@@ -30986,7 +31039,7 @@
                <td></td>
                <td>{@link org.apache.juneau.rest.RestContext#REST_messages 
REST_messages}</td>
                <td>Messages.</td>
-               <td style='max-width:250px;overflow:hidden'><c>List&lt;{@link 
org.apache.juneau.rest.MessageBundleLocation}&gt;</c></td>
+               <td style='max-width:250px;overflow:hidden'><c>List&lt;{@link 
org.apache.juneau.utils.Tuple2}&lt;Class,String&gt;&gt;</c></td>
        </tr>
        <tr>
                <td></td>
@@ -38836,6 +38889,8 @@
                String getFoo();  <jc>// @RestMethod(name=GET,path="/foo") is 
implied.</jc>
        }
                </p>
+       <li>
+               Improved {@link 
org.apache.juneau.rest.annotation.RestMethod#REST_messages REST_messages} 
support (mostly bug fixes).
 </ul>
 
 <h5 class='topic w800'>juneau-rest-server-springboot</h5>
diff --git a/juneau-doc/src/main/javadoc/resources/juneau-doc.css 
b/juneau-doc/src/main/javadoc/resources/juneau-doc.css
index e61a042..ec0f464 100755
--- a/juneau-doc/src/main/javadoc/resources/juneau-doc.css
+++ b/juneau-doc/src/main/javadoc/resources/juneau-doc.css
@@ -41,6 +41,7 @@
  *
  * Available tags:
  *     <l> - A literal.
+ *     <review> - Identifies code that needs review.
  
***************************************************************************************************************************/
 
 .fixedWidth {
@@ -493,7 +494,7 @@ hr {
 }
 
 div.info, div.warn, div.severe {
-       background-image: 
url('data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9Im5vIj8+CjwhLS0gQ3JlYXRlZCB3aXRoIElua3NjYXBlIChodHRwOi8vd3d3Lmlua3NjYXBlLm9yZy8pIC0tPgo8c3ZnIAoJaWQ9InN2ZzI4MTAiIAoJeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiAKCXhtbG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hsaW5rIiAKCWhlaWdodD0iMjQiIAoJd2lkdGg9IjQyIiAKCXZlcnNpb249IjEuMCIgCgl2aWV3Qm94PSIwIDAgNDgwIDQ4MCI+Cgk8ZGVmcyBpZD0iZGVmczI4MzYiPgoJCTxsaW5lYXJHcmFkaWVudCBpZD0ibGl
 [...]
+       background-image: 
url('data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9Im5vIj8+CjwhLS0gQ3JlYXRlZCB3aXRoIElua3NjYXBlIChodHRwOi8vd3d3Lmlua3NjYXBlLm9yZy8pIC0tPgo8c3ZnIAoJaWQ9InN2ZzI4MTAiIAoJeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiAKCXhtbG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hsaW5rIiAKCWhlaWdodD0iMjQiIAoJd2lkdGg9IjQyIiAKCXZlcnNpb249IjEuMCIgCgl2aWV3Qm94PSIwIDAgNDgwIDQ4MCI+Cgk8ZGVmcyBpZD0iZGVmczI4MzYiPgoJCTxsaW5lYXJHcmFkaWVudCBpZD0ibGluZW
 [...]
        background-repeat: no-repeat;
        background-position: left center;
        padding: 15px 50px;
@@ -527,3 +528,12 @@ div.severe {
 .todo {
        background-color:#FD8;
 }
+
+review {
+       background-color: #ffdf00;
+       padding: 10px;
+       border-radius: 5px;
+       width: 800px;
+       text-align: center;
+       box-shadow: 1px 1px 1px 0px rgba(0, 0, 0, 0.5);
+}
diff --git 
a/juneau-rest/juneau-rest-server-utest/src/test/java/org/apache/juneau/rest/RestContext_context_Test.java
 
b/juneau-rest/juneau-rest-server-utest/src/test/java/org/apache/juneau/rest/RestContext_context_Test.java
new file mode 100644
index 0000000..2a4c299
--- /dev/null
+++ 
b/juneau-rest/juneau-rest-server-utest/src/test/java/org/apache/juneau/rest/RestContext_context_Test.java
@@ -0,0 +1,104 @@
+// 
***************************************************************************************************************************
+// * 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.rest;
+
+import static org.apache.juneau.assertions.Assertions.*;
+import static org.junit.runners.MethodSorters.*;
+
+import org.apache.juneau.rest.annotation.*;
+import org.apache.juneau.rest.mock2.*;
+import org.junit.*;
+
+@FixMethodOrder(NAME_ASCENDING)
+public class RestContext_context_Test {
+
+       public static class MyRestContext extends RestContext {
+               public MyRestContext(RestContextBuilder builder) throws 
Exception {
+                       super(builder);
+               }
+       }
+
+       @Rest
+       public static class A1 {
+               @RestMethod
+               public String get(RestContext context) {
+                       return context.getClass().getSimpleName();
+               }
+       }
+
+       @Test
+       public void a01_default() throws Exception {
+               MockRestClient x = client(A1.class);
+               x.get().run().assertBody().is("RestContext");
+       }
+
+       @Rest(context=MyRestContext.class)
+       public static class A2 extends A1 {}
+
+       @Test
+       public void a02_custom() throws Exception {
+               MockRestClient x = client(A2.class);
+               x.get().run().assertBody().is("MyRestContext");
+       }
+
+       @Rest
+       public static class A3 extends A2 {}
+
+       @Test
+       public void a03_notOverriddenByChild() throws Exception {
+               MockRestClient x = client(A3.class);
+               x.get().run().assertBody().is("MyRestContext");
+       }
+
+       @Rest
+       public static class A4 extends A1 {
+                @RestHook(HookEvent.INIT)
+                public void init(RestContextBuilder builder) throws Exception {
+                        builder.context(MyRestContext.class);
+                }
+       }
+
+       @Test
+       public void a04_definedInBuilder() throws Exception {
+               MockRestClient x = client(A4.class);
+               x.get().run().assertBody().is("MyRestContext");
+       }
+
+
+       public static class MyBadRestContext extends RestContext {
+               public MyBadRestContext() throws Exception {
+                       super(null);
+               }
+       }
+
+       @Rest(context=MyBadRestContext.class)
+       public static class A5 {
+               @RestMethod
+               public String get(RestContext context) {
+                       return context.getClass().getSimpleName();
+               }
+       }
+
+       @Test
+       public void a05_invalidConstructor() throws Exception {
+               assertThrown(()->client(A5.class)).contains("Invalid class 
specified for REST_context");
+       }
+
+       
//------------------------------------------------------------------------------------------------------------------
+       // Helper methods
+       
//------------------------------------------------------------------------------------------------------------------
+
+       private static MockRestClient client(Class<?> c) {
+               return MockRestClient.create(c).build();
+       }
+}
diff --git 
a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/BasicRest.java
 
b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/BasicRest.java
index a4ff1f7..ff842cf 100644
--- 
a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/BasicRest.java
+++ 
b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/BasicRest.java
@@ -36,6 +36,10 @@ import org.apache.juneau.http.exception.*;
 /**
  * Identical to {@link BasicRestServlet} but doesn't extend from {@link 
HttpServlet}.
  *
+ * <p>
+ * This is particularly useful in Spring Boot environments that auto-detect 
servlets to deploy in servlet containers,
+ * but you want this resource to be deployed as a child instead.
+ *
  * <ul class='seealso'>
  *     <li class='link'>{@doc juneau-rest-server.Instantiation.BasicRest}
  * </ul>
diff --git 
a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/BasicRestCallHandler.java
 
b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/BasicRestCallHandler.java
index 6888649..af776d5 100644
--- 
a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/BasicRestCallHandler.java
+++ 
b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/BasicRestCallHandler.java
@@ -149,7 +149,7 @@ public class BasicRestCallHandler implements 
RestCallHandler {
                        if (call.getPathInfoUndecoded() != null) {
                                String p = 
call.getPathInfoUndecoded().substring(1);
                                if (context.isStaticFile(p)) {
-                                       r = context.resolveStaticFile(p);
+                                       r = context.getStaticFile(p);
                                        if (! r.exists()) {
                                                call.output(null);
                                                r = null;
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 03312dd..7677d47 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
@@ -87,7 +87,15 @@ import org.apache.juneau.xml.*;
  * </ul>
  */
 @ConfigurableContext(nocache=true)
-public final class RestContext extends BeanContext {
+public class RestContext extends BeanContext {
+
+       /** Represents a null value for the {@link Rest#context()} annotation.*/
+       @SuppressWarnings("javadoc")
+       public static final class Null extends RestContext {
+               public Null(RestContextBuilder builder) throws Exception {
+                       super(builder);
+               }
+       }
 
        
//-------------------------------------------------------------------------------------------------------------------
        // Configurable properties
@@ -804,7 +812,7 @@ public final class RestContext extends BeanContext {
         *              <li class='jm'>{@link 
#getClasspathResource(String,Locale) getClasspathResource(String,Locale)}
         *              <li class='jm'>{@link 
#getClasspathResource(Class,MediaType,String,Locale) 
getClasspathResource(Class,MediaType,String,Locale)}
         *              <li class='jm'>{@link 
#getClasspathResourceAsString(String,Locale) 
getClasspathResourceAsString(String,Locale)}
-        *              <li class='jm'>{@link #resolveStaticFile(String) 
resolveStaticFile(String)}
+        *              <li class='jm'>{@link #getStaticFile(String) 
resolveStaticFile(String)}
         *      </ul>
         *      <li class='jc'>{@link RestRequest}
         *      <ul>
@@ -1676,7 +1684,7 @@ public final class RestContext extends BeanContext {
         * <p>
         * Used for specifying the content type on file resources retrieved 
through the following methods:
         * <ul class='javatree'>
-        *      <li class='jm'>{@link RestContext#resolveStaticFile(String) 
RestContext.resolveStaticFile(String)}
+        *      <li class='jm'>{@link RestContext#getStaticFile(String) 
RestContext.resolveStaticFile(String)}
         *      <li class='jm'>{@link 
RestRequest#getClasspathHttpResource(String,boolean,MediaType,boolean)}
         *      <li class='jm'>{@link 
RestRequest#getClasspathHttpResource(String,boolean)}
         *      <li class='jm'>{@link 
RestRequest#getClasspathHttpResource(String)}
@@ -3193,6 +3201,65 @@ public final class RestContext extends BeanContext {
        public static final String REST_consumes = PREFIX + ".consumes.ls";
 
        /**
+        * Configuration property:  REST context class.
+        *
+        * <review>NEEDS REVIEW</review>
+        *
+        * <h5 class='section'>Property:</h5>
+        * <ul class='spaced-list'>
+        *      <li><b>ID:</b>  {@link 
org.apache.juneau.rest.RestContext#REST_context REST_context}
+        *      <li><b>Name:</b>  <js>"RestContext.context.c"</js>
+        *      <li><b>Data type:</b>  <c>Class&lt;? extends {@link 
org.apache.juneau.rest.RestContext}&gt;</c>
+        *      <li><b>Default:</b>  {@link org.apache.juneau.rest.RestContext}
+        *      <li><b>Session property:</b>  <jk>false</jk>
+        *      <li><b>Annotations:</b>
+        *              <ul>
+        *                      <li class='ja'>{@link 
org.apache.juneau.rest.annotation.Rest#context()}
+        *              </ul>
+        *      <li><b>Methods:</b>
+        *              <ul>
+        *                      <li class='jm'>{@link 
org.apache.juneau.rest.RestContextBuilder#context(Class)}
+        *              </ul>
+        * </ul>
+        *
+        * <h5 class='section'>Description:</h5>
+        * <p>
+        * 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 RestContextBuilder}.
+        * </ul>
+        *
+        * <h5 class='section'>Example:</h5>
+        * <p class='bcode w800'>
+        *      <jc>// Our extended context class</jc>
+        *      <jk>public</jk> MyRestContext <jk>extends</jk> RestContext {
+        *              <jk>public</jk> MyRestContext(RestContextBuilder 
<jv>builder</jv>) {
+        *                      <jk>super</jk>(<jv>builder</jv>);
+        *              }
+        *
+        *              <jc>// Override any methods.</jc>
+        *      }
+        * </p>
+        * <p class='bcode w800'>
+        *      <jc>// Option #1 - Defined via annotation.</jc>
+        *      <ja>@Rest</ja>(context=MyRestContext.<jk>class</jk>)
+        *      <jk>public class</jk> MyResource {
+        *              ...
+        *
+        *              <jc>// Option #2 - Defined via builder passed in 
through init method.</jc>
+        *              <ja>@RestHook</ja>(<jsf>INIT</jsf>)
+        *              <jk>public void</jk> init(RestContextBuilder 
<jv>builder</jv>) <jk>throws</jk> Exception {
+        *                      
<jv>builder</jv>.context(MyRestContext.<jk>class</jk>);
+        *              }
+        *      }
+        * </p>
+        */
+       public static final String REST_context = PREFIX + ".context.c";
+
+       /**
         * Configuration property:  Use classpath resource caching.
         *
         * <h5 class='section'>Property:</h5>
@@ -3704,7 +3771,7 @@ public final class RestContext extends BeanContext {
         * @throws Exception If any initialization problems were encountered.
         */
        @SuppressWarnings("deprecation")
-       RestContext(RestContextBuilder builder) throws Exception {
+       public RestContext(RestContextBuilder builder) throws Exception {
                super(builder.getPropertyStore());
 
                startTime = Instant.now();
@@ -4277,7 +4344,7 @@ public final class RestContext extends BeanContext {
         * @throws NotFound Invalid path.
         * @throws IOException Thrown by underlying stream.
         */
-       protected StaticFile resolveStaticFile(String pathInfo) throws 
NotFound, IOException {
+       protected StaticFile getStaticFile(String pathInfo) throws NotFound, 
IOException {
                if (! staticFilesCache.containsKey(pathInfo)) {
                        String p = urlDecode(trimSlashes(pathInfo));
                        if (p.indexOf("..") != -1)
@@ -4921,20 +4988,6 @@ public final class RestContext extends BeanContext {
        }
 
        /**
-        * Returns the context of the child resource associated with the 
specified path.
-        *
-        * <ul class='seealso'>
-        *      <li class='jf'>{@link RestContext#REST_children}
-        * </ul>
-        *
-        * @param path The path of the child resource to resolve.
-        * @return The resolved context, or <jk>null</jk> if it could not be 
resolved.
-        */
-       public RestContext getChildResource(String path) {
-               return childResources.get(path);
-       }
-
-       /**
         * Returns the authority path of the resource.
         *
         * <ul class='seealso'>
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 d3ea603..d9a0d14 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
@@ -204,7 +204,12 @@ public class RestContextBuilder extends BeanContextBuilder 
implements ServletCon
        @Override /* BeanContextBuilder */
        public RestContext build() {
                try {
-                       return new RestContext(this);
+                       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);
                } catch (Exception e) {
                        throw toHttpException(e, InternalServerError.class);
                }
@@ -799,6 +804,46 @@ public class RestContextBuilder extends BeanContextBuilder 
implements ServletCon
        }
 
        /**
+        * <i><l>RestContext</l> configuration property:&emsp;</i>  REST 
context class.
+        *
+        * <review>NEEDS REVIEW</review>
+        * <p>
+        * 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 RestContextBuilder}.
+        * </ul>
+        *
+        * <h5 class='section'>Example:</h5>
+        * <p class='bcode w800'>
+        *      <jc>// Our REST class</jc>
+        *      <ja>@Rest</ja>(context=MyRestContext.<jk>class</jk>)
+        *      <jk>public class</jk> MyResource {
+        *              ...
+        *      }
+        * </p>
+        * <p class='bcode w800'>
+        *      <ja>@Rest</ja>
+        *      <jk>public class</jk> MyResource {
+        *              ...
+        *              <ja>@RestHook</ja>(<jsf>INIT</jsf>)
+        *              <jk>public void</jk> init(RestContextBuilder 
<jv>builder</jv>) <jk>throws</jk> Exception {
+        *                      
<jv>builder</jv>.context(MyRestContext.<jk>class</jk>);
+        *              }
+        *      }
+        * </p>
+        *
+        * @param value The new value for this setting.
+        * @return This object (for method chaining).
+        */
+       @FluentSetter
+       public RestContextBuilder context(Class<? extends RestContext> value) {
+               return set(REST_context, value);
+       }
+
+       /**
         * <i><l>RestContext</l> configuration property:&emsp;</i>  Class-level 
response converters.
         *
         * <p>
diff --git 
a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/annotation/Rest.java
 
b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/annotation/Rest.java
index 96a72be..904e97c 100644
--- 
a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/annotation/Rest.java
+++ 
b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/annotation/Rest.java
@@ -279,6 +279,41 @@ public @interface Rest {
        String config() default "";
 
        /**
+        * Allows you to extend the {@link RestContext} class to modify how any 
of the methods are implemented.
+        *
+        * <review>NEEDS REVIEW</review>
+        * <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 RestContextBuilder}.
+        * </ul>
+        *
+        * <h5 class='section'>Example:</h5>
+        * <p class='bcode w800'>
+        *      <jc>// Our extended context class</jc>
+        *      <jk>public</jk> MyRestContext <jk>extends</jk> RestContext {
+        *              <jk>public</jk> MyRestContext(RestContextBuilder 
<jv>builder</jv>) {
+        *                      <jk>super</jk>(<jv>builder</jv>);
+        *              }
+        *
+        *              // Override any methods.
+        *      }
+        * </p>
+        * <p class='bcode w800'>
+        *      <jc>// Our REST class</jc>
+        *      <ja>@Rest</ja>(context=MyRestContext.<jk>class</jk>)
+        *      <jk>public class</jk> MyResource {
+        *              ...
+        *      }
+        * </p>
+        *
+        * <ul class='seealso'>
+        *      <li class='jm'>{@link RestContextBuilder#context(Class)}
+        * </ul>
+        */
+       Class<? extends RestContext> context() default RestContext.Null.class;
+
+       /**
         * Class-level response converters.
         *
         * <p>
diff --git 
a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/annotation/RestConfigApply.java
 
b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/annotation/RestConfigApply.java
index 74c31a8..76daa0a 100644
--- 
a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/annotation/RestConfigApply.java
+++ 
b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/annotation/RestConfigApply.java
@@ -157,6 +157,10 @@ public class RestConfigApply extends ConfigApply<Rest> {
 
                psb.prependTo(REST_paramResolvers, a.paramResolvers());
 
+               Class<?> cc = a.context();
+               if (! cc.equals(RestContext.Null.class))
+                       psb.set(REST_context, cc);
+
                s = string(a.uriContext());
                if (isNotEmpty(s))
                        psb.set(REST_uriContext, s);

Reply via email to