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);
}
/**