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

commit bf26eca3dfa5ff05af283af7181a5d76615e83d0
Author: JamesBognar <[email protected]>
AuthorDate: Tue Jan 12 16:24:29 2021 -0500

    REST refactoring.
---
 .../org/apache/juneau/cp/BeanFactory_Test.java     | 16 ++++-
 .../src/main/java/org/apache/juneau/Value.java     | 10 +++
 .../java/org/apache/juneau/cp/BeanFactory.java     | 73 ++++++++++++++++------
 .../org/apache/juneau/internal/ObjectUtils.java    | 14 +++++
 .../java/org/apache/juneau/reflect/ClassInfo.java  | 35 ++++++++++-
 .../juneau/examples/rest/springboot/App.java       | 44 ++++++++++++-
 .../rest/springboot/HelloWorldMessageProvider.java | 29 +++++----
 .../rest/springboot}/HelloWorldResource.java       | 64 ++++++++++++++++---
 .../examples/rest/springboot/RootResources.java    |  4 --
 .../microservice/springboot/template/App.java      | 57 ++++++++++++++---
 .../template/HelloWorldMessageProvider.java        | 29 +++++----
 .../springboot/template/HelloWorldResource.java    | 58 ++++++++++++++---
 .../springboot/template/RootResources.java         | 43 ++++++++++---
 .../juneau/rest/springboot/SpringBeanFactory.java  | 19 +++---
 .../juneau/rest/springboot/SpringRestServlet.java  |  8 ++-
 .../java/org/apache/juneau/rest/RestContext.java   |  6 +-
 .../org/apache/juneau/rest/RestContextBuilder.java |  5 +-
 .../java/org/apache/juneau/rest/RestServlet.java   |  5 +-
 18 files changed, 411 insertions(+), 108 deletions(-)

diff --git 
a/juneau-core/juneau-core-utest/src/test/java/org/apache/juneau/cp/BeanFactory_Test.java
 
b/juneau-core/juneau-core-utest/src/test/java/org/apache/juneau/cp/BeanFactory_Test.java
index a094f23..4368671 100644
--- 
a/juneau-core/juneau-core-utest/src/test/java/org/apache/juneau/cp/BeanFactory_Test.java
+++ 
b/juneau-core/juneau-core-utest/src/test/java/org/apache/juneau/cp/BeanFactory_Test.java
@@ -15,6 +15,8 @@ package org.apache.juneau.cp;
 import static org.apache.juneau.assertions.Assertions.*;
 import static org.junit.runners.MethodSorters.*;
 
+import java.util.*;
+
 import org.apache.juneau.annotation.*;
 import org.junit.*;
 
@@ -279,7 +281,9 @@ public class BeanFactory_Test {
        // Create bean via method.
        
//-----------------------------------------------------------------------------------------------------------------
 
-       public static class E {}
+       public static class E {
+               public A a;
+       }
 
        public static class E1 {
 
@@ -338,6 +342,12 @@ public class BeanFactory_Test {
                public static E createC2(A a) {
                        return new E();
                }
+
+               public static E createC3(Optional<A> a) {
+                       E e = new E();
+                       e.a = a.orElse(null);
+                       return e;
+               }
        }
 
        @Test
@@ -365,8 +375,12 @@ public class BeanFactory_Test {
 
                assertObject(bf.createBeanViaMethod(E.class, x, 
"createC1")).doesNotExist();
                assertObject(bf.createBeanViaMethod(E.class, x, 
"createC2")).doesNotExist();
+               assertObject(bf.createBeanViaMethod(E.class, x, 
"createC3")).exists();
+               assertObject(bf.createBeanViaMethod(E.class, x, 
"createC3").a).doesNotExist();
                bf.addBean(A.class, new A());
                assertObject(bf.createBeanViaMethod(E.class, x, 
"createC1")).exists();
                assertObject(bf.createBeanViaMethod(E.class, x, 
"createC2")).exists();
+               assertObject(bf.createBeanViaMethod(E.class, x, 
"createC3")).exists();
+               assertObject(bf.createBeanViaMethod(E.class, x, 
"createC3").a).exists();
        }
 }
diff --git 
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/Value.java 
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/Value.java
index 37f3b2a..d982e9a 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/Value.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/Value.java
@@ -27,6 +27,16 @@ import org.apache.juneau.reflect.*;
 public class Value<T> {
 
        /**
+        * Creator.
+        *
+        * @param object The object being wrapped.
+        * @return A new {@link Value} object.
+        */
+       public static <T> Value<T> of(T object) {
+               return new Value<>(object);
+       }
+
+       /**
         * Returns the generic parameter type of the Value parameter at the 
specified position.
         *
         * <h5 class='figure'>Example:</h5>
diff --git 
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/cp/BeanFactory.java
 
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/cp/BeanFactory.java
index 260fefc..f8bc7f2 100644
--- 
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/cp/BeanFactory.java
+++ 
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/cp/BeanFactory.java
@@ -23,6 +23,7 @@ import java.util.stream.*;
 import org.apache.juneau.*;
 import org.apache.juneau.annotation.*;
 import org.apache.juneau.collections.*;
+import org.apache.juneau.internal.*;
 import org.apache.juneau.reflect.*;
 
 /**
@@ -36,15 +37,24 @@ public class BeanFactory {
        public static final class Null extends BeanFactory {}
 
        private final Map<Class<?>,Supplier<?>> beanMap = new 
ConcurrentHashMap<>();
-       private final BeanFactory parent;
-       private final Object outer;
+       private final Optional<BeanFactory> parent;
+       private final Optional<Object> outer;
 
        /**
         * Default constructor.
         */
        public BeanFactory() {
-               this.parent = null;
-               this.outer = null;
+               this(Optional.empty(), Optional.empty());
+       }
+
+       /**
+        * Constructor.
+        *
+        * @param parent Parent bean factory.  Can be <jk>null</jk> if this is 
the root resource.
+        * @param outer Outer bean context to use when instantiating local 
classes.  Can be <jk>null</jk>.
+        */
+       public BeanFactory(BeanFactory parent, Object outer) {
+               this(Optional.ofNullable(parent), Optional.ofNullable(outer));
        }
 
        /**
@@ -53,7 +63,7 @@ public class BeanFactory {
         * @param parent - Optional parent bean factory.
         * @param outer Outer bean context to use when instantiating local 
classes.
         */
-       public BeanFactory(BeanFactory parent, Object outer) {
+       public BeanFactory(Optional<BeanFactory> parent, Optional<Object> 
outer) {
                this.parent = parent;
                this.outer = outer;
        }
@@ -68,13 +78,23 @@ public class BeanFactory {
        @SuppressWarnings("unchecked")
        public <T> Optional<T> getBean(Class<T> c) {
                Supplier<?> o = beanMap.get(c);
-               if (o == null && parent != null)
-                       return parent.getBean(c);
+               if (o == null && parent.isPresent())
+                       return parent.get().getBean(c);
                T t = (T)(o == null ? null : o.get());
                return Optional.ofNullable(t);
        }
 
        /**
+        * Returns the bean of the specified type.
+        *
+        * @param c The type of bean to return.
+        * @return The bean.
+        */
+       public Optional<?> getBean(ClassInfo c) {
+               return getBean(c.inner());
+       }
+
+       /**
         * Adds a bean of the specified type to this factory.
         *
         * @param <T> The class to associate this bean with.
@@ -109,15 +129,24 @@ public class BeanFactory {
        /**
         * Returns <jk>true</jk> if this factory contains the specified bean 
type instance.
         *
-        * @param <T> The bean type to check.
         * @param c The bean type to check.
         * @return <jk>true</jk> if this factory contains the specified bean 
type instance.
         */
-       public <T> boolean hasBean(Class<T> c) {
+       public boolean hasBean(Class<?> c) {
                return getBean(c).isPresent();
        }
 
        /**
+        * Returns <jk>true</jk> if this factory contains the specified bean 
type instance.
+        *
+        * @param c The bean type to check.
+        * @return <jk>true</jk> if this factory contains the specified bean 
type instance.
+        */
+       public final boolean hasBean(ClassInfo c) {
+               return hasBean(c.inner());
+       }
+
+       /**
         * Creates a bean of the specified type.
         *
         * @param <T> The bean type to create.
@@ -199,10 +228,12 @@ public class BeanFactory {
                List<ClassInfo> l = AList.of();
                for (int i = 0; i < paramTypes.size(); i++) {
                        ClassInfo pt = paramTypes.get(i);
-                       if (i == 0 && pt.isInstance(outer))
+                       ClassInfo ptr = pt.resolved();
+                       if (i == 0 && ptr.isInstance(outer.orElse(null)))
                                continue;
-                       if (! hasBean(pt.inner()))
-                               l.add(pt);
+                       if (! hasBean(ptr))
+                               if (! pt.is(Optional.class))
+                                       l.add(pt);
                }
                return l;
        }
@@ -217,10 +248,16 @@ public class BeanFactory {
                Object[] o = new Object[paramTypes.size()];
                for (int i = 0; i < paramTypes.size(); i++) {
                        ClassInfo pt = paramTypes.get(i);
-                       if (i == 0 && pt.isInstance(outer))
-                               o[i] = outer;
-                       else
-                               o[i] = getBean(pt.inner()).get();
+                       ClassInfo ptr = pt.resolved();
+                       if (i == 0 && ptr.isInstance(outer.orElse(null)))
+                               o[i] = outer.get();
+                       else {
+                               if (pt.is(Optional.class)) {
+                                       o[i] = getBean(ptr);
+                               } else {
+                                       o[i] = getBean(ptr).get();
+                               }
+                       }
                }
                return o;
        }
@@ -233,8 +270,8 @@ public class BeanFactory {
        public OMap toMap() {
                return OMap.of()
                        .a("beanMap", beanMap.keySet().stream().map(x -> 
x.getSimpleName()).collect(Collectors.toList()))
-                       .a("outer", outer == null ? null : 
outer.getClass().getSimpleName())
-                       .a("parent", parent);
+                       .a("outer", ObjectUtils.identity(outer))
+                       .a("parent", ObjectUtils.identity(parent));
        }
 
        @Override /* Object */
diff --git 
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/internal/ObjectUtils.java
 
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/internal/ObjectUtils.java
index 5e08c26..0798158 100644
--- 
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/internal/ObjectUtils.java
+++ 
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/internal/ObjectUtils.java
@@ -16,6 +16,7 @@ import java.lang.reflect.*;
 import java.util.*;
 import java.util.function.*;
 
+import org.apache.juneau.reflect.*;
 import org.apache.juneau.utils.*;
 
 /**
@@ -313,4 +314,17 @@ public class ObjectUtils {
                                        return tt;
                return null;
        }
+
+       /**
+        * Converts the specified object into an identifiable string of the 
form "Class[identityHashCode]"
+        * @param o The object to convert to a string.
+        * @return An identity string.
+        */
+       public static String identity(Object o) {
+               if (o == null)
+                       return null;
+               if (o instanceof Optional)
+                       o = ((Optional<?>)o).get();
+               return ClassInfo.of(o).getShortName() + "@" + 
System.identityHashCode(o);
+       }
 }
diff --git 
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/reflect/ClassInfo.java
 
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/reflect/ClassInfo.java
index 3f8d0b7..e969439 100644
--- 
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/reflect/ClassInfo.java
+++ 
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/reflect/ClassInfo.java
@@ -218,11 +218,42 @@ public final class ClassInfo {
         * @return The parameterized type, or this object if this class is not 
a parameterized {@link Value} type.
         */
        public ClassInfo resolved() {
-               if (Value.isType(t))
-                       return 
of(Value.getParameterType(t))._getProxiedClassInfo();
+               if (isValue(t) || isOptional(t)) {
+                       Type t = getFirstParameterType(this.t);
+                       if (t != null)
+                               return of(t)._getProxiedClassInfo();
+               }
                return _getProxiedClassInfo();
        }
 
+       private static Type getFirstParameterType(Type t) {
+               if (t instanceof ParameterizedType) {
+                       ParameterizedType pt = (ParameterizedType)t;
+                       Type[] ta = pt.getActualTypeArguments();
+                       if (ta.length > 0)
+                               return ta[0];
+               } else if (t instanceof Class) /* Class that extends 
Optional<T> */ {
+                       Class<?> c = (Class<?>)t;
+                       if (c != Value.class && Value.class.isAssignableFrom(c))
+                               return ClassInfo.of(c).getParameterType(0, 
Value.class);
+                       if (c != Optional.class && 
Optional.class.isAssignableFrom(c))
+                               return ClassInfo.of(c).getParameterType(0, 
Optional.class);
+               }
+               return null;
+       }
+
+       private static boolean isOptional(Type t) {
+               return
+                       (t instanceof ParameterizedType && 
((ParameterizedType)t).getRawType() == Optional.class)
+                       || (t instanceof Class && 
Optional.class.isAssignableFrom((Class<?>)t));
+       }
+
+       private static boolean isValue(Type t) {
+               return
+                       (t instanceof ParameterizedType && 
((ParameterizedType)t).getRawType() == Value.class)
+                       || (t instanceof Class && 
Value.class.isAssignableFrom((Class<?>)t));
+       }
+
        private ClassInfo _getProxiedClassInfo() {
                return proxyFor == null ? this : proxyFor;
        }
diff --git 
a/juneau-examples/juneau-examples-rest-springboot/src/main/java/org/apache/juneau/examples/rest/springboot/App.java
 
b/juneau-examples/juneau-examples-rest-springboot/src/main/java/org/apache/juneau/examples/rest/springboot/App.java
index 0d419fc..9fa808b 100644
--- 
a/juneau-examples/juneau-examples-rest-springboot/src/main/java/org/apache/juneau/examples/rest/springboot/App.java
+++ 
b/juneau-examples/juneau-examples-rest-springboot/src/main/java/org/apache/juneau/examples/rest/springboot/App.java
@@ -14,6 +14,8 @@ package org.apache.juneau.examples.rest.springboot;
 
 import javax.servlet.*;
 
+import org.apache.juneau.rest.annotation.*;
+import org.apache.juneau.rest.springboot.*;
 import org.springframework.boot.autoconfigure.SpringBootApplication;
 import org.springframework.boot.builder.*;
 import org.springframework.boot.web.servlet.*;
@@ -42,11 +44,47 @@ public class App {
        }
 
        /**
-        * @return Our root resource.
+        * Our root REST bean.
+        * <p>
+        * Note that this must extend from {@link SpringRestServlet} so that 
child resources can be resolved as Spring
+        * beans.
+        * <p>
+        * All REST objects are attached to this bean using the {@link 
Rest#children()} annotation.
+        *
+        * @return The root resources REST bean.
+        */
+       @Bean
+       public RootResources getRootResources() {
+               return new RootResources();
+       }
+
+       /**
+        * Optionally return the {@link HelloWorldResource} object as an 
injectable bean.
+        *
+        * @return The hello-world REST bean.
+        */
+       @Bean
+       public HelloWorldResource getHelloWorldResource() {
+               return new HelloWorldResource("Hello Spring user!");
+       }
+
+       /**
+        * Optionally return an injectable message provider for the {@link 
HelloWorldResource} class.
+        *
+        * @return The message provider for the hello-world REST bean.
+        */
+       @Bean
+       public HelloWorldMessageProvider getHelloWorldMessageProvider() {
+               return new HelloWorldMessageProvider("Hello Spring injection 
user!");
+       }
+
+       /**
+        * @param rootResources The root REST resource servlet
+        * @return The servlet registration mapped to "/*".
         */
        @Bean
-       public ServletRegistrationBean<Servlet> getRootResources() {
-               return new ServletRegistrationBean<>(new RootResources(), "/*");
+       public ServletRegistrationBean<Servlet> getRootServlet(RootResources 
rootResources) {
+               return new ServletRegistrationBean<>(rootResources, "/*");
        }
 
        /**
diff --git 
a/juneau-rest/juneau-rest-server-springboot/src/main/java/org/apache/juneau/rest/springboot/SpringRestServlet.java
 
b/juneau-examples/juneau-examples-rest-springboot/src/main/java/org/apache/juneau/examples/rest/springboot/HelloWorldMessageProvider.java
similarity index 74%
copy from 
juneau-rest/juneau-rest-server-springboot/src/main/java/org/apache/juneau/rest/springboot/SpringRestServlet.java
copy to 
juneau-examples/juneau-examples-rest-springboot/src/main/java/org/apache/juneau/examples/rest/springboot/HelloWorldMessageProvider.java
index e55c565..54f44b2 100644
--- 
a/juneau-rest/juneau-rest-server-springboot/src/main/java/org/apache/juneau/rest/springboot/SpringRestServlet.java
+++ 
b/juneau-examples/juneau-examples-rest-springboot/src/main/java/org/apache/juneau/examples/rest/springboot/HelloWorldMessageProvider.java
@@ -10,26 +10,29 @@
 // * "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.springboot;
+package org.apache.juneau.examples.rest.springboot;
 
-import javax.inject.*;
-
-import org.apache.juneau.cp.*;
-import org.apache.juneau.rest.*;
-import org.springframework.context.*;
+import java.util.function.*;
 
 /**
- * Subclass of a {@link RestServlet} meant for use as deployed top-level REST 
beans.
+ * An example of a Spring bean that can be used for injecting messages into 
{@link HelloWorldResource}.
  */
-public abstract class SpringRestServlet extends RestServlet {
+public class HelloWorldMessageProvider implements Supplier<String> {
 
-       private static final long serialVersionUID = 1L;
+       private final String message;
 
-       @Inject
-       private ApplicationContext appContext;
+       /**
+        * Constructor.
+        *
+        * @param message The message to display.
+        */
+       public HelloWorldMessageProvider(String message) {
+               this.message = message;
+       }
 
        @Override
-       protected BeanFactory createBeanFactory(BeanFactory parent) {
-               return new SpringBeanFactory(appContext, parent, this);
+       public String get() {
+               return message;
        }
+
 }
diff --git 
a/juneau-microservice/juneau-my-springboot-microservice/src/main/java/org/apache/juneau/microservice/springboot/template/HelloWorldResource.java
 
b/juneau-examples/juneau-examples-rest-springboot/src/main/java/org/apache/juneau/examples/rest/springboot/HelloWorldResource.java
old mode 100755
new mode 100644
similarity index 55%
copy from 
juneau-microservice/juneau-my-springboot-microservice/src/main/java/org/apache/juneau/microservice/springboot/template/HelloWorldResource.java
copy to 
juneau-examples/juneau-examples-rest-springboot/src/main/java/org/apache/juneau/examples/rest/springboot/HelloWorldResource.java
index 6b2b6cf..2d58a52
--- 
a/juneau-microservice/juneau-my-springboot-microservice/src/main/java/org/apache/juneau/microservice/springboot/template/HelloWorldResource.java
+++ 
b/juneau-examples/juneau-examples-rest-springboot/src/main/java/org/apache/juneau/examples/rest/springboot/HelloWorldResource.java
@@ -10,30 +10,76 @@
 // * "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.microservice.springboot.template;
+package org.apache.juneau.examples.rest.springboot;
 
 import static org.apache.juneau.http.HttpMethod.*;
 
+import java.util.*;
+
+import javax.inject.*;
+
+import org.apache.juneau.html.annotation.*;
 import org.apache.juneau.rest.*;
 import org.apache.juneau.rest.annotation.*;
 
 /**
  * Sample REST resource that prints out a simple "Hello world!" message.
+ *
+ * <ul class='seealso'>
+ *     <li class='extlink'>{@source}
+ * </ul>
  */
 @Rest(
-       title="Hello World example",
-       path="/helloworld",
-       description="Simplest possible REST resource"
+       title="Hello World",
+       description="An example of the simplest-possible resource",
+       path="/helloWorld"
+)
+@HtmlDocConfig(
+       aside={
+               "<div style='max-width:400px' class='text'>",
+               "       <p>This page shows a resource that simply response with 
a 'Hello world!' message</p>",
+               "       <p>The POJO serialized is a simple String.</p>",
+               "</div>"
+       }
 )
-public class HelloWorldResource extends BasicRestServlet {
-       private static final long serialVersionUID = 1L;
+public class HelloWorldResource extends BasicRestObject {
+
+       private final String message;
+
+       /**
+        * Optional message provider that can be injected into this object.
+        */
+       @Inject
+       private Optional<HelloWorldMessageProvider> messageProvider;
+
+       /**
+        * Default constructor.
+        * <p>
+        * Used by default if bean cannot be found in the Spring application 
context.
+        */
+       public HelloWorldResource() {
+               this("Hello world!");
+       }
+
+       /**
+        * Constructor.
+        *
+        * @param message The message to display.
+        */
+       public HelloWorldResource(String message) {
+               this.message = message;
+       }
 
        /**
         * GET request handler.
-        * @return The string "Hello world!"
+        *
+        * @return A simple Hello-World message.
         */
-       @RestMethod(method=GET, path="/*")
+       @RestMethod(method=GET, path="/*", summary="Responds with \"Hello 
world!\"")
        public String sayHello() {
-               return "Hello world!";
+               String message = this.message;
+               if (messageProvider != null && messageProvider.isPresent())
+                       message = messageProvider.get().get();
+               return message;
        }
 }
diff --git 
a/juneau-examples/juneau-examples-rest-springboot/src/main/java/org/apache/juneau/examples/rest/springboot/RootResources.java
 
b/juneau-examples/juneau-examples-rest-springboot/src/main/java/org/apache/juneau/examples/rest/springboot/RootResources.java
index 4e3a176..8e47ead 100644
--- 
a/juneau-examples/juneau-examples-rest-springboot/src/main/java/org/apache/juneau/examples/rest/springboot/RootResources.java
+++ 
b/juneau-examples/juneau-examples-rest-springboot/src/main/java/org/apache/juneau/examples/rest/springboot/RootResources.java
@@ -12,7 +12,6 @@
 // 
***************************************************************************************************************************
 package org.apache.juneau.examples.rest.springboot;
 
-import org.apache.juneau.examples.rest.*;
 import org.apache.juneau.examples.rest.dto.*;
 import org.apache.juneau.html.annotation.*;
 import org.apache.juneau.microservice.resources.*;
@@ -71,8 +70,5 @@ import org.apache.juneau.serializer.annotation.*;
        quoteChar="'"
 )
 public class RootResources extends BasicSpringRestServletGroup {
-       // IMPORTANT!  If you don't need RDF support, change the parent class 
to ResourceGroup.
-       // It allows you to remove the Jena prerequisite.
-
        private static final long serialVersionUID = 1L;
 }
diff --git 
a/juneau-microservice/juneau-my-springboot-microservice/src/main/java/org/apache/juneau/microservice/springboot/template/App.java
 
b/juneau-microservice/juneau-my-springboot-microservice/src/main/java/org/apache/juneau/microservice/springboot/template/App.java
index 2c6516e..bff325f 100644
--- 
a/juneau-microservice/juneau-my-springboot-microservice/src/main/java/org/apache/juneau/microservice/springboot/template/App.java
+++ 
b/juneau-microservice/juneau-my-springboot-microservice/src/main/java/org/apache/juneau/microservice/springboot/template/App.java
@@ -14,12 +14,14 @@ package org.apache.juneau.microservice.springboot.template;
 
 import javax.servlet.*;
 
+import org.apache.juneau.rest.annotation.*;
+import org.apache.juneau.rest.springboot.*;
 import org.springframework.boot.autoconfigure.SpringBootApplication;
 import org.springframework.boot.builder.*;
 import org.springframework.boot.web.servlet.*;
 import org.springframework.context.annotation.*;
 import org.springframework.stereotype.Controller;
-import org.springframework.web.filter.HiddenHttpMethodFilter;
+import org.springframework.web.filter.*;
 
 /**
  * Entry point for Examples REST application when deployed as a Spring Boot 
application.
@@ -30,8 +32,7 @@ public class App {
 
        /**
         * Entry point method.
-        *
-        * @param args Command-line arguments
+        * @param args Command-line arguments.
         */
        @SuppressWarnings("resource")
        public static void main(String[] args) {
@@ -39,19 +40,55 @@ public class App {
        }
 
        /**
-        * @return Our root resource.
+        * Our root REST bean.
+        * <p>
+        * Note that this must extend from {@link SpringRestServlet} so that 
child resources can be resolved as Spring
+        * beans.
+        * <p>
+        * All REST objects are attached to this bean using the {@link 
Rest#children()} annotation.
+        *
+        * @return The root resources REST bean.
+        */
+       @Bean
+       public RootResources getRootResources() {
+               return new RootResources();
+       }
+
+       /**
+        * Optionally return the {@link HelloWorldResource} object as an 
injectable bean.
+        *
+        * @return The hello-world REST bean.
+        */
+       @Bean
+       public HelloWorldResource getHelloWorldResource() {
+               return new HelloWorldResource("Hello Spring user!");
+       }
+
+       /**
+        * Optionally return an injectable message provider for the {@link 
HelloWorldResource} class.
+        *
+        * @return The message provider for the hello-world REST bean.
+        */
+       @Bean
+       public HelloWorldMessageProvider getHelloWorldMessageProvider() {
+               return new HelloWorldMessageProvider("Hello Spring injection 
user!");
+       }
+
+       /**
+        * @param rootResources The root REST resource servlet
+        * @return The servlet registration mapped to "/*".
         */
        @Bean
-       public ServletRegistrationBean<Servlet> getRootResources() {
-               return new ServletRegistrationBean<>(new RootResources(), "/*");
+       public ServletRegistrationBean<Servlet> getRootServlet(RootResources 
rootResources) {
+               return new ServletRegistrationBean<>(rootResources, "/*");
        }
 
        /**
-        * If you want to parse URL-encoded form posts directly into beans, 
this call will disable the HiddenHttpMethodFilter
-        * which triggers form posts to be consumed.
+        * We want to be able to consume url-encoded-form-post bodies, but 
HiddenHttpMethodFilter triggers the HTTP
+        * body to be consumed.  So disable it.
         *
-        * @param filter The filter to alter.
-        * @return The registration bean.
+        * @param filter The filter.
+        * @return Filter registration bean.
         */
        @Bean
        public FilterRegistrationBean<HiddenHttpMethodFilter> 
registration(HiddenHttpMethodFilter filter) {
diff --git 
a/juneau-rest/juneau-rest-server-springboot/src/main/java/org/apache/juneau/rest/springboot/SpringRestServlet.java
 
b/juneau-microservice/juneau-my-springboot-microservice/src/main/java/org/apache/juneau/microservice/springboot/template/HelloWorldMessageProvider.java
similarity index 74%
copy from 
juneau-rest/juneau-rest-server-springboot/src/main/java/org/apache/juneau/rest/springboot/SpringRestServlet.java
copy to 
juneau-microservice/juneau-my-springboot-microservice/src/main/java/org/apache/juneau/microservice/springboot/template/HelloWorldMessageProvider.java
index e55c565..b536beb 100644
--- 
a/juneau-rest/juneau-rest-server-springboot/src/main/java/org/apache/juneau/rest/springboot/SpringRestServlet.java
+++ 
b/juneau-microservice/juneau-my-springboot-microservice/src/main/java/org/apache/juneau/microservice/springboot/template/HelloWorldMessageProvider.java
@@ -10,26 +10,29 @@
 // * "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.springboot;
+package org.apache.juneau.microservice.springboot.template;
 
-import javax.inject.*;
-
-import org.apache.juneau.cp.*;
-import org.apache.juneau.rest.*;
-import org.springframework.context.*;
+import java.util.function.*;
 
 /**
- * Subclass of a {@link RestServlet} meant for use as deployed top-level REST 
beans.
+ * An example of a Spring bean that can be used for injecting messages into 
{@link HelloWorldResource}.
  */
-public abstract class SpringRestServlet extends RestServlet {
+public class HelloWorldMessageProvider implements Supplier<String> {
 
-       private static final long serialVersionUID = 1L;
+       private final String message;
 
-       @Inject
-       private ApplicationContext appContext;
+       /**
+        * Constructor.
+        *
+        * @param message The message to display.
+        */
+       public HelloWorldMessageProvider(String message) {
+               this.message = message;
+       }
 
        @Override
-       protected BeanFactory createBeanFactory(BeanFactory parent) {
-               return new SpringBeanFactory(appContext, parent, this);
+       public String get() {
+               return message;
        }
+
 }
diff --git 
a/juneau-microservice/juneau-my-springboot-microservice/src/main/java/org/apache/juneau/microservice/springboot/template/HelloWorldResource.java
 
b/juneau-microservice/juneau-my-springboot-microservice/src/main/java/org/apache/juneau/microservice/springboot/template/HelloWorldResource.java
old mode 100755
new mode 100644
index 6b2b6cf..28ab92d
--- 
a/juneau-microservice/juneau-my-springboot-microservice/src/main/java/org/apache/juneau/microservice/springboot/template/HelloWorldResource.java
+++ 
b/juneau-microservice/juneau-my-springboot-microservice/src/main/java/org/apache/juneau/microservice/springboot/template/HelloWorldResource.java
@@ -14,6 +14,11 @@ package org.apache.juneau.microservice.springboot.template;
 
 import static org.apache.juneau.http.HttpMethod.*;
 
+import java.util.*;
+
+import javax.inject.*;
+
+import org.apache.juneau.html.annotation.*;
 import org.apache.juneau.rest.*;
 import org.apache.juneau.rest.annotation.*;
 
@@ -21,19 +26,56 @@ import org.apache.juneau.rest.annotation.*;
  * Sample REST resource that prints out a simple "Hello world!" message.
  */
 @Rest(
-       title="Hello World example",
-       path="/helloworld",
-       description="Simplest possible REST resource"
+       title="Hello World",
+       description="An example of the simplest-possible resource",
+       path="/helloWorld"
+)
+@HtmlDocConfig(
+       aside={
+               "<div style='max-width:400px' class='text'>",
+               "       <p>This page shows a resource that simply response with 
a 'Hello world!' message</p>",
+               "       <p>The POJO serialized is a simple String.</p>",
+               "</div>"
+       }
 )
-public class HelloWorldResource extends BasicRestServlet {
-       private static final long serialVersionUID = 1L;
+public class HelloWorldResource extends BasicRestObject {
+
+       private final String message;
+
+       /**
+        * Optional message provider that can be injected into this object.
+        */
+       @Inject
+       private Optional<HelloWorldMessageProvider> messageProvider;
+
+       /**
+        * Default constructor.
+        * <p>
+        * Used by default if bean cannot be found in the Spring application 
context.
+        */
+       public HelloWorldResource() {
+               this("Hello world!");
+       }
+
+       /**
+        * Constructor.
+        *
+        * @param message The message to display.
+        */
+       public HelloWorldResource(String message) {
+               this.message = message;
+       }
 
        /**
         * GET request handler.
-        * @return The string "Hello world!"
+        *
+        * @return A simple Hello-World message.
         */
-       @RestMethod(method=GET, path="/*")
+       @RestMethod(method=GET, path="/*", summary="Responds with \"Hello 
world!\"")
        public String sayHello() {
-               return "Hello world!";
+               String message = this.message;
+               if (messageProvider != null && messageProvider.isPresent())
+                       message = messageProvider.get().get();
+               return message;
        }
 }
diff --git 
a/juneau-microservice/juneau-my-springboot-microservice/src/main/java/org/apache/juneau/microservice/springboot/template/RootResources.java
 
b/juneau-microservice/juneau-my-springboot-microservice/src/main/java/org/apache/juneau/microservice/springboot/template/RootResources.java
old mode 100755
new mode 100644
index fb170c3..3863681
--- 
a/juneau-microservice/juneau-my-springboot-microservice/src/main/java/org/apache/juneau/microservice/springboot/template/RootResources.java
+++ 
b/juneau-microservice/juneau-my-springboot-microservice/src/main/java/org/apache/juneau/microservice/springboot/template/RootResources.java
@@ -12,21 +12,24 @@
 // 
***************************************************************************************************************************
 package org.apache.juneau.microservice.springboot.template;
 
-import org.apache.juneau.html.annotation.HtmlDocConfig;
-import org.apache.juneau.microservice.resources.ConfigResource;
-import org.apache.juneau.microservice.resources.LogsResource;
+import org.apache.juneau.html.annotation.*;
+import org.apache.juneau.microservice.resources.*;
 import org.apache.juneau.rest.annotation.*;
 import org.apache.juneau.rest.springboot.*;
-import org.apache.juneau.rest.widget.ContentTypeMenuItem;
-import org.apache.juneau.rest.widget.ThemeMenuItem;
+import org.apache.juneau.rest.widget.*;
+import org.apache.juneau.serializer.annotation.*;
 
 /**
- * Root microservice page.
+ * Sample REST resource showing how to implement a "router" resource page.
+ *
+ * <ul class='seealso'>
+ *     <li class='extlink'>{@source}
+ * </ul>
  */
 @Rest(
        path="/*",
-       title="My Microservice",
-       description="Top-level resources page",
+       title="Root resources",
+       description="Example of a router resource page.",
        children={
                HelloWorldResource.class,
                ConfigResource.class,
@@ -40,8 +43,28 @@ import org.apache.juneau.rest.widget.ThemeMenuItem;
        },
        navlinks={
                "api: servlet:/api",
-               "stats: servlet:/stats"
-       }
+               "stats: servlet:/stats",
+               "$W{ContentTypeMenuItem}",
+               "$W{ThemeMenuItem}",
+               "source: 
$C{Source/gitHub}/org/apache/juneau/examples/rest/$R{servletClassSimple}.java"
+       },
+       aside={
+               "<div class='text'>",
+               "       <p>This is an example of a 'router' page that serves as 
a jumping-off point to child resources.</p>",
+               "       <p>Resources can be nested arbitrarily deep through 
router pages.</p>",
+               "       <p>Note the <span class='link'>options</span> link 
provided that lets you see the generated swagger doc for this page.</p>",
+               "       <p>Also note the <span class='link'>sources</span> link 
on these pages to view the source code for the page.</p>",
+               "       <p>All content on pages in the UI are serialized POJOs. 
 In this case, it's a serialized array of beans with 2 properties, 'name' and 
'description'.</p>",
+               "       <p>Other features (such as this aside) are added 
through annotations.</p>",
+               "</div>"
+       },
+       asideFloat="RIGHT"
+)
+@SerializerConfig(
+       // For testing purposes, we want to use single quotes in all the 
serializers so it's easier to do simple
+       // String comparisons.
+       // You can apply any of the Serializer/Parser/BeanContext settings this 
way.
+       quoteChar="'"
 )
 public class RootResources extends BasicSpringRestServletGroup {
        private static final long serialVersionUID = 1L;
diff --git 
a/juneau-rest/juneau-rest-server-springboot/src/main/java/org/apache/juneau/rest/springboot/SpringBeanFactory.java
 
b/juneau-rest/juneau-rest-server-springboot/src/main/java/org/apache/juneau/rest/springboot/SpringBeanFactory.java
index bf628ba..46765ae 100644
--- 
a/juneau-rest/juneau-rest-server-springboot/src/main/java/org/apache/juneau/rest/springboot/SpringBeanFactory.java
+++ 
b/juneau-rest/juneau-rest-server-springboot/src/main/java/org/apache/juneau/rest/springboot/SpringBeanFactory.java
@@ -22,7 +22,7 @@ import org.springframework.context.*;
  */
 public class SpringBeanFactory extends BeanFactory {
 
-       private final ApplicationContext appContext;
+       private final Optional<ApplicationContext> appContext;
 
        /**
         * Constructor.
@@ -31,21 +31,22 @@ public class SpringBeanFactory extends BeanFactory {
         * @param parent The parent REST object bean factory.  Can be 
<jk>null</jk>.
         * @param resource The REST object.  Can be <jk>null</jk>.
         */
-       public SpringBeanFactory(ApplicationContext appContext, BeanFactory 
parent, Object resource) {
-               super(parent, resource);
+       public SpringBeanFactory(Optional<ApplicationContext> appContext, 
Optional<BeanFactory> parent, Object resource) {
+               super(parent, Optional.of(resource));
                this.appContext = appContext;
        }
 
        @Override
        public <T> Optional<T> getBean(Class<T> c) {
-               Optional<T> o = super.getBean(c);
-               if (o.isPresent())
-                       return o;
                try {
-                       T t = appContext.getBean(c);
-                       return Optional.of(t);
+                       Optional<T> o = super.getBean(c);
+                       if (o.isPresent())
+                               return o;
+                       if (appContext.isPresent())
+                               return 
Optional.ofNullable(appContext.get().getBean(c));
                } catch (Exception e) {
-                       return Optional.empty();
+                       e.printStackTrace();
                }
+               return Optional.empty();
        }
 }
diff --git 
a/juneau-rest/juneau-rest-server-springboot/src/main/java/org/apache/juneau/rest/springboot/SpringRestServlet.java
 
b/juneau-rest/juneau-rest-server-springboot/src/main/java/org/apache/juneau/rest/springboot/SpringRestServlet.java
index e55c565..5a4079c 100644
--- 
a/juneau-rest/juneau-rest-server-springboot/src/main/java/org/apache/juneau/rest/springboot/SpringRestServlet.java
+++ 
b/juneau-rest/juneau-rest-server-springboot/src/main/java/org/apache/juneau/rest/springboot/SpringRestServlet.java
@@ -12,6 +12,8 @@
 // 
***************************************************************************************************************************
 package org.apache.juneau.rest.springboot;
 
+import java.util.*;
+
 import javax.inject.*;
 
 import org.apache.juneau.cp.*;
@@ -26,10 +28,10 @@ public abstract class SpringRestServlet extends RestServlet 
{
        private static final long serialVersionUID = 1L;
 
        @Inject
-       private ApplicationContext appContext;
+       private Optional<ApplicationContext> appContext;
 
-       @Override
-       protected BeanFactory createBeanFactory(BeanFactory parent) {
+       @Override /* RestServlet */
+       public BeanFactory createBeanFactory(Optional<BeanFactory> parent) {
                return new SpringBeanFactory(appContext, parent, this);
        }
 }
diff --git 
a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestContext.java
 
b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestContext.java
index 32cb3b7..88c0ce2 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
@@ -3291,6 +3291,8 @@ public class RestContext extends BeanContext {
 
                        beanFactory = createBeanFactory(r);
                        beanFactory.addBean(BeanFactory.class, beanFactory);
+                       beanFactory.addBean(RestContext.class, this);
+                       beanFactory.addBean(Object.class, r);
 
                        PropertyStore ps = getPropertyStore();
                        beanFactory.addBean(PropertyStore.class, ps);
@@ -3925,7 +3927,9 @@ public class RestContext extends BeanContext {
                BeanFactory x = null;
                if (resource instanceof BeanFactory)
                        x = (BeanFactory)resource;
-               BeanFactory bf = new BeanFactory(parentContext == null ? null : 
parentContext.rootBeanFactory, resource);
+               BeanFactory parent = parentContext == null ? null : 
parentContext.rootBeanFactory;
+               BeanFactory bf = new BeanFactory(parent, resource);
+               bf.addBean(BeanFactory.class, bf);
                if (x == null)
                        x = getInstanceProperty(REST_beanFactory, 
BeanFactory.class, null, bf);
                if (x == null)
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 5fa0ccd..a11300d 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
@@ -202,8 +202,9 @@ public class RestContextBuilder extends BeanContextBuilder 
implements ServletCon
        protected BeanFactory createBeanFactory(Optional<RestContext> 
parentContext, Optional<Object> resource) throws Exception {
                BeanFactory x = null;
                if (resource.isPresent()) {
-                       BeanFactory bf = new 
BeanFactory(parentContext.isPresent() ? parentContext.get().rootBeanFactory : 
null, resource);
-                       x = bf.createBeanViaMethod(BeanFactory.class, resource, 
"createBeanFactory");
+                       Object r = resource.get();
+                       BeanFactory bf = new 
BeanFactory(parentContext.isPresent() ? parentContext.get().rootBeanFactory : 
null, r);
+                       x = bf.createBeanViaMethod(BeanFactory.class, r, 
"createBeanFactory");
                }
                if (x == null && parentContext.isPresent()) {
                        x = parentContext.get().rootBeanFactory;
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 8664f58..f9bec8e 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
@@ -20,6 +20,7 @@ import static org.apache.juneau.rest.annotation.HookEvent.*;
 
 import java.io.*;
 import java.text.*;
+import java.util.*;
 import java.util.concurrent.atomic.*;
 import java.util.function.*;
 import java.util.logging.*;
@@ -72,8 +73,8 @@ public abstract class RestServlet extends HttpServlet {
         * @param parent The parent bean factory.
         * @return A new bean factory.
         */
-       protected BeanFactory createBeanFactory(BeanFactory parent) {
-               return new BeanFactory(parent, this);
+       public BeanFactory createBeanFactory(Optional<BeanFactory> parent) {
+               return new BeanFactory(parent.orElse(null), this);
        }
 
        /**

Reply via email to