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 23202a3  Context API refactoring.
23202a3 is described below

commit 23202a3c67a1795f79c9accf7129170a3a63bef4
Author: JamesBognar <[email protected]>
AuthorDate: Sun Sep 12 10:55:44 2021 -0400

    Context API refactoring.
---
 .../org/apache/juneau/cp/DefaultClassList.java     |  96 +++++
 .../apache/juneau/rest/mock/MockRestClient.java    |   2 +-
 .../java/org/apache/juneau/rest/RestContext.java   | 157 +-------
 .../org/apache/juneau/rest/RestContextBuilder.java | 395 ++++++++++----------
 .../org/apache/juneau/rest/annotation/Rest.java    |   3 +-
 .../juneau/rest/annotation/RestAnnotation.java     |   2 +-
 .../juneau/rest/logging/BasicRestLogger.java       |   7 +-
 .../rest/logging/BasicTestCaptureRestLogger.java   |   4 +-
 .../juneau/rest/logging/BasicTestRestLogger.java   |   2 +-
 .../org/apache/juneau/rest/logging/RestLogger.java | 403 ++++++++++++++++++++-
 .../juneau/rest/logging/RestLoggerBuilder.java     | 346 ------------------
 .../apache/juneau/rest/logging/RestLoggerRule.java | 262 +++++++++++++-
 .../juneau/rest/logging/RestLoggerRuleBuilder.java | 280 --------------
 .../apache/juneau/cp/DefaultClassList_Test.java    |  41 +++
 14 files changed, 1001 insertions(+), 999 deletions(-)

diff --git 
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/cp/DefaultClassList.java
 
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/cp/DefaultClassList.java
new file mode 100644
index 0000000..81c1d5e
--- /dev/null
+++ 
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/cp/DefaultClassList.java
@@ -0,0 +1,96 @@
+// 
***************************************************************************************************************************
+// * 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.cp;
+
+import static java.util.Arrays.*;
+import static org.apache.juneau.assertions.Assertions.*;
+
+import java.util.*;
+
+/**
+ * A list of default implementation classes.
+ */
+public class DefaultClassList {
+
+       /**
+        * Static creator.
+        *
+        * @return A new object.
+        */
+       public static DefaultClassList create() {
+               return new DefaultClassList();
+       }
+
+       /**
+        * Static creator.
+        *
+        * @param values Initial entries in this list.
+        * @return A new object initialized with the specified values.
+        */
+       public static DefaultClassList of(Class<?>...values) {
+               return new DefaultClassList().add(values);
+       }
+
+       private final List<Class<?>> entries;
+
+       /**
+        * Constructor.
+        */
+       protected DefaultClassList() {
+               entries = new ArrayList<>();
+       }
+
+       /**
+        * Copy constructor
+        *
+        * @param value The object to copy.
+        */
+       public DefaultClassList(DefaultClassList value) {
+               entries = new ArrayList<>(value.entries);
+       }
+
+       /**
+        * Prepends the specified values to the beginning of this list.
+        *
+        * @param values The values to prepend to this list.
+        * @return This object.
+        */
+       public DefaultClassList add(Class<?>...values) {
+               entries.addAll(0, asList(values));
+               return this;
+       }
+
+       /**
+        * Returns the first class in this list which is a subclass of (or same 
as) the specified type.
+        *
+        * @param type The parent type to check for.
+        * @return The first class in this list which is a subclass of the 
specified type.
+        */
+       @SuppressWarnings("unchecked")
+       public <T> Optional<Class<? extends T>> get(Class<T> type) {
+               assertArgNotNull("type", type);
+               for (Class<?> e : entries)
+                       if (e != null && type.isAssignableFrom(e))
+                               return Optional.of((Class<? extends T>)e);
+               return Optional.empty();
+       }
+
+       /**
+        * Creates a copy of this list.
+        *
+        * @return A copy of this list.
+        */
+       public DefaultClassList copy() {
+               return new DefaultClassList(this);
+       }
+}
diff --git 
a/juneau-rest/juneau-rest-mock/src/main/java/org/apache/juneau/rest/mock/MockRestClient.java
 
b/juneau-rest/juneau-rest-mock/src/main/java/org/apache/juneau/rest/mock/MockRestClient.java
index ca9436f..851ef4e 100644
--- 
a/juneau-rest/juneau-rest-mock/src/main/java/org/apache/juneau/rest/mock/MockRestClient.java
+++ 
b/juneau-rest/juneau-rest-mock/src/main/java/org/apache/juneau/rest/mock/MockRestClient.java
@@ -282,7 +282,7 @@ public class MockRestClient extends RestClient implements 
HttpClientConnection {
                                RestContext rc = RestContext
                                        .create(o.getClass(), null, null)
                                        .init(o)
-                                       
.callLoggerDefault(BasicTestRestLogger.class)
+                                       
.defaultClasses(BasicTestRestLogger.class)
                                        .debugDefault(CONDITIONAL)
                                        .build()
                                        .postInit()
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 4699829..7fdf04f 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
@@ -19,9 +19,7 @@ import static org.apache.juneau.internal.IOUtils.*;
 import static org.apache.juneau.internal.StringUtils.*;
 import static org.apache.juneau.rest.HttpRuntimeException.*;
 import static org.apache.juneau.rest.ResponseProcessor.*;
-import static org.apache.juneau.rest.logging.RestLoggingDetail.*;
 import static java.util.Collections.*;
-import static java.util.logging.Level.*;
 import static java.util.Optional.*;
 
 import java.io.*;
@@ -194,9 +192,8 @@ public class RestContext extends Context {
        final Charset defaultCharset;
        final long maxInput;
 
-       final BeanRef<RestLogger> callLoggerDefault;
-
        final Enablement debugDefault;
+       final DefaultClassList defaultClasses;
 
        // Lifecycle methods
        private final MethodInvoker[]
@@ -246,6 +243,7 @@ public class RestContext extends Context {
                        resource = builder.resource;
                        parentContext = builder.parentContext;
                        rootBeanStore = builder.beanStore();
+                       defaultClasses = builder.defaultClasses();
 
                        BeanStore bs = beanStore = rootBeanStore.copy().build();
                        beanStore
@@ -262,14 +260,10 @@ public class RestContext extends Context {
                        varResolver = bs.add(VarResolver.class, 
builder.varResolver().bean(Messages.class, messages).build());
                        config = bs.add(Config.class, 
builder.config().resolving(varResolver.createSession()));
                        responseProcessors = bs.add(ResponseProcessor[].class, 
builder.responseProcessors().build().toArray());
-
-                       Object r = resource.get();
-
-                       callLoggerDefault = builder.callLoggerDefault;
                        debugDefault = builder.debugDefault;
+                       callLogger = bs.add(RestLogger.class, 
builder.callLogger().beanStore(beanStore).loggerOnce(logger).thrownStoreOnce(thrownStore).build());
 
-                       callLogger = createCallLogger(r, builder, bs, logger, 
thrownStore);
-                       bs.addBean(RestLogger.class, callLogger);
+                       Object r = resource.get();
 
                        partSerializer = createPartSerializer(r, builder, bs);
                        bs.addBean(HttpPartSerializer.class, partSerializer);
@@ -627,146 +621,6 @@ public class RestContext extends Context {
        }
 
        /**
-        * Instantiates the call logger this REST resource.
-        *
-        * <p>
-        * Instantiates based on the following logic:
-        * <ul>
-        *      <li>Returns the resource class itself is an instance of 
RestLogger.
-        *      <li>Looks for REST call logger set via any of the following:
-        *              <ul>
-        *                      <li>{@link 
RestContextBuilder#callLogger(Class)}/{@link 
RestContextBuilder#callLogger(RestLogger)}
-        *                      <li>{@link Rest#callLogger()}.
-        *              </ul>
-        *      <li>Looks for a static or non-static <c>createCallLogger()</> 
method that returns {@link RestLogger} on the
-        *              resource class with any of the following arguments:
-        *              <ul>
-        *                      <li>{@link RestContext}
-        *                      <li>{@link BeanStore}
-        *                      <li>{@link BasicFileFinder}
-        *                      <li>Any {@doc RestInjection injected beans}.
-        *              </ul>
-        *      <li>Resolves it via the bean store registered in this context.
-        *      <li>Looks for {@link 
RestContextBuilder#callLoggerDefault(RestLogger)}.
-        *      <li>Instantiates a {@link BasicFileFinder}.
-        * </ul>
-        *
-        * <ul class='seealso'>
-        *      <li class='jm'>{@link RestContextBuilder#callLogger(Class)}
-        *      <li class='jm'>{@link RestContextBuilder#callLogger(RestLogger)}
-        * </ul>
-        *
-        * @param resource
-        *      The REST servlet or bean that this context defines.
-        * @param builder
-        *      The builder for this object.
-        * @param beanStore
-        *      The factory used for creating beans and retrieving injected 
beans.
-        *      <br>Created by {@link RestContextBuilder#beanStore()}.
-        * @param logger
-        *      The Java logger to use for logging messages.
-        * @param thrownStore
-        *      The thrown exception statistics store.
-        * @return The file finder for this REST resource.
-        * @throws Exception If file finder could not be instantiated.
-        */
-       protected RestLogger createCallLogger(Object resource, 
RestContextBuilder builder, BeanStore beanStore, Logger logger, ThrownStore 
thrownStore) throws Exception {
-
-               RestLogger x = null;
-
-               if (resource instanceof RestLogger)
-                       x = (RestLogger)resource;
-
-               if (x == null)
-                       x = builder.callLogger.value().orElse(null);
-
-               if (x == null)
-                       x = beanStore.getBean(RestLogger.class).orElse(null);
-
-               if (x == null)
-                       x = builder.callLoggerDefault.value().orElse(null);
-
-               if (x == null)
-                       x = createCallLoggerBuilder(resource, builder, 
beanStore, logger, thrownStore).build();
-
-               x = BeanStore
-                       .of(beanStore, resource)
-                       .addBean(RestLogger.class, x)
-                       .beanCreateMethodFinder(RestLogger.class, resource)
-                       .find("createCallLogger")
-                       .withDefault(x)
-                       .run();
-
-               return x;
-       }
-
-       /**
-        * Instantiates the call logger builder for this REST resource.
-        *
-        * <p>
-        * Allows subclasses to intercept and modify the builder used by the 
{@link 
#createCallLogger(Object,RestContextBuilder,BeanStore,Logger,ThrownStore)} 
method.
-        *
-        * @param resource
-        *      The REST servlet or bean that this context defines.
-        * @param builder
-        *      The builder for this object.
-        * @param beanStore
-        *      The factory used for creating beans and retrieving injected 
beans.
-        *      <br>Created by {@link RestContextBuilder#beanStore()}.
-        * @param logger
-        *      The Java logger to use for logging messages.
-        * @param thrownStore
-        *      The thrown exception statistics store.
-        * @return The call logger builder for this REST resource.
-        * @throws Exception If call logger builder could not be instantiated.
-        */
-       protected RestLoggerBuilder createCallLoggerBuilder(Object resource, 
RestContextBuilder builder, BeanStore beanStore, Logger logger, ThrownStore 
thrownStore) throws Exception {
-
-               Class<? extends RestLogger> c = 
builder.callLogger.type().orElse(null);
-
-               if (c == null)
-                       c = builder.callLoggerDefault.type().orElse(null);
-
-               RestLoggerBuilder x = RestLogger
-                       .create()
-                       .beanStore(beanStore)
-                       .implClass(c)
-                       .normalRules(  // Rules when debugging is not enabled.
-                               RestLoggerRule.create()  // Log 500+ errors 
with status-line and header information.
-                                       .statusFilter(a -> a >= 500)
-                                       .level(SEVERE)
-                                       .requestDetail(HEADER)
-                                       .responseDetail(HEADER)
-                                       .build(),
-                               RestLoggerRule.create()  // Log 400-500 errors 
with just status-line information.
-                                       .statusFilter(a -> a >= 400)
-                                       .level(WARNING)
-                                       .requestDetail(STATUS_LINE)
-                                       .responseDetail(STATUS_LINE)
-                                       .build()
-                       )
-                       .debugRules(  // Rules when debugging is enabled.
-                               RestLoggerRule.create()  // Log everything with 
full details.
-                                       .level(SEVERE)
-                                       .requestDetail(ENTITY)
-                                       .responseDetail(ENTITY)
-                                       .build()
-                       )
-                       .logger(logger)
-                       .thrownStore(thrownStore);
-
-               x = BeanStore
-                       .of(beanStore, resource)
-                       .addBean(RestLoggerBuilder.class, x)
-                       .beanCreateMethodFinder(RestLoggerBuilder.class, 
resource)
-                       .find("createCallLoggerBuilder")
-                       .withDefault(x)
-                       .run();
-
-               return x;
-       }
-
-       /**
         * Instantiates the HTTP part serializer for this REST resource.
         *
         * <p>
@@ -1916,8 +1770,7 @@ public class RestContext extends Context {
         * Returns the call logger to use for this resource.
         *
         * <ul class='seealso'>
-        *      <li class='jm'>{@link RestContextBuilder#callLogger(Class)}
-        *      <li class='jm'>{@link RestContextBuilder#callLogger(RestLogger)}
+        *      <li class='jm'>{@link RestContextBuilder#callLogger()}
         * </ul>
         *
         * @return
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 b0518bc..0b56553 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
@@ -20,9 +20,11 @@ import static org.apache.juneau.internal.ObjectUtils.*;
 import static org.apache.juneau.internal.StringUtils.*;
 import static org.apache.juneau.parser.Parser.*;
 import static org.apache.juneau.rest.HttpRuntimeException.*;
+import static org.apache.juneau.rest.logging.RestLoggingDetail.*;
 import static org.apache.juneau.serializer.Serializer.*;
 import static java.util.Arrays.*;
 import static java.util.Optional.*;
+import static java.util.logging.Level.*;
 
 import java.lang.annotation.*;
 import java.lang.reflect.Method;
@@ -119,6 +121,8 @@ public class RestContextBuilder extends ContextBuilder 
implements ServletConfig
        final ServletConfig inner;
        final Class<?> resourceClass;
        final RestContext parentContext;
+
+       private DefaultClassList defaultClasses;
        private BeanStore beanStore;
        private Config config;
        private VarResolver.Builder varResolver;
@@ -127,6 +131,7 @@ public class RestContextBuilder extends ContextBuilder 
implements ServletConfig
        private MethodExecStore.Builder methodExecStore;
        private Messages.Builder messages;
        private ResponseProcessorList.Builder responseProcessors;
+       private RestLogger.Builder callLogger;
 
        String
                allowedHeaderParams = env("RestContext.allowedHeaderParams", 
"Accept,Content-Type"),
@@ -150,8 +155,6 @@ public class RestContextBuilder extends ContextBuilder 
implements ServletConfig
        Class<? extends RestOperations> operationsClass = RestOperations.class;
 
        BeanRef<SwaggerProvider> swaggerProvider = 
BeanRef.of(SwaggerProvider.class);
-       BeanRef<RestLogger> callLoggerDefault = BeanRef.of(RestLogger.class);
-       BeanRef<RestLogger> callLogger = BeanRef.of(RestLogger.class);
        BeanRef<DebugEnablement> debugEnablement = 
BeanRef.of(DebugEnablement.class);
        BeanRef<StaticFiles> staticFiles = BeanRef.of(StaticFiles.class);
        BeanRef<StaticFiles> staticFilesDefault = BeanRef.of(StaticFiles.class);
@@ -233,10 +236,12 @@ public class RestContextBuilder extends ContextBuilder 
implements ServletConfig
 
                        // Pass-through default values.
                        if (parentContext != null) {
-                               callLoggerDefault = 
parentContext.callLoggerDefault;
                                debugDefault = parentContext.debugDefault;
                                
staticFilesDefault.value(parentContext.staticFilesDefault);
                                
fileFinderDefault.value(parentContext.fileFinderDefault);
+                               defaultClasses = 
parentContext.defaultClasses.copy();
+                       } else {
+                               defaultClasses = DefaultClassList.create();
                        }
 
                        beanStore = createBeanStore(resourceClass, 
parentContext)
@@ -351,6 +356,29 @@ public class RestContextBuilder extends ContextBuilder 
implements ServletConfig
        }
 
        /**
+        * Returns access to the default classes list.
+        *
+        * <p>
+        * This defines the implementation classes for a variety of bean types.
+        *
+        * @return The default classes list for this builder.
+        */
+       public DefaultClassList defaultClasses() {
+               return defaultClasses;
+       }
+
+       /**
+        * Adds default implementation classes to use.
+        *
+        * @param values The values to add to the list of default classes.
+        * @return This object.
+        */
+       public RestContextBuilder defaultClasses(Class<?>...values) {
+               defaultClasses().add(values);
+               return this;
+       }
+
+       /**
         * Returns access to the bean store being used by this builder.
         *
         * <p>
@@ -489,18 +517,6 @@ public class RestContextBuilder extends ContextBuilder 
implements ServletConfig
        }
 
        /**
-        * Sets the variable resolver for this builder.
-        *
-        * @param value The new variable resolver.
-        * @return This object (for method chaining).
-        */
-       @FluentSetter
-       public RestContextBuilder varResolver(VarResolver.Builder value) {
-               varResolver = value;
-               return this;
-       }
-
-       /**
         * Creates the var resolver builder.
         *
         * <p>
@@ -804,18 +820,6 @@ public class RestContextBuilder extends ContextBuilder 
implements ServletConfig
        }
 
        /**
-        * Sets the builder for the {@link ThrownStore} object in the REST 
context.
-        *
-        * @param value The builder for the {@link ThrownStore} object in the 
REST context.
-        * @return This object.
-        * @throws RuntimeException If {@link #init(Object)} has not been 
called.
-        */
-       public final RestContextBuilder thrownStore(ThrownStore value) {
-               thrownStore().impl(value);
-               return this;
-       }
-
-       /**
         * Instantiates the thrown exception store for this REST resource.
         *
         * <p>
@@ -866,6 +870,9 @@ public class RestContextBuilder extends ContextBuilder 
implements ServletConfig
                        );
                }
 
+               // Specify the implementation class if its set as a default.
+               defaultClasses().get(ThrownStore.class).ifPresent(x -> 
v.get().implClass(x));
+
                BeanStore
                        .of(beanStore, r)
                        .addBean(ThrownStore.Builder.class, v.get())
@@ -889,18 +896,6 @@ public class RestContextBuilder extends ContextBuilder 
implements ServletConfig
        }
 
        /**
-        * Sets the builder for the {@link MethodExecStore} object in the REST 
context.
-        *
-        * @param value The builder for the {@link MethodExecStore} object in 
the REST context.
-        * @return This object.
-        * @throws RuntimeException If {@link #init(Object)} has not been 
called.
-        */
-       public final RestContextBuilder methodExecStore(MethodExecStore value) {
-               methodExecStore().impl(value);
-               return this;
-       }
-
-       /**
         * Instantiates the method execution statistics store for this REST 
resource.
         *
         * @param beanStore
@@ -932,6 +927,9 @@ public class RestContextBuilder extends ContextBuilder 
implements ServletConfig
                        );
                }
 
+               // Specify the implementation class if its set as a default.
+               defaultClasses().get(MethodExecStore.class).ifPresent(x -> 
v.get().implClass(x));
+
                BeanStore
                        .of(beanStore, r)
                        .addBean(MethodExecStore.Builder.class, v.get())
@@ -955,18 +953,6 @@ public class RestContextBuilder extends ContextBuilder 
implements ServletConfig
        }
 
        /**
-        * Sets the builder for the {@link MethodExecStore} object in the REST 
context.
-        *
-        * @param value The builder for the {@link MethodExecStore} object in 
the REST context.
-        * @return This object.
-        * @throws RuntimeException If {@link #init(Object)} has not been 
called.
-        */
-       public final RestContextBuilder messages(Messages value) {
-               messages().impl(value);
-               return this;
-       }
-
-       /**
         * Instantiates the messages for this REST object.
         *
         * <p>
@@ -1171,18 +1157,6 @@ public class RestContextBuilder extends ContextBuilder 
implements ServletConfig
        }
 
        /**
-        * Sets the builder for the {@link ResponseProcessorList} object in the 
REST context.
-        *
-        * @param value The builder for the {@link ResponseProcessorList} 
object in the REST context.
-        * @return This object.
-        * @throws RuntimeException If {@link #init(Object)} has not been 
called.
-        */
-       public final RestContextBuilder 
responseProcessors(ResponseProcessorList value) {
-               responseProcessors().impl(value);
-               return this;
-       }
-
-       /**
         * Instantiates the response handlers for this REST resource.
         *
         * <p>
@@ -1257,7 +1231,170 @@ public class RestContextBuilder extends ContextBuilder 
implements ServletConfig
                return v.get();
        }
 
+       /**
+        * Returns the builder for the {@link RestLogger} object in the REST 
context.
+        *
+        * <p>
+        * Specifies the logger to use for logging of HTTP requests and 
responses.
+        *
+        * <h5 class='section'>Example:</h5>
+        * <p class='bcode w800'>
+        *      <jc>// Our customized logger.</jc>
+        *      <jk>public class</jk> MyLogger <jk>extends</jk> BasicRestLogger 
{
+        *
+        *              <ja>@Override</ja>
+        *                      <jk>protected void</jk> log(Level 
<jv>level</jv>, String <jv>msg</jv>, Throwable <jv>e</jv>) {
+        *                      <jc>// Handle logging ourselves.</jc>
+        *              }
+        *      }
+        *
+        *      <jc>// Option #1 - Registered via annotation resolving to a 
config file setting with default value.</jc>
+        *      <ja>@Rest</ja>(callLogger=MyLogger.<jk>class</jk>)
+        *      <jk>public class</jk> MyResource {
+        *
+        *              <jc>// Option #2 - Registered via builder passed in 
through resource constructor.</jc>
+        *              <jk>public</jk> MyResource(RestContextBuilder 
<jv>builder</jv>) <jk>throws</jk> Exception {
+        *
+        *                      <jc>// Using method on builder.</jc>
+        *                      
<jv>builder</jv>.callLogger(MyLogger.<jk>class</jk>);
+        *              }
+        *
+        *              <jc>// Option #3 - Registered 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>.callLogger(MyLogger.<jk>class</jk>);
+        *              }
+        *      }
+        * </p>
+        *
+        * <ul class='notes'>
+        *      <li>
+        *              The default call logger if not specified is {@link 
BasicRestLogger}.
+        *      <li>
+        *              The resource class itself will be used if it implements 
the {@link RestLogger} interface and not
+        *              explicitly overridden via this annotation.
+        *      <li>
+        *              When defined as a class, the implementation must have 
one of the following constructors:
+        *              <ul>
+        *                      <li><code><jk>public</jk> T(RestContext)</code>
+        *                      <li><code><jk>public</jk> T()</code>
+        *                      <li><code><jk>public static</jk> T 
<jsm>create</jsm>(RestContext)</code>
+        *                      <li><code><jk>public static</jk> T 
<jsm>create</jsm>()</code>
+        *              </ul>
+        *      <li>
+        *              Inner classes of the REST resource class are allowed.
+        * </ul>
+        *
+        * <ul class='seealso'>
+        *      <li class='link'>{@doc RestLoggingAndDebugging}
+        *      <li class='ja'>{@link Rest#callLogger()}
+        * </ul>
+        *
+        * @return The builder for the {@link RestLogger} object in the REST 
context.
+        * @throws RuntimeException If {@link #init(Object)} has not been 
called.
+        */
+       public final RestLogger.Builder callLogger() {
+               if (callLogger == null)
+                       callLogger = createCallLogger(beanStore(), resource());
+               return callLogger;
+       }
 
+       /**
+        * Instantiates the call logger this REST resource.
+        *
+        * <p>
+        * Instantiates based on the following logic:
+        * <ul>
+        *      <li>Returns the resource class itself is an instance of 
RestLogger.
+        *      <li>Looks for REST call logger set via any of the following:
+        *              <ul>
+        *                      <li>{@link RestContextBuilder#callLogger()}
+        *                      <li>{@link Rest#callLogger()}.
+        *              </ul>
+        *      <li>Looks for a static or non-static <c>createCallLogger()</> 
method that returns {@link RestLogger} on the
+        *              resource class with any of the following arguments:
+        *              <ul>
+        *                      <li>{@link RestContext}
+        *                      <li>{@link BeanStore}
+        *                      <li>{@link BasicFileFinder}
+        *                      <li>Any {@doc RestInjection injected beans}.
+        *              </ul>
+        *      <li>Resolves it via the bean store registered in this context.
+        *      <li>Instantiates a {@link BasicFileFinder}.
+        * </ul>
+        *
+        * <ul class='seealso'>
+        *      <li class='jm'>{@link RestContextBuilder#callLogger()}
+        * </ul>
+        *
+        * @param beanStore
+        *      The factory used for creating beans and retrieving injected 
beans.
+        * @param resource
+        *      The REST servlet or bean that this context defines.
+        * @return The call logger builder for this REST resource.
+        */
+       protected RestLogger.Builder createCallLogger(BeanStore beanStore, 
Supplier<?> resource) {
+
+               Value<RestLogger.Builder> v = Value.empty();
+               Object r = resource.get();
+
+               beanStore.getBean(RestLogger.Builder.class).map(x -> 
x.copy()).ifPresent(x-> v.set(x));
+
+               BeanStore
+                       .of(beanStore, r)
+                       .addBean(RestLogger.Builder.class, v.get())
+                       .beanCreateMethodFinder(RestLogger.Builder.class, 
resource)
+                       .find("createCallLogger")
+                       .execute()
+                       .ifPresent(x -> v.set(x));
+
+               if (v.isEmpty()) {
+                       v.set(
+                               RestLogger
+                                       .create()
+                                       .beanStore(beanStore)
+                                       .normalRules(  // Rules when debugging 
is not enabled.
+                                               RestLoggerRule.create()  // Log 
500+ errors with status-line and header information.
+                                                       .statusFilter(a -> a >= 
500)
+                                                       .level(SEVERE)
+                                                       .requestDetail(HEADER)
+                                                       .responseDetail(HEADER)
+                                                       .build(),
+                                               RestLoggerRule.create()  // Log 
400-500 errors with just status-line information.
+                                                       .statusFilter(a -> a >= 
400)
+                                                       .level(WARNING)
+                                                       
.requestDetail(STATUS_LINE)
+                                                       
.responseDetail(STATUS_LINE)
+                                                       .build()
+                                       )
+                                       .debugRules(  // Rules when debugging 
is enabled.
+                                               RestLoggerRule.create()  // Log 
everything with full details.
+                                                       .level(SEVERE)
+                                                       .requestDetail(ENTITY)
+                                                       .responseDetail(ENTITY)
+                                                       .build()
+                                       )
+                       );
+               }
+
+               if (r instanceof RestLogger)
+                       v.get().impl((RestLogger)r);
+
+               beanStore.getBean(RestLogger.class).ifPresent(x-> 
v.get().impl(x));
+
+               // Specify the implementation class if its set as a default.
+               defaultClasses().get(RestLogger.class).ifPresent(x -> 
v.get().implClass(x));
+
+               BeanStore
+                       .of(beanStore, r)
+                       .addBean(RestLogger.Builder.class, v.get())
+                       .beanCreateMethodFinder(RestLogger.class, resource)
+                       .find("createCallLogger")
+                       .execute()
+                       .ifPresent(x -> v.get().impl(x));
+
+               return v.get();
+       }
 
        
//----------------------------------------------------------------------------------------------------
        // Methods that give access to the config file, var resolver, and 
properties.
@@ -1562,138 +1699,6 @@ public class RestContextBuilder extends ContextBuilder 
implements ServletConfig
        }
 
        /**
-        * REST call logger.
-        *
-        * <p>
-        * Specifies the logger to use for logging of HTTP requests and 
responses.
-        *
-        * <h5 class='section'>Example:</h5>
-        * <p class='bcode w800'>
-        *      <jc>// Our customized logger.</jc>
-        *      <jk>public class</jk> MyLogger <jk>extends</jk> BasicRestLogger 
{
-        *
-        *              <ja>@Override</ja>
-        *                      <jk>protected void</jk> log(Level 
<jv>level</jv>, String <jv>msg</jv>, Throwable <jv>e</jv>) {
-        *                      <jc>// Handle logging ourselves.</jc>
-        *              }
-        *      }
-        *
-        *      <jc>// Option #1 - Registered via annotation resolving to a 
config file setting with default value.</jc>
-        *      <ja>@Rest</ja>(callLogger=MyLogger.<jk>class</jk>)
-        *      <jk>public class</jk> MyResource {
-        *
-        *              <jc>// Option #2 - Registered via builder passed in 
through resource constructor.</jc>
-        *              <jk>public</jk> MyResource(RestContextBuilder 
<jv>builder</jv>) <jk>throws</jk> Exception {
-        *
-        *                      <jc>// Using method on builder.</jc>
-        *                      
<jv>builder</jv>.callLogger(MyLogger.<jk>class</jk>);
-        *              }
-        *
-        *              <jc>// Option #3 - Registered 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>.callLogger(MyLogger.<jk>class</jk>);
-        *              }
-        *      }
-        * </p>
-        *
-        * <ul class='notes'>
-        *      <li>
-        *              The default call logger if not specified is {@link 
BasicRestLogger} unless overwritten by {@link 
RestContextBuilder#callLoggerDefault(RestLogger)}.
-        *      <li>
-        *              The resource class itself will be used if it implements 
the {@link RestLogger} interface and not
-        *              explicitly overridden via this annotation.
-        *      <li>
-        *              When defined as a class, the implementation must have 
one of the following constructors:
-        *              <ul>
-        *                      <li><code><jk>public</jk> T(RestContext)</code>
-        *                      <li><code><jk>public</jk> T()</code>
-        *                      <li><code><jk>public static</jk> T 
<jsm>create</jsm>(RestContext)</code>
-        *                      <li><code><jk>public static</jk> T 
<jsm>create</jsm>()</code>
-        *              </ul>
-        *      <li>
-        *              Inner classes of the REST resource class are allowed.
-        * </ul>
-        *
-        * <ul class='seealso'>
-        *      <li class='link'>{@doc RestLoggingAndDebugging}
-        *      <li class='ja'>{@link Rest#callLogger()}
-        * </ul>
-        *
-        * @param value
-        *      The new value for this setting.
-        *      <br>The default is {@link BasicRestLogger}.
-        * @return This object (for method chaining).
-        */
-       @FluentSetter
-       public RestContextBuilder callLogger(Class<? extends RestLogger> value) 
{
-               callLogger.type(value);
-               return this;
-       }
-
-       /**
-        * REST call logger.
-        *
-        * <p>
-        * Same as {@link #callLogger(Class)} but specifies an 
already-instantiated call logger.
-        *
-        * <ul class='seealso'>
-        *      <li class='link'>{@doc RestLoggingAndDebugging}
-        *      <li class='ja'>{@link Rest#callLogger()}
-        * </ul>
-        *
-        * @param value
-        *      The new value for this setting.
-        *      <br>The default is {@link BasicRestLogger}.
-        * @return This object (for method chaining).
-        */
-       @FluentSetter
-       public RestContextBuilder callLogger(RestLogger value) {
-               callLogger.value(value);
-               return this;
-       }
-
-       /**
-        * Default REST call logger.
-        *
-        * <p>
-        * The default logger to use if one is not specified.
-        *
-        * <p>
-        * This logger is inherited by child resources if not specified on 
those resources.
-        *
-        * @param value
-        *      The new value for this setting.
-        *      <br>The default is {@link BasicRestLogger}.
-        * @return This object (for method chaining).
-        */
-       @FluentSetter
-       public RestContextBuilder callLoggerDefault(Class<? extends RestLogger> 
value) {
-               callLoggerDefault.type(value);
-               return this;
-       }
-
-       /**
-        * Default REST call logger.
-        *
-        * <p>
-        * The default logger to use if one is not specified.
-        *
-        * <p>
-        * This logger is inherited by child resources if not specified on 
those resources.
-        *
-        * @param value
-        *      The new value for this setting.
-        *      <br>The default is {@link BasicRestLogger}.
-        * @return This object (for method chaining).
-        */
-       @FluentSetter
-       public RestContextBuilder callLoggerDefault(RestLogger value) {
-               callLoggerDefault.value(value);
-               return this;
-       }
-
-       /**
         * Child REST resources.
         *
         * <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 4765ad2..c659545 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
@@ -198,8 +198,7 @@ public @interface Rest {
         * </ul>
         *
         * <ul class='seealso'>
-        *      <li class='jm'>{@link RestContextBuilder#callLogger(Class)}
-        *      <li class='jm'>{@link RestContextBuilder#callLogger(RestLogger)}
+        *      <li class='jm'>{@link RestContextBuilder#callLogger()}
         *      <li class='link'>{@doc RestLoggingAndDebugging}
         * </ul>
         */
diff --git 
a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/annotation/RestAnnotation.java
 
b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/annotation/RestAnnotation.java
index 55157e4..2219373 100644
--- 
a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/annotation/RestAnnotation.java
+++ 
b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/annotation/RestAnnotation.java
@@ -1072,7 +1072,7 @@ public class RestAnnotation {
                        type(a.staticFiles()).ifPresent(x -> b.staticFiles(x));
                        string(a.path()).ifPresent(x -> b.path(x));
                        string(a.clientVersionHeader()).ifPresent(x -> 
b.clientVersionHeader(x));
-                       type(a.callLogger()).ifPresent(x -> b.callLogger(x));
+                       type(a.callLogger()).ifPresent(x -> 
b.callLogger().implClass(x));
                        type(a.swaggerProvider()).ifPresent(x -> 
b.swaggerProvider(x));
                        type(a.restOpContextClass()).ifPresent(x -> 
b.restOpContextClass(x));
                        type(a.restChildrenClass()).ifPresent(x -> 
b.restChildrenClass(x));
diff --git 
a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/logging/BasicRestLogger.java
 
b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/logging/BasicRestLogger.java
index d601e53..373e416 100644
--- 
a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/logging/BasicRestLogger.java
+++ 
b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/logging/BasicRestLogger.java
@@ -82,10 +82,7 @@ import org.apache.juneau.rest.util.*;
  * </p>
  *
  * <ul class='seealso'>
- *     <li class='jm'>{@link RestContextBuilder#callLogger(Class)}
- *     <li class='jm'>{@link RestContextBuilder#callLogger(RestLogger)}
- *     <li class='jm'>{@link RestContextBuilder#callLoggerDefault(Class)}
- *     <li class='jm'>{@link RestContextBuilder#callLoggerDefault(RestLogger)}
+ *     <li class='jm'>{@link RestContextBuilder#callLogger()}
  *     <li class='jm'>{@link RestContextBuilder#debug(Enablement)}
  *     <li class='jm'>{@link RestContextBuilder#debugOn(String)}
  *     <li class='ja'>{@link Rest#debug}
@@ -110,7 +107,7 @@ public class BasicRestLogger implements RestLogger {
         *
         * @param builder The builder object.
         */
-       public BasicRestLogger(RestLoggerBuilder builder) {
+       public BasicRestLogger(RestLogger.Builder builder) {
                this.logger = firstNonNull(builder.logger, 
Logger.getLogger(getProperty(String.class, SP_logger, "global")));
                this.thrownStore = builder.thrownStore;
                this.normalRules = builder.normalRules.toArray(new 
RestLoggerRule[builder.normalRules.size()]);
diff --git 
a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/logging/BasicTestCaptureRestLogger.java
 
b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/logging/BasicTestCaptureRestLogger.java
index 99b80c1..ec70a16 100644
--- 
a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/logging/BasicTestCaptureRestLogger.java
+++ 
b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/logging/BasicTestCaptureRestLogger.java
@@ -74,7 +74,7 @@ public class BasicTestCaptureRestLogger extends 
BasicRestLogger {
         *
         * @param builder The settings to use for this logger.
         */
-       public BasicTestCaptureRestLogger(RestLoggerBuilder builder) {
+       public BasicTestCaptureRestLogger(RestLogger.Builder builder) {
                super(builder);
        }
 
@@ -87,7 +87,7 @@ public class BasicTestCaptureRestLogger extends 
BasicRestLogger {
                super(builder());
        }
 
-       private static RestLoggerBuilder builder() {
+       private static RestLogger.Builder builder() {
                return RestLogger.create()
                        .normalRules(  // Rules when debugging is not enabled.
                                RestLoggerRule.create()  // Log 500+ errors 
with status-line and header information.
diff --git 
a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/logging/BasicTestRestLogger.java
 
b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/logging/BasicTestRestLogger.java
index e4836d2..1a88e62 100644
--- 
a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/logging/BasicTestRestLogger.java
+++ 
b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/logging/BasicTestRestLogger.java
@@ -58,7 +58,7 @@ public class BasicTestRestLogger extends BasicRestLogger {
                
super(builder().logger(context.getLogger()).thrownStore(context.getThrownStore()));
        }
 
-       private static RestLoggerBuilder builder() {
+       private static RestLogger.Builder builder() {
                return RestLogger.create()
                        .normalRules(  // Rules when debugging is not enabled.
                                RestLoggerRule.create()  // Log 500+ errors 
with status-line and header information.
diff --git 
a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/logging/RestLogger.java
 
b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/logging/RestLogger.java
index ac376e4..625febe 100644
--- 
a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/logging/RestLogger.java
+++ 
b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/logging/RestLogger.java
@@ -12,12 +12,21 @@
 // 
***************************************************************************************************************************
 package org.apache.juneau.rest.logging;
 
+import static org.apache.juneau.Enablement.*;
+import static org.apache.juneau.internal.ClassUtils.*;
+import static org.apache.juneau.rest.HttpRuntimeException.*;
+
+import java.util.*;
 import java.util.function.*;
 import java.util.logging.*;
 
 import javax.servlet.http.*;
 
 import org.apache.juneau.*;
+import org.apache.juneau.collections.*;
+import org.apache.juneau.cp.*;
+import org.apache.juneau.http.response.*;
+import org.apache.juneau.mstat.*;
 import org.apache.juneau.rest.*;
 import org.apache.juneau.rest.annotation.*;
 
@@ -25,7 +34,7 @@ import org.apache.juneau.rest.annotation.*;
  * Interface class used for logging HTTP requests.
  *
  * <p>
- * The {@link RestLoggerBuilder#implClass(Class)} method has been provided for 
easy extension of this class.
+ * The {@link Builder#implClass(Class)} method has been provided for easy 
extension of this class.
  *
  * <p>
  * The following default implementations are also provided:
@@ -37,10 +46,7 @@ import org.apache.juneau.rest.annotation.*;
  * </ul>
  *
  * <ul class='seealso'>
- *     <li class='jm'>{@link RestContextBuilder#callLogger(Class)}
- *     <li class='jm'>{@link RestContextBuilder#callLogger(RestLogger)}
- *     <li class='jm'>{@link RestContextBuilder#callLoggerDefault(Class)}
- *     <li class='jm'>{@link RestContextBuilder#callLoggerDefault(RestLogger)}
+ *     <li class='jm'>{@link RestContextBuilder#callLogger()}
  *     <li class='jm'>{@link RestContextBuilder#debug(Enablement)}
  *     <li class='jm'>{@link RestContextBuilder#debugOn(String)}
  *     <li class='ja'>{@link Rest#debug}
@@ -71,7 +77,7 @@ public interface RestLogger {
         * <ul>
         *      <li>{@link Enablement#ALWAYS "ALWAYS"} (default) - Logging is 
enabled.
         *      <li>{@link Enablement#NEVER "NEVER"} - Logging is disabled.
-        *      <li>{@link Enablement#CONDITIONAL "CONDITIONALLY"} - Logging is 
enabled if it passes the {@link RestLoggerBuilder#enabledTest(Predicate)} test.
+        *      <li>{@link Enablement#CONDITIONAL "CONDITIONALLY"} - Logging is 
enabled if it passes the {@link Builder#enabledTest(Predicate)} test.
         * </ul>
         */
        public static final String SP_enabled = "juneau.restLogger.enabled";
@@ -128,8 +134,389 @@ public interface RestLogger {
         *
         * @return A new builder for this object.
         */
-       public static RestLoggerBuilder create() {
-               return new RestLoggerBuilder();
+       public static Builder create() {
+               return new Builder();
+       }
+
+       /**
+        * The builder for this object.
+        */
+       public static class Builder {
+
+               Logger logger;
+               ThrownStore thrownStore;
+               List<RestLoggerRule> normalRules = AList.create(), debugRules = 
AList.create();
+               Enablement enabled;
+               Predicate<HttpServletRequest> enabledTest;
+               RestLoggingDetail requestDetail, responseDetail;
+               Level level;
+               BeanStore beanStore;
+               Class<? extends RestLogger> implClass;
+               RestLogger impl;
+
+               /**
+                * Constructor.
+                */
+               protected Builder() {}
+
+               /**
+                * Copy constuctor.
+                *
+                * @param copyFrom The builder to copy.
+                */
+               protected Builder(Builder copyFrom) {
+                       logger = copyFrom.logger;
+                       thrownStore = copyFrom.thrownStore;
+                       normalRules = 
AList.<RestLoggerRule>create().append(copyFrom.normalRules);
+                       debugRules = 
AList.<RestLoggerRule>create().append(copyFrom.debugRules);
+                       enabled = copyFrom.enabled;
+                       enabledTest = copyFrom.enabledTest;
+                       requestDetail = copyFrom.requestDetail;
+                       responseDetail = copyFrom.responseDetail;
+                       level = copyFrom.level;
+                       beanStore = copyFrom.beanStore;
+                       implClass = copyFrom.implClass;
+                       impl = copyFrom.impl;
+               }
+
+               /**
+                * Creates a new {@link RestLogger} object from this builder.
+                *
+                * <p>
+                * Instantiates an instance of the {@link #implClass(Class) 
implementation class} or
+                * else {@link BasicRestLogger} if implementation class was not 
specified.
+                *
+                * @return A new {@link RestLogger} object.
+                */
+               public RestLogger build() {
+                       try {
+                               if (impl != null)
+                                       return impl;
+                               Class<? extends RestLogger> ic = 
isConcrete(implClass) ? implClass : BasicRestLogger.class;
+                               return 
BeanStore.of(beanStore).addBeans(Builder.class, this).createBean(ic);
+                       } catch (Exception e) {
+                               throw toHttpException(e, 
InternalServerError.class);
+                       }
+               }
+
+               /**
+                * Specifies the bean store to use for instantiating the {@link 
RestLogger} object.
+                *
+                * @param value The new value for this setting.
+                * @return  This object.
+                */
+               public Builder beanStore(BeanStore value) {
+                       beanStore = value;
+                       return this;
+               }
+
+               /**
+                * Specifies a subclass of {@link RestLogger} to create when 
the {@link #build()} method is called.
+                *
+                * @param value The new value for this setting.
+                * @return  This object.
+                */
+               public Builder implClass(Class<? extends RestLogger> value) {
+                       implClass = value;
+                       return this;
+               }
+
+               /**
+                * Specifies the logger to use for logging the request.
+                *
+                * <p>
+                * If not specified, the logger name is determined in the 
following order:
+                * <ol>
+                *      <li><js>{@link RestLogger#SP_logger 
"juneau.restLogger.logger"} system property.
+                *      <li><js>{@link RestLogger#SP_logger 
"JUNEAU_RESTLOGGER_LOGGER"} environment variable.
+                *      <li><js>"global"</js>.
+                * </ol>
+                *
+                * <p>
+                * The {@link BasicRestLogger#getLogger()} method can also be 
overridden to provide different logic.
+                *
+                * @param value
+                *      The logger to use for logging the request.
+                * @return This object.
+                */
+               public Builder logger(Logger value) {
+                       logger = value;
+                       return this;
+               }
+
+               /**
+                * Specifies the logger to use for logging the request.
+                *
+                * <p>
+                * Shortcut for calling 
<c>logger(Logger.<jsm>getLogger</jsm>(value))</c>.
+                *
+                * <p>
+                * If not specified, the logger name is determined in the 
following order:
+                * <ol>
+                *      <li><js>{@link RestLogger#SP_logger 
"juneau.restLogger.logger"} system property.
+                *      <li><js>{@link RestLogger#SP_logger 
"JUNEAU_RESTLOGGER_LOGGER"} environment variable.
+                *      <li><js>"global"</js>.
+                * </ol>
+                *
+                * <p>
+                * The {@link BasicRestLogger#getLogger()} method can also be 
overridden to provide different logic.
+                *
+                * @param value
+                *      The logger to use for logging the request.
+                * @return This object.
+                */
+               public Builder logger(String value) {
+                       logger = value == null ? null :Logger.getLogger(value);
+                       return this;
+               }
+
+               /**
+                * Same as {@link #logger(Logger)} but only sets the value if 
it's currently <jk>null</jk>.
+                *
+                * @param value The logger to use for logging the request.
+                * @return This object.
+                */
+               public Builder loggerOnce(Logger value) {
+                       if (logger == null)
+                               logger = value;
+                       return this;
+               }
+
+               /**
+                * Specifies the thrown exception store to use for getting 
stack trace information (hash IDs and occurrence counts).
+                *
+                * @param value
+                *      The stack trace store.
+                *      <br>If <jk>null</jk>, stack trace information will not 
be logged.
+                * @return This object.
+                */
+               public Builder thrownStore(ThrownStore value) {
+                       thrownStore = value;
+                       return this;
+               }
+
+               /**
+                * Same as {@link #thrownStore(ThrownStore)} but only sets the 
value if it's currently <jk>null</jk>.
+                *
+                * @param value
+                *      The stack trace store.
+                *      <br>If <jk>null</jk>, stack trace information will not 
be logged.
+                * @return This object.
+                */
+               public Builder thrownStoreOnce(ThrownStore value) {
+                       if (thrownStore == null)
+                               thrownStore = value;
+                       return this;
+               }
+               /**
+                * Specifies the default logging enablement setting.
+                *
+                * <p>
+                * This specifies the default logging enablement value if not 
set on the first matched rule or if no rules match.
+                *
+                * <p>
+                * The possible values are:
+                * <ul>
+                *      <li>{@link Enablement#ALWAYS ALWAYS} (default) - 
Logging is enabled.
+                *      <li>{@link Enablement#NEVER NEVER} - Logging is 
disabled.
+                *      <li>{@link Enablement#CONDITIONAL CONDITIONALLY} - 
Logging is enabled if it passes the {@link #enabledTest(Predicate)} test.
+                * </ul>
+                *
+                * <p>
+                * If not specified, the setting is determined via the 
following:
+                * <ul>
+                *      <li><js>{@link RestLogger#SP_enabled 
"juneau.restLogger.enabled"} system property.
+                *      <li><js>{@link RestLogger#SP_enabled 
"JUNEAU_RESTLOGGER_ENABLED"} environment variable.
+                *      <li><js>"ALWAYS"</js>.
+                * </ul>
+                *
+                * <p>
+                * @param value
+                *      The default enablement flag value.  Can be 
<jk>null</jk> to use the default.
+                * @return This object.
+                */
+               public Builder enabled(Enablement value) {
+                       enabled = value;
+                       return this;
+               }
+
+               /**
+                * Specifies the default logging enablement test predicate.
+                *
+                * <p>
+                * This specifies the default logging enablement test if not 
set on the first matched rule or if no rules match.
+                *
+                * <p>
+                * This setting has no effect if the enablement setting is not 
{@link Enablement#CONDITIONAL CONDITIONALLY}.
+                *
+                * <p>
+                * The default if not specified is <c><jv>x</jv> -> 
<jk>false</jk></c> (never log).
+                *
+                * @param value
+                *      The default enablement flag value.  Can be 
<jk>null</jk> to use the default.
+                * @return This object.
+                */
+               public Builder enabledTest(Predicate<HttpServletRequest> value) 
{
+                       enabledTest = value;
+                       return this;
+               }
+
+               /**
+                * Shortcut for calling <c>enabled(<jsf>NEVER</jsf>)</c>.
+                *
+                * @return This object.
+                */
+               public Builder disabled() {
+                       return enabled(NEVER);
+               }
+
+               /**
+                * The default level of detail to log on a request.
+                *
+                * <p>
+                * This specifies the default level of request detail if not 
set on the first matched rule or if no rules match.
+                *
+                * <p>
+                * The possible values are:
+                * <ul>
+                *      <li>{@link RestLoggingDetail#STATUS_LINE STATUS_LINE} - 
Log only the status line.
+                *      <li>{@link RestLoggingDetail#HEADER HEADER} - Log the 
status line and headers.
+                *      <li>{@link RestLoggingDetail#ENTITY ENTITY} - Log the 
status line and headers and body if available.
+                * </ul>
+                *
+                * <p>
+                * If not specified, the setting is determined via the 
following:
+                * <ul>
+                *      <li><js>{@link RestLogger#SP_requestDetail 
"juneau.restLogger.requestDetail"} system property.
+                *      <li><js>{@link RestLogger#SP_requestDetail 
"JUNEAU_RESTLOGGER_requestDetail"} environment variable.
+                *      <li><js>"STATUS_LINE"</js>.
+                * </ul>
+                *
+                * @param value
+                *      The new value for this property, or <jk>null</jk> to 
use the default.
+                * @return This object.
+                */
+               public Builder requestDetail(RestLoggingDetail value) {
+                       requestDetail = value;
+                       return this;
+               }
+
+               /**
+                * The default level of detail to log on a response.
+                *
+                * <p>
+                * This specifies the default level of response detail if not 
set on the first matched rule or if no rules match.
+                *
+                * <p>
+                * The possible values are:
+                * <ul>
+                *      <li>{@link RestLoggingDetail#STATUS_LINE STATUS_LINE} - 
Log only the status line.
+                *      <li>{@link RestLoggingDetail#HEADER HEADER} - Log the 
status line and headers.
+                *      <li>{@link RestLoggingDetail#ENTITY ENTITY} - Log the 
status line and headers and body if available.
+                * </ul>
+                *
+                * <p>
+                * If not specified, the setting is determined via the 
following:
+                * <ul>
+                *      <li><js>{@link RestLogger#SP_responseDetail 
"juneau.restLogger.responseDetail"} system property.
+                *      <li><js>{@link RestLogger#SP_responseDetail 
"JUNEAU_RESTLOGGER_responseDetail"} environment variable.
+                *      <li><js>"STATUS_LINE"</js>.
+                * </ul>
+                *
+                * @param value
+                *      The new value for this property, or <jk>null</jk> to 
use the default.
+                * @return This object.
+                */
+               public Builder responseDetail(RestLoggingDetail value) {
+                       responseDetail = value;
+                       return this;
+               }
+
+               /**
+                * The default logging level to use for logging the 
request/response.
+                *
+                * <p>
+                * This specifies the default logging level if not set on the 
first matched rule or if no rules match.
+                *
+                * <p>
+                * If not specified, the setting is determined via the 
following:
+                * <ul>
+                *      <li><js>{@link RestLogger#SP_level 
"juneau.restLogger.level"} system property.
+                *      <li><js>{@link RestLogger#SP_level 
"JUNEAU_RESTLOGGER_level"} environment variable.
+                *      <li><js>"OFF"</js>.
+                * </ul>
+                *
+                * @param value
+                *      The new value for this property, or <jk>null</jk> to 
use the default value.
+                * @return This object.
+                */
+               public Builder level(Level value) {
+                       level = value;
+                       return this;
+               }
+
+               /**
+                * Adds logging rules to use when debug mode is not enabled.
+                *
+                * <p>
+                * Logging rules are matched in the order they are added.  The 
first to match wins.
+                *
+                * @param values The logging rules to add to the list of rules.
+                * @return This object.
+                */
+               public Builder normalRules(RestLoggerRule...values) {
+                       for (RestLoggerRule rule : values)
+                               normalRules.add(rule);
+                       return this;
+               }
+
+               /**
+                * Adds logging rules to use when debug mode is enabled.
+                *
+                * <p>
+                * Logging rules are matched in the order they are added.  The 
first to match wins.
+                *
+                * @param values The logging rules to add to the list of rules.
+                * @return This object.
+                */
+               public Builder debugRules(RestLoggerRule...values) {
+                       for (RestLoggerRule rule : values)
+                               debugRules.add(rule);
+                       return this;
+               }
+
+               /**
+                * Shortcut for adding the same rules as normal and debug rules.
+                *
+                * <p>
+                * Logging rules are matched in the order they are added.  The 
first to match wins.
+                *
+                * @param values The logging rules to add to the list of rules.
+                * @return This object.
+                */
+               public Builder rules(RestLoggerRule...values) {
+                       return normalRules(values).debugRules(values);
+               }
+
+               /**
+                * Specifies an already-instantiated bean for the {@link 
#build()} method to return.
+                *
+                * @param value The value for this setting.
+                * @return This object.
+                */
+               public Builder impl(RestLogger value) {
+                       impl = value;
+                       return this;
+               }
+
+               /**
+                * Creates a copy of this builder.
+                *
+                * @return A copy of this builder.
+                */
+               public Builder copy() {
+                       return new Builder(this);
+               }
        }
 
        /**
diff --git 
a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/logging/RestLoggerBuilder.java
 
b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/logging/RestLoggerBuilder.java
deleted file mode 100644
index b78afd2..0000000
--- 
a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/logging/RestLoggerBuilder.java
+++ /dev/null
@@ -1,346 +0,0 @@
-// 
***************************************************************************************************************************
-// * 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.logging;
-
-import static org.apache.juneau.Enablement.*;
-import static org.apache.juneau.internal.ClassUtils.*;
-import static org.apache.juneau.rest.HttpRuntimeException.*;
-
-import java.util.*;
-import java.util.function.*;
-import java.util.logging.*;
-
-import javax.servlet.http.*;
-
-import org.apache.juneau.*;
-import org.apache.juneau.collections.*;
-import org.apache.juneau.cp.*;
-import org.apache.juneau.http.response.*;
-import org.apache.juneau.mstat.*;
-
-/**
- * Builder class for {@link BasicRestLogger} objects.
- */
-public class RestLoggerBuilder {
-
-       Logger logger;
-       ThrownStore thrownStore;
-       List<RestLoggerRule> normalRules = AList.create(), debugRules = 
AList.create();
-       Enablement enabled;
-       Predicate<HttpServletRequest> enabledTest;
-       RestLoggingDetail requestDetail, responseDetail;
-       Level level;
-       BeanStore beanStore;
-       Class<? extends RestLogger> implClass;
-
-       /**
-        * Creates a new {@link RestLogger} object from this builder.
-        *
-        * <p>
-        * Instantiates an instance of the {@link #implClass(Class) 
implementation class} or
-        * else {@link BasicRestLogger} if implementation class was not 
specified.
-        *
-        * @return A new {@link RestLogger} object.
-        */
-       public RestLogger build() {
-               try {
-                       Class<? extends RestLogger> ic = isConcrete(implClass) 
? implClass : getDefaultImplClass();
-                       return 
BeanStore.of(beanStore).addBeans(RestLoggerBuilder.class, this).createBean(ic);
-               } catch (Exception e) {
-                       throw toHttpException(e, InternalServerError.class);
-               }
-       }
-
-       /**
-        * Specifies the default implementation class if not specified via 
{@link #implClass(Class)}.
-        *
-        * @return The default implementation class if not specified via {@link 
#implClass(Class)}.
-        */
-       protected Class<? extends RestLogger> getDefaultImplClass() {
-               return BasicRestLogger.class;
-       }
-
-       /**
-        * Specifies the bean store to use for instantiating the {@link 
RestLogger} object.
-        *
-        * @param value The new value for this setting.
-        * @return  This object (for method chaining).
-        */
-       public RestLoggerBuilder beanStore(BeanStore value) {
-               this.beanStore = value;
-               return this;
-       }
-
-       /**
-        * Specifies a subclass of {@link RestLogger} to create when the {@link 
#build()} method is called.
-        *
-        * @param value The new value for this setting.
-        * @return  This object (for method chaining).
-        */
-       public RestLoggerBuilder implClass(Class<? extends RestLogger> value) {
-               this.implClass = value;
-               return this;
-       }
-
-       /**
-        * Specifies the logger to use for logging the request.
-        *
-        * <p>
-        * If not specified, the logger name is determined in the following 
order:
-        * <ol>
-        *      <li><js>{@link RestLogger#SP_logger "juneau.restLogger.logger"} 
system property.
-        *      <li><js>{@link RestLogger#SP_logger "JUNEAU_RESTLOGGER_LOGGER"} 
environment variable.
-        *      <li><js>"global"</js>.
-        * </ol>
-        *
-        * <p>
-        * The {@link BasicRestLogger#getLogger()} method can also be 
overridden to provide different logic.
-        *
-        * @param value
-        *      The logger to use for logging the request.
-        * @return This object (for method chaining).
-        */
-       public RestLoggerBuilder logger(Logger value) {
-               this.logger = value;
-               return this;
-       }
-
-       /**
-        * Specifies the logger to use for logging the request.
-        *
-        * <p>
-        * Shortcut for calling 
<c>logger(Logger.<jsm>getLogger</jsm>(value))</c>.
-        *
-        * <p>
-        * If not specified, the logger name is determined in the following 
order:
-        * <ol>
-        *      <li><js>{@link RestLogger#SP_logger "juneau.restLogger.logger"} 
system property.
-        *      <li><js>{@link RestLogger#SP_logger "JUNEAU_RESTLOGGER_LOGGER"} 
environment variable.
-        *      <li><js>"global"</js>.
-        * </ol>
-        *
-        * <p>
-        * The {@link BasicRestLogger#getLogger()} method can also be 
overridden to provide different logic.
-        *
-        * @param value
-        *      The logger to use for logging the request.
-        * @return This object (for method chaining).
-        */
-       public RestLoggerBuilder logger(String value) {
-               this.logger = value == null ? null :Logger.getLogger(value);
-               return this;
-       }
-
-       /**
-        * Specifies the thrown exception store to use for getting stack trace 
information (hash IDs and occurrence counts).
-        *
-        * @param value
-        *      The stack trace store.
-        *      <br>If <jk>null</jk>, stack trace information will not be 
logged.
-        * @return This object (for method chaining).
-        */
-       public RestLoggerBuilder thrownStore(ThrownStore value) {
-               this.thrownStore = value;
-               return this;
-       }
-
-       /**
-        * Specifies the default logging enablement setting.
-        *
-        * <p>
-        * This specifies the default logging enablement value if not set on 
the first matched rule or if no rules match.
-        *
-        * <p>
-        * The possible values are:
-        * <ul>
-        *      <li>{@link Enablement#ALWAYS ALWAYS} (default) - Logging is 
enabled.
-        *      <li>{@link Enablement#NEVER NEVER} - Logging is disabled.
-        *      <li>{@link Enablement#CONDITIONAL CONDITIONALLY} - Logging is 
enabled if it passes the {@link #enabledTest(Predicate)} test.
-        * </ul>
-        *
-        * <p>
-        * If not specified, the setting is determined via the following:
-        * <ul>
-        *      <li><js>{@link RestLogger#SP_enabled 
"juneau.restLogger.enabled"} system property.
-        *      <li><js>{@link RestLogger#SP_enabled 
"JUNEAU_RESTLOGGER_ENABLED"} environment variable.
-        *      <li><js>"ALWAYS"</js>.
-        * </ul>
-        *
-        * <p>
-        * @param value
-        *      The default enablement flag value.  Can be <jk>null</jk> to use 
the default.
-        * @return This object (for method chaining).
-        */
-       public RestLoggerBuilder enabled(Enablement value) {
-               this.enabled = value;
-               return this;
-       }
-
-       /**
-        * Specifies the default logging enablement test predicate.
-        *
-        * <p>
-        * This specifies the default logging enablement test if not set on the 
first matched rule or if no rules match.
-        *
-        * <p>
-        * This setting has no effect if the enablement setting is not {@link 
Enablement#CONDITIONAL CONDITIONALLY}.
-        *
-        * <p>
-        * The default if not specified is <c><jv>x</jv> -> <jk>false</jk></c> 
(never log).
-        *
-        * @param value
-        *      The default enablement flag value.  Can be <jk>null</jk> to use 
the default.
-        * @return This object (for method chaining).
-        */
-       public RestLoggerBuilder enabledTest(Predicate<HttpServletRequest> 
value) {
-               this.enabledTest = value;
-               return this;
-       }
-
-       /**
-        * Shortcut for calling <c>enabled(<jsf>NEVER</jsf>)</c>.
-        *
-        * @return This object (for method chaining).
-        */
-       public RestLoggerBuilder disabled() {
-               return this.enabled(NEVER);
-       }
-
-       /**
-        * The default level of detail to log on a request.
-        *
-        * <p>
-        * This specifies the default level of request detail if not set on the 
first matched rule or if no rules match.
-        *
-        * <p>
-        * The possible values are:
-        * <ul>
-        *      <li>{@link RestLoggingDetail#STATUS_LINE STATUS_LINE} - Log 
only the status line.
-        *      <li>{@link RestLoggingDetail#HEADER HEADER} - Log the status 
line and headers.
-        *      <li>{@link RestLoggingDetail#ENTITY ENTITY} - Log the status 
line and headers and body if available.
-        * </ul>
-        *
-        * <p>
-        * If not specified, the setting is determined via the following:
-        * <ul>
-        *      <li><js>{@link RestLogger#SP_requestDetail 
"juneau.restLogger.requestDetail"} system property.
-        *      <li><js>{@link RestLogger#SP_requestDetail 
"JUNEAU_RESTLOGGER_requestDetail"} environment variable.
-        *      <li><js>"STATUS_LINE"</js>.
-        * </ul>
-        *
-        * @param value
-        *      The new value for this property, or <jk>null</jk> to use the 
default.
-        * @return This object (for method chaining).
-        */
-       public RestLoggerBuilder requestDetail(RestLoggingDetail value) {
-               this.requestDetail = value;
-               return this;
-       }
-
-       /**
-        * The default level of detail to log on a response.
-        *
-        * <p>
-        * This specifies the default level of response detail if not set on 
the first matched rule or if no rules match.
-        *
-        * <p>
-        * The possible values are:
-        * <ul>
-        *      <li>{@link RestLoggingDetail#STATUS_LINE STATUS_LINE} - Log 
only the status line.
-        *      <li>{@link RestLoggingDetail#HEADER HEADER} - Log the status 
line and headers.
-        *      <li>{@link RestLoggingDetail#ENTITY ENTITY} - Log the status 
line and headers and body if available.
-        * </ul>
-        *
-        * <p>
-        * If not specified, the setting is determined via the following:
-        * <ul>
-        *      <li><js>{@link RestLogger#SP_responseDetail 
"juneau.restLogger.responseDetail"} system property.
-        *      <li><js>{@link RestLogger#SP_responseDetail 
"JUNEAU_RESTLOGGER_responseDetail"} environment variable.
-        *      <li><js>"STATUS_LINE"</js>.
-        * </ul>
-        *
-        * @param value
-        *      The new value for this property, or <jk>null</jk> to use the 
default.
-        * @return This object (for method chaining).
-        */
-       public RestLoggerBuilder responseDetail(RestLoggingDetail value) {
-               this.responseDetail = value;
-               return this;
-       }
-
-       /**
-        * The default logging level to use for logging the request/response.
-        *
-        * <p>
-        * This specifies the default logging level if not set on the first 
matched rule or if no rules match.
-        *
-        * <p>
-        * If not specified, the setting is determined via the following:
-        * <ul>
-        *      <li><js>{@link RestLogger#SP_level "juneau.restLogger.level"} 
system property.
-        *      <li><js>{@link RestLogger#SP_level "JUNEAU_RESTLOGGER_level"} 
environment variable.
-        *      <li><js>"OFF"</js>.
-        * </ul>
-        *
-        * @param value
-        *      The new value for this property, or <jk>null</jk> to use the 
default value.
-        * @return This object (for method chaining).
-        */
-       public RestLoggerBuilder level(Level value) {
-               this.level = value;
-               return this;
-       }
-
-       /**
-        * Adds logging rules to use when debug mode is not enabled.
-        *
-        * <p>
-        * Logging rules are matched in the order they are added.  The first to 
match wins.
-        *
-        * @param rules The logging rules to add to the list of rules.
-        * @return This object (for method chaining).
-        */
-       public RestLoggerBuilder normalRules(RestLoggerRule...rules) {
-               for (RestLoggerRule rule : rules)
-                       this.normalRules.add(rule);
-               return this;
-       }
-
-       /**
-        * Adds logging rules to use when debug mode is enabled.
-        *
-        * <p>
-        * Logging rules are matched in the order they are added.  The first to 
match wins.
-        *
-        * @param rules The logging rules to add to the list of rules.
-        * @return This object (for method chaining).
-        */
-       public RestLoggerBuilder debugRules(RestLoggerRule...rules) {
-               for (RestLoggerRule rule : rules)
-                       this.debugRules.add(rule);
-               return this;
-       }
-
-       /**
-        * Shortcut for adding the same rules as normal and debug rules.
-        *
-        * <p>
-        * Logging rules are matched in the order they are added.  The first to 
match wins.
-        *
-        * @param rules The logging rules to add to the list of rules.
-        * @return This object (for method chaining).
-        */
-       public RestLoggerBuilder rules(RestLoggerRule...rules) {
-               return normalRules(rules).debugRules(rules);
-       }
-}
diff --git 
a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/logging/RestLoggerRule.java
 
b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/logging/RestLoggerRule.java
index 61d202d..ae7bc4d 100644
--- 
a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/logging/RestLoggerRule.java
+++ 
b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/logging/RestLoggerRule.java
@@ -26,6 +26,15 @@ import org.apache.juneau.json.*;
  */
 public class RestLoggerRule {
 
+       /**
+        * Creates a new builder for this object.
+        *
+        * @return A new builder for this object.
+        */
+       public static Builder create() {
+               return new Builder();
+       }
+
        private final Predicate<Integer> statusFilter;
        private final Predicate<HttpServletRequest> requestFilter;
        private final Predicate<HttpServletResponse> responseFilter;
@@ -41,7 +50,7 @@ public class RestLoggerRule {
         *
         * @param b Builder
         */
-       RestLoggerRule(RestLoggerRuleBuilder b) {
+       RestLoggerRule(Builder b) {
                this.statusFilter = b.statusFilter;
                this.exceptionFilter = b.exceptionFilter;
                this.requestFilter = b.requestFilter;
@@ -55,12 +64,253 @@ public class RestLoggerRule {
        }
 
        /**
-        * Creates a new builder for this object.
-        *
-        * @return A new builder for this object.
+        * The builder for this object.
         */
-       public static RestLoggerRuleBuilder create() {
-               return new RestLoggerRuleBuilder();
+       public static class Builder {
+
+               Predicate<Integer> statusFilter;
+               Predicate<HttpServletRequest> requestFilter;
+               Predicate<HttpServletResponse> responseFilter;
+               Predicate<Throwable> exceptionFilter;
+               Enablement enabled;
+               Predicate<HttpServletRequest> enabledTest;
+               Level level;
+               RestLoggingDetail requestDetail, responseDetail;
+               boolean logStackTrace;
+
+               /**
+                * Apply a status-based predicate check for this rule to match 
against.
+                *
+                * <h5 class='section'>Example:</h5>
+                * <p class='bcode w800'>
+                *      <jc>// Create a logger rule that only matches if the 
status code is greater than or equal to 500.</jc>
+                *      RestLogger
+                *              .<jsm>createRule</jsm>()
+                *              .statusFilter(<jv>x</jv> -&gt; <jv>x</jv> &gt;= 
500)
+                *              .build();
+                * </p>
+                *
+                * @param value
+                *      The predicate check, or <jk>null</jk> to not use any 
filtering based on status code.
+                * @return This object (for method chaining).
+                */
+               public Builder statusFilter(Predicate<Integer> value) {
+                       this.statusFilter = value;
+                       return this;
+               }
+
+               /**
+                * Apply a throwable-based predicate check for this rule to 
match against.
+                *
+                * <h5 class='section'>Example:</h5>
+                * <p class='bcode w800'>
+                *      <jc>// Create a logger rule that only matches if a 
NotFound exception was thrown.</jc>
+                *      RestLogger
+                *              .<jsm>createRule</jsm>()
+                *              .exceptionFilter(<jv>x</jv> -&gt; <jv>x</jv> 
<jk>instanceof</jk> NotFound)
+                *              .build();
+                * </p>
+                *
+                * <p>
+                * This check is only performed if an actual throwable was 
thrown.  Therefore it's not necessary to perform a
+                * null check in the predicate.
+                *
+                * @param value
+                *      The predicate check, or <jk>null</jk> to not use any 
filtering based on exceptions.
+                * @return This object (for method chaining).
+                */
+               public Builder exceptionFilter(Predicate<Throwable> value) {
+                       this.exceptionFilter = value;
+                       return this;
+               }
+
+               /**
+                * Apply a request-based predicate check for this rule to match 
against.
+                *
+                * <h5 class='section'>Example:</h5>
+                * <p class='bcode w800'>
+                *      <jc>// Create a logger rule that only matches if the 
servlet path contains "foobar".</jc>
+                *      RestLogger
+                *              .<jsm>createRule</jsm>()
+                *              .requestFilter(<jv>x</jv> -&gt; 
<jv>x</jv>.getServletPath().contains(<js>"foobar"</js>))
+                *              .build();
+                * </p>
+                *
+                * @param value
+                *      The predicate check, or <jk>null</jk> to not use any 
filtering based on the request.
+                * @return This object (for method chaining).
+                */
+               public Builder requestFilter(Predicate<HttpServletRequest> 
value) {
+                       this.requestFilter = value;
+                       return this;
+               }
+
+               /**
+                * Apply a response-based predicate check for this rule to 
match against.
+                *
+                * <h5 class='section'>Example:</h5>
+                * <p class='bcode w800'>
+                *      <jc>// Create a logger rule that only matches if the 
servlet path contains "foobar".</jc>
+                *      RestLogger
+                *              .<jsm>createRule</jsm>()
+                *              .responseFilter(<jv>x</jv> -&gt; 
<jv>x</jv>.getStatus() &gt;= 500)
+                *              .build();
+                * </p>
+                *
+                * <p>
+                * Note that the {@link #statusFilter(Predicate)} and {@link 
#exceptionFilter(Predicate)} methods are simply
+                * convenience response filters.
+                *
+                * @param value
+                *      The predicate check, or <jk>null</jk> to not use any 
filtering based on the response.
+                * @return This object (for method chaining).
+                */
+               public Builder responseFilter(Predicate<HttpServletResponse> 
value) {
+                       this.responseFilter = value;
+                       return this;
+               }
+
+               /**
+                * Specifies whether logging is enabled when using this rule.
+                *
+                * <p>
+                * The possible values are:
+                * <ul>
+                *      <li>{@link Enablement#ALWAYS ALWAYS} - Logging is 
enabled.
+                *      <li>{@link Enablement#NEVER NEVER} - Logging is 
disabled.
+                *      <li>{@link Enablement#CONDITIONAL CONDITIONALLY} - 
Logging is enabled if it passes the {@link #enabledTest(Predicate)} test.
+                * </ul>
+                *
+                * <h5 class='section'>Example:</h5>
+                * <p class='bcode w800'>
+                *      <jc>// Create a logger rule where logging is only 
enabled if the query string contains "foobar".</jc>
+                *      RestLogger
+                *              .<jsm>createRule</jsm>()
+                *              .enabled(<jsf>CONDITIONALLY</jsf>)
+                *              .enabledTest(<jv>x</jv> -> 
<jv>x</jv>.getQueryString().contains(<js>"foobar"</js>))
+                *              .build();
+                * </p>
+                *
+                * @param value
+                *      The enablement flag value, or <jk>null</jk> to inherit 
from the call logger whose default value is {@link Enablement#ALWAYS ALWAYS}
+                *      unless overridden via a 
<js>"juneau.restCallLogger.enabled"</js> system property or 
<js>"JUNEAU_RESTCALLLOGGER_ENABLED"</js> environment variable.
+                * @return This object (for method chaining).
+                */
+               public Builder enabled(Enablement value) {
+                       this.enabled = value;
+                       return this;
+               }
+
+               /**
+                * Specifies the predicate test to use when the enabled setting 
is set to {@link Enablement#CONDITIONAL CONDITIONALLY}.
+                *
+                * <p>
+                * This setting has no effect if the enablement value is not 
{@link Enablement#CONDITIONAL CONDITIONALLY}.
+                *
+                * <h5 class='section'>Example:</h5>
+                * <p class='bcode w800'>
+                *      <jc>// Create a logger rule where logging is only 
enabled if the query string contains "foobar".</jc>
+                *      RestLogger
+                *              .<jsm>createRule</jsm>()
+                *              .enabled(<jsf>CONDITIONALLY</jsf>)
+                *              .enabledTest(<jv>x</jv> -> 
<jv>x</jv>.getQueryString().contains(<js>"foobar"</js>))
+                *              .build();
+                * </p>
+                *
+                * @param value
+                *      The enablement predicate test, or <jk>null</jk> to 
inherit from the call logger whose default value is <c><jv>x</jv> -&gt; 
<jk>false</jk></c>.
+                * @return This object (for method chaining).
+                */
+               public Builder enabledTest(Predicate<HttpServletRequest> value) 
{
+                       this.enabledTest = value;
+                       return this;
+               }
+
+               /**
+                * Shortcut for calling <c>enabled(<jsf>NEVER</jsf>)</c>.
+                *
+                * @return This object (for method chaining).
+                */
+               public Builder disabled() {
+                       return this.enabled(Enablement.NEVER);
+               }
+
+               /**
+                * The level of detail to log on a request.
+                *
+                * <p>
+                * The possible values are:
+                * <ul>
+                *      <li>{@link RestLoggingDetail#STATUS_LINE STATUS_LINE} - 
Log only the status line.
+                *      <li>{@link RestLoggingDetail#HEADER HEADER} - Log the 
status line and headers.
+                *      <li>{@link RestLoggingDetail#ENTITY ENTITY} - Log the 
status line and headers and body if available.
+                * </ul>
+                *
+                * @param value
+                *      The new value for this property, or <jk>null</jk> to 
inherit from the call logger.
+                * @return This object (for method chaining).
+                */
+               public Builder requestDetail(RestLoggingDetail value) {
+                       this.requestDetail = value;
+                       return this;
+               }
+
+               /**
+                * The level of detail to log on a response.
+                *
+                * <p>
+                * The possible values are:
+                * <ul>
+                *      <li>{@link RestLoggingDetail#STATUS_LINE STATUS_LINE} - 
Log only the status line.
+                *      <li>{@link RestLoggingDetail#HEADER HEADER} - Log the 
status line and headers.
+                *      <li>{@link RestLoggingDetail#ENTITY ENTITY} - Log the 
status line and headers and body if available.
+                * </ul>
+                *
+                * @param value
+                *      The new value for this property, or <jk>null</jk> to 
inherit from the call logger.
+                * @return This object (for method chaining).
+                */
+               public Builder responseDetail(RestLoggingDetail value) {
+                       this.responseDetail = value;
+                       return this;
+               }
+
+               /**
+                * The logging level to use for logging the request/response.
+                *
+                * <p>
+                * The default value is {@link Level#INFO}.
+                *
+                * @param value
+                *      The new value for this property, or <jk>null</jk> to 
inherit from the call logger.
+                * @return This object (for method chaining).
+                */
+               public Builder level(Level value) {
+                       this.level = value;
+                       return this;
+               }
+
+               /**
+                * Log a stack trace as part of the log entry.
+                *
+                * <p>
+                * The default value is <jk>false</jk>.
+                *
+                * @return This object (for method chaining).
+                */
+               public Builder logStackTrace() {
+                       this.logStackTrace = true;
+                       return this;
+               }
+
+               /**
+                * Instantiates a new {@link RestLoggerRule} object using the 
settings in this builder.
+                *
+                * @return A new {@link RestLoggerRule} object.
+                */
+               public RestLoggerRule build() {
+                       return new RestLoggerRule(this);
+               }
        }
 
        /**
diff --git 
a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/logging/RestLoggerRuleBuilder.java
 
b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/logging/RestLoggerRuleBuilder.java
deleted file mode 100644
index d76d515..0000000
--- 
a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/logging/RestLoggerRuleBuilder.java
+++ /dev/null
@@ -1,280 +0,0 @@
-// 
***************************************************************************************************************************
-// * 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.logging;
-
-import java.util.function.*;
-import java.util.logging.*;
-
-import javax.servlet.http.*;
-
-import org.apache.juneau.*;
-import org.apache.juneau.rest.*;
-
-/**
- * Creator for {@link RestLoggerRule} objects.
- *
- * <p>
- * See the {@link BasicRestLogger} for usage.
- *
- * <ul class='seealso'>
- *     <li class='jm'>{@link RestContextBuilder#callLogger(Class)}
- *     <li class='jm'>{@link RestContextBuilder#callLogger(RestLogger)}
- *     <li class='link'>{@doc RestLoggingAndDebugging}
- * </ul>
- */
-public class RestLoggerRuleBuilder {
-
-       Predicate<Integer> statusFilter;
-       Predicate<HttpServletRequest> requestFilter;
-       Predicate<HttpServletResponse> responseFilter;
-       Predicate<Throwable> exceptionFilter;
-       Enablement enabled;
-       Predicate<HttpServletRequest> enabledTest;
-       Level level;
-       RestLoggingDetail requestDetail, responseDetail;
-       boolean logStackTrace;
-
-       /**
-        * Apply a status-based predicate check for this rule to match against.
-        *
-        * <h5 class='section'>Example:</h5>
-        * <p class='bcode w800'>
-        *      <jc>// Create a logger rule that only matches if the status 
code is greater than or equal to 500.</jc>
-        *      RestLogger
-        *              .<jsm>createRule</jsm>()
-        *              .statusFilter(<jv>x</jv> -&gt; <jv>x</jv> &gt;= 500)
-        *              .build();
-        * </p>
-        *
-        * @param value
-        *      The predicate check, or <jk>null</jk> to not use any filtering 
based on status code.
-        * @return This object (for method chaining).
-        */
-       public RestLoggerRuleBuilder statusFilter(Predicate<Integer> value) {
-               this.statusFilter = value;
-               return this;
-       }
-
-       /**
-        * Apply a throwable-based predicate check for this rule to match 
against.
-        *
-        * <h5 class='section'>Example:</h5>
-        * <p class='bcode w800'>
-        *      <jc>// Create a logger rule that only matches if a NotFound 
exception was thrown.</jc>
-        *      RestLogger
-        *              .<jsm>createRule</jsm>()
-        *              .exceptionFilter(<jv>x</jv> -&gt; <jv>x</jv> 
<jk>instanceof</jk> NotFound)
-        *              .build();
-        * </p>
-        *
-        * <p>
-        * This check is only performed if an actual throwable was thrown.  
Therefore it's not necessary to perform a
-        * null check in the predicate.
-        *
-        * @param value
-        *      The predicate check, or <jk>null</jk> to not use any filtering 
based on exceptions.
-        * @return This object (for method chaining).
-        */
-       public RestLoggerRuleBuilder exceptionFilter(Predicate<Throwable> 
value) {
-               this.exceptionFilter = value;
-               return this;
-       }
-
-       /**
-        * Apply a request-based predicate check for this rule to match against.
-        *
-        * <h5 class='section'>Example:</h5>
-        * <p class='bcode w800'>
-        *      <jc>// Create a logger rule that only matches if the servlet 
path contains "foobar".</jc>
-        *      RestLogger
-        *              .<jsm>createRule</jsm>()
-        *              .requestFilter(<jv>x</jv> -&gt; 
<jv>x</jv>.getServletPath().contains(<js>"foobar"</js>))
-        *              .build();
-        * </p>
-        *
-        * @param value
-        *      The predicate check, or <jk>null</jk> to not use any filtering 
based on the request.
-        * @return This object (for method chaining).
-        */
-       public RestLoggerRuleBuilder 
requestFilter(Predicate<HttpServletRequest> value) {
-               this.requestFilter = value;
-               return this;
-       }
-
-       /**
-        * Apply a response-based predicate check for this rule to match 
against.
-        *
-        * <h5 class='section'>Example:</h5>
-        * <p class='bcode w800'>
-        *      <jc>// Create a logger rule that only matches if the servlet 
path contains "foobar".</jc>
-        *      RestLogger
-        *              .<jsm>createRule</jsm>()
-        *              .responseFilter(<jv>x</jv> -&gt; <jv>x</jv>.getStatus() 
&gt;= 500)
-        *              .build();
-        * </p>
-        *
-        * <p>
-        * Note that the {@link #statusFilter(Predicate)} and {@link 
#exceptionFilter(Predicate)} methods are simply
-        * convenience response filters.
-        *
-        * @param value
-        *      The predicate check, or <jk>null</jk> to not use any filtering 
based on the response.
-        * @return This object (for method chaining).
-        */
-       public RestLoggerRuleBuilder 
responseFilter(Predicate<HttpServletResponse> value) {
-               this.responseFilter = value;
-               return this;
-       }
-
-       /**
-        * Specifies whether logging is enabled when using this rule.
-        *
-        * <p>
-        * The possible values are:
-        * <ul>
-        *      <li>{@link Enablement#ALWAYS ALWAYS} - Logging is enabled.
-        *      <li>{@link Enablement#NEVER NEVER} - Logging is disabled.
-        *      <li>{@link Enablement#CONDITIONAL CONDITIONALLY} - Logging is 
enabled if it passes the {@link #enabledTest(Predicate)} test.
-        * </ul>
-        *
-        * <h5 class='section'>Example:</h5>
-        * <p class='bcode w800'>
-        *      <jc>// Create a logger rule where logging is only enabled if 
the query string contains "foobar".</jc>
-        *      RestLogger
-        *              .<jsm>createRule</jsm>()
-        *              .enabled(<jsf>CONDITIONALLY</jsf>)
-        *              .enabledTest(<jv>x</jv> -> 
<jv>x</jv>.getQueryString().contains(<js>"foobar"</js>))
-        *              .build();
-        * </p>
-        *
-        * @param value
-        *      The enablement flag value, or <jk>null</jk> to inherit from the 
call logger whose default value is {@link Enablement#ALWAYS ALWAYS}
-        *      unless overridden via a 
<js>"juneau.restCallLogger.enabled"</js> system property or 
<js>"JUNEAU_RESTCALLLOGGER_ENABLED"</js> environment variable.
-        * @return This object (for method chaining).
-        */
-       public RestLoggerRuleBuilder enabled(Enablement value) {
-               this.enabled = value;
-               return this;
-       }
-
-       /**
-        * Specifies the predicate test to use when the enabled setting is set 
to {@link Enablement#CONDITIONAL CONDITIONALLY}.
-        *
-        * <p>
-        * This setting has no effect if the enablement value is not {@link 
Enablement#CONDITIONAL CONDITIONALLY}.
-        *
-        * <h5 class='section'>Example:</h5>
-        * <p class='bcode w800'>
-        *      <jc>// Create a logger rule where logging is only enabled if 
the query string contains "foobar".</jc>
-        *      RestLogger
-        *              .<jsm>createRule</jsm>()
-        *              .enabled(<jsf>CONDITIONALLY</jsf>)
-        *              .enabledTest(<jv>x</jv> -> 
<jv>x</jv>.getQueryString().contains(<js>"foobar"</js>))
-        *              .build();
-        * </p>
-        *
-        * @param value
-        *      The enablement predicate test, or <jk>null</jk> to inherit from 
the call logger whose default value is <c><jv>x</jv> -&gt; <jk>false</jk></c>.
-        * @return This object (for method chaining).
-        */
-       public RestLoggerRuleBuilder enabledTest(Predicate<HttpServletRequest> 
value) {
-               this.enabledTest = value;
-               return this;
-       }
-
-       /**
-        * Shortcut for calling <c>enabled(<jsf>NEVER</jsf>)</c>.
-        *
-        * @return This object (for method chaining).
-        */
-       public RestLoggerRuleBuilder disabled() {
-               return this.enabled(Enablement.NEVER);
-       }
-
-       /**
-        * The level of detail to log on a request.
-        *
-        * <p>
-        * The possible values are:
-        * <ul>
-        *      <li>{@link RestLoggingDetail#STATUS_LINE STATUS_LINE} - Log 
only the status line.
-        *      <li>{@link RestLoggingDetail#HEADER HEADER} - Log the status 
line and headers.
-        *      <li>{@link RestLoggingDetail#ENTITY ENTITY} - Log the status 
line and headers and body if available.
-        * </ul>
-        *
-        * @param value
-        *      The new value for this property, or <jk>null</jk> to inherit 
from the call logger.
-        * @return This object (for method chaining).
-        */
-       public RestLoggerRuleBuilder requestDetail(RestLoggingDetail value) {
-               this.requestDetail = value;
-               return this;
-       }
-
-       /**
-        * The level of detail to log on a response.
-        *
-        * <p>
-        * The possible values are:
-        * <ul>
-        *      <li>{@link RestLoggingDetail#STATUS_LINE STATUS_LINE} - Log 
only the status line.
-        *      <li>{@link RestLoggingDetail#HEADER HEADER} - Log the status 
line and headers.
-        *      <li>{@link RestLoggingDetail#ENTITY ENTITY} - Log the status 
line and headers and body if available.
-        * </ul>
-        *
-        * @param value
-        *      The new value for this property, or <jk>null</jk> to inherit 
from the call logger.
-        * @return This object (for method chaining).
-        */
-       public RestLoggerRuleBuilder responseDetail(RestLoggingDetail value) {
-               this.responseDetail = value;
-               return this;
-       }
-
-       /**
-        * The logging level to use for logging the request/response.
-        *
-        * <p>
-        * The default value is {@link Level#INFO}.
-        *
-        * @param value
-        *      The new value for this property, or <jk>null</jk> to inherit 
from the call logger.
-        * @return This object (for method chaining).
-        */
-       public RestLoggerRuleBuilder level(Level value) {
-               this.level = value;
-               return this;
-       }
-
-       /**
-        * Log a stack trace as part of the log entry.
-        *
-        * <p>
-        * The default value is <jk>false</jk>.
-        *
-        * @return This object (for method chaining).
-        */
-       public RestLoggerRuleBuilder logStackTrace() {
-               this.logStackTrace = true;
-               return this;
-       }
-
-       /**
-        * Instantiates a new {@link RestLoggerRule} object using the settings 
in this builder.
-        *
-        * @return A new {@link RestLoggerRule} object.
-        */
-       public RestLoggerRule build() {
-               return new RestLoggerRule(this);
-       }
-}
diff --git 
a/juneau-utest/src/test/java/org/apache/juneau/cp/DefaultClassList_Test.java 
b/juneau-utest/src/test/java/org/apache/juneau/cp/DefaultClassList_Test.java
new file mode 100644
index 0000000..db8038a
--- /dev/null
+++ b/juneau-utest/src/test/java/org/apache/juneau/cp/DefaultClassList_Test.java
@@ -0,0 +1,41 @@
+// 
***************************************************************************************************************************
+// * 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.cp;
+
+import static org.apache.juneau.assertions.Assertions.*;
+import static org.junit.runners.MethodSorters.*;
+import static org.apache.juneau.cp.DefaultClassList.*;
+
+import org.junit.*;
+
+@FixMethodOrder(NAME_ASCENDING)
+public class DefaultClassList_Test {
+
+       
//-----------------------------------------------------------------------------------------------------------------
+       // Basic tests.
+       
//-----------------------------------------------------------------------------------------------------------------
+
+       @Test
+       public void a01_basic() {
+               DefaultClassList x = create();
+               assertOptional(x.get(String.class)).isNull();
+
+               x = of(Long.class,null);
+               assertOptional(x.get(String.class)).isNull();
+               assertOptional(x.get(Long.class)).isNotNull();
+               assertOptional(x.get(Number.class)).isNotNull();
+               assertOptional(x.get(Object.class)).isNotNull();
+
+               assertThrown(()->create().get(null)).message().is("Argument 
'type' cannot be null.");
+       }
+}

Reply via email to