You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@juneau.apache.org by ja...@apache.org on 2020/07/29 14:58:24 UTC
[juneau] branch master updated: New @Rest(context) setting.
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 <ja...@salesforce.com>
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<? extends {@link org.apache.juneau.rest.RestContext}></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<{@link org.apache.juneau.rest.RestConverter}|Class<{@link org.apache.juneau.rest.RestConverter}>></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<{@link org.apache.juneau.rest.MessageBundleLocation}></c></td>
+ <td style='max-width:250px;overflow:hidden'><c>List<{@link org.apache.juneau.utils.Tuple2}<Class,String>></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<? extends {@link org.apache.juneau.rest.RestContext}></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: </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: </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);