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

commit cdea0cdccafd7ad77dac637b3036790c9bce769b
Author: JamesBognar <[email protected]>
AuthorDate: Mon Sep 6 10:18:08 2021 -0400

    Context API refactoring.
---
 .../org/apache/juneau/assertions/Assertions.java   |  18 ++
 .../main/java/org/apache/juneau/cp/BeanStore.java  |  15 ++
 .../org/apache/juneau/encoders/EncoderGroup.java   | 205 +++++++++++++++++----
 .../juneau/encoders/EncoderGroupBuilder.java       | 105 -----------
 .../juneau-examples-rest-jetty.launch              |  26 +--
 .../juneau-examples-rest-springboot.launch         |  28 +--
 .../juneau-microservice-test.launch                |  30 +--
 .../my-jetty-microservice.launch                   |  28 +--
 .../my-springboot-microservice.launch              |  28 +--
 .../apache/juneau/rest/ResponseProcessorList.java  |  11 +-
 .../java/org/apache/juneau/rest/RestContext.java   |  79 +-------
 .../org/apache/juneau/rest/RestContextBuilder.java |  88 ++++++---
 .../java/org/apache/juneau/rest/RestOpArgList.java |   8 +-
 .../java/org/apache/juneau/rest/RestOpContext.java |  36 ++--
 .../apache/juneau/rest/RestOpContextBuilder.java   |  86 ++++++++-
 .../org/apache/juneau/rest/annotation/Rest.java    |   3 +-
 .../juneau/rest/annotation/RestAnnotation.java     |   2 +-
 .../apache/juneau/rest/annotation/RestDelete.java  |   5 +-
 .../rest/annotation/RestDeleteAnnotation.java      |  14 +-
 .../org/apache/juneau/rest/annotation/RestGet.java |   5 +-
 .../juneau/rest/annotation/RestGetAnnotation.java  |  13 +-
 .../org/apache/juneau/rest/annotation/RestOp.java  |   5 +-
 .../juneau/rest/annotation/RestOpAnnotation.java   |  13 +-
 .../apache/juneau/rest/annotation/RestPost.java    |   5 +-
 .../juneau/rest/annotation/RestPostAnnotation.java |  13 +-
 .../org/apache/juneau/rest/annotation/RestPut.java |   5 +-
 .../juneau/rest/annotation/RestPutAnnotation.java  |  13 +-
 .../apache/juneau/encoders/EncoderGroupTest.java   |  10 +-
 28 files changed, 498 insertions(+), 399 deletions(-)

diff --git 
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/assertions/Assertions.java
 
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/assertions/Assertions.java
index 3ce2f0e..5c87856 100644
--- 
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/assertions/Assertions.java
+++ 
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/assertions/Assertions.java
@@ -993,4 +993,22 @@ public class Assertions {
                if (! expression)
                        throw illegalArgumentException(msg, args);
        }
+
+       /**
+        * Throws an {@link IllegalArgumentException} if the specified value 
doesn't have all subclasses of the specified type.
+        *
+        * @param name The argument name.
+        * @param type The expected parent class.
+        * @param value The array value being checked.
+        * @return The value cast to the specified array type.
+        * @throws IllegalArgumentException Constructed exception.
+        */
+       @SuppressWarnings("unchecked")
+       public static final <T> Class<T>[] assertClassArrayArgIsType(String 
name, Class<T> type, Class<?>[] value) throws IllegalArgumentException {
+               for (int i = 0; i < value.length; i++)
+                       if (! type.isAssignableFrom(value[i]))
+                               throw illegalArgumentException("Arg {0} did not 
have arg of type {1} at index {2}: {3}", name, type.getName(), i, 
value[i].getName());
+               return (Class<T>[])value;
+       }
+
 }
diff --git 
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/cp/BeanStore.java 
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/cp/BeanStore.java
index 78f5d17..42153d0 100644
--- 
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/cp/BeanStore.java
+++ 
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/cp/BeanStore.java
@@ -312,6 +312,21 @@ public class BeanStore {
        }
 
        /**
+        * Same as {@link #createBean(Class)} but allows you to validate that 
the specified type is of the specified parent class.
+        *
+        * @param <T> The bean type to create.
+        * @param c The bean type to create.
+        * @param type The bean subtype to create.
+        * @return A newly-created bean.
+        * @throws ExecutableException If bean could not be created.
+        */
+       public <T> T createBean(Class<T> c, Class<? extends T> type) throws 
ExecutableException {
+               if (! c.isAssignableFrom(type))
+                       throw new ExecutableException("Could not instantiate 
class of type {0} because it was not a subtype of the class: {1}.", 
c.getName(), type);
+               return createBean(type);
+       }
+
+       /**
         * Same as {@link #createBean(Class)} but returns the bean creation 
wrapped in a supplier.
         *
         * @param c The bean type to create.
diff --git 
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/encoders/EncoderGroup.java
 
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/encoders/EncoderGroup.java
index 690a162..d217125 100644
--- 
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/encoders/EncoderGroup.java
+++ 
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/encoders/EncoderGroup.java
@@ -12,12 +12,18 @@
 // 
***************************************************************************************************************************
 package org.apache.juneau.encoders;
 
+import static java.util.Arrays.*;
+import static org.apache.juneau.assertions.Assertions.*;
 import static org.apache.juneau.http.HttpHeaders.*;
+import static java.util.stream.Collectors.*;
 
 import java.util.*;
+import java.util.ArrayList;
 import java.util.concurrent.*;
 
+import org.apache.juneau.*;
 import org.apache.juneau.collections.*;
+import org.apache.juneau.cp.*;
 import org.apache.juneau.http.header.*;
 
 /**
@@ -36,31 +42,39 @@ import org.apache.juneau.http.header.*;
  * Encoders are matched against <c>Accept-Encoding</c> strings in the order 
they exist in this group.
  *
  * <p>
- * Adding new entries will cause the entries to be prepended to the group.
- * This allows for previous encoders to be overridden through subsequent calls.
+ * Encoders are tried in the order they appear in the group.  The {@link 
Builder#add(Class...)}/{@link Builder#add(Encoder...)}
+ * methods prepend the values to the list to allow them the opportunity to 
override encoders already in the list.
  *
  * <p>
- * For example, calling 
<code>groupBuilder.append(E1.<jk>class</jk>,E2.<jk>class</jk>).append(E3.<jk>class</jk>,
+ * For example, calling 
<code>groupBuilder.add(E1.<jk>class</jk>,E2.<jk>class</jk>).add(E3.<jk>class</jk>,
  * E4.<jk>class</jk>)</code> will result in the order <c>E3, E4, E1, E2</c>.
  *
  * <h5 class='section'>Example:</h5>
  * <p class='bcode w800'>
  *     <jc>// Create an encoder group with support for gzip compression.</jc>
- *     EncoderGroup g = 
EncoderGroup.<jsm>create</jsm>().append(GzipEncoder.<jk>class</jk>).build();
+ *     EncoderGroup <jv>group</jv> = EncoderGroup
+ *             .<jsm>create</jsm>()
+ *             .add(GzipEncoder.<jk>class</jk>)
+ *             .build();
  *
  *     <jc>// Should return "gzip"</jc>
- *     String matchedCoding = g.findMatch(<js>"compress;q=1.0, gzip;q=0.8, 
identity;q=0.5, *;q=0"</js>);
+ *     String <jv>matchedCoding</jv> = 
<jv>group</jv>.findMatch(<js>"compress;q=1.0, gzip;q=0.8, identity;q=0.5, 
*;q=0"</js>);
  *
  *     <jc>// Get the encoder</jc>
- *     IEncoder encoder = g.getEncoder(matchedCoding);
+ *     Encoder <jv>encoder</jv> = 
<jv>group</jv>.getEncoder(<jv>matchedCoding</jv>);
  * </p>
  */
 public final class EncoderGroup {
 
        /**
+        * An identifier that a group of encoders should inherit from another 
group.
+        */
+       public static abstract class Inherit extends Encoder {}
+
+       /**
         * A default encoder group consisting of identity and G-Zip encoding.
         */
-       public static final EncoderGroup DEFAULT = 
create().append(IdentityEncoder.class, GzipEncoder.class).build();
+       public static final EncoderGroup DEFAULT = 
create().add(IdentityEncoder.class, GzipEncoder.class).build();
 
        // Maps Accept-Encoding headers to matching encoders.
        private final ConcurrentHashMap<String,EncoderMatch> cache = new 
ConcurrentHashMap<>();
@@ -70,33 +84,34 @@ public final class EncoderGroup {
        private final List<Encoder> encoders;
 
        /**
-        * Instantiates a new clean-slate {@link EncoderGroupBuilder} object.
+        * Instantiates a new clean-slate {@link EncoderGroup.Builder} object.
         *
         * <p>
         * This is equivalent to simply calling <code><jk>new</jk> 
EncoderGroupBuilder()</code>.
         *
-        * @return A new {@link EncoderGroupBuilder} object.
-        */
-       public static EncoderGroupBuilder create() {
-               return new EncoderGroupBuilder();
-       }
-
-       /**
-        * Returns a builder that's a copy of the settings on this encoder 
group.
-        *
-        * @return A new {@link EncoderGroupBuilder} initialized to this group.
+        * @return A new {@link EncoderGroup.Builder} object.
         */
-       public EncoderGroupBuilder copy() {
-               return new EncoderGroupBuilder(this);
+       public static Builder create() {
+               return new Builder();
        }
 
        /**
-        * Constructor
+        * Constructor.
         *
-        * @param encoders The encoders to add to this group.
+        * @param builder The builder for this object.
         */
-       public EncoderGroup(Encoder[] encoders) {
-               this.encoders = AList.unmodifiable(encoders);
+       protected EncoderGroup(Builder builder) {
+               List<Encoder> x = new ArrayList<>();
+               BeanStore bs = builder.beanStore;
+               for (Object e : builder.encoders) {
+                       if (e == EncoderGroup.Inherit.class && 
builder.inheritFrom != null) {
+                               for (Object e2 : builder.inheritFrom.encoders)
+                                       x.add(instantiate(bs, e2));
+                       } else {
+                               x.add(instantiate(bs, e));
+                       }
+               }
+               encoders = Collections.unmodifiableList(x);
 
                AList<String> lc = AList.create();
                AList<Encoder> l = AList.create();
@@ -111,6 +126,139 @@ public final class EncoderGroup {
                this.encodingsEncoders = l.asArrayOf(Encoder.class);
        }
 
+       @SuppressWarnings("unchecked")
+       private static Encoder instantiate(BeanStore bs, Object o) {
+               if (o instanceof Encoder)
+                       return (Encoder)o;
+               try {
+                       return bs.createBean(Encoder.class, (Class<? extends 
Encoder>)o);
+               } catch (ExecutableException e) {
+                       throw new RuntimeException(e);
+               }
+       }
+
+       /**
+        * Builder class for this object.
+        */
+       public static class Builder {
+               final AList<Object> encoders;
+               Builder inheritFrom;
+               BeanStore beanStore = BeanStore.create().build();
+
+               Builder() {
+                       encoders = AList.create();
+               }
+
+               /**
+                * Registers the specified encoders with this group.
+                *
+                * <p>
+                * Entries are added to the beginning of the list.
+                *
+                * @param values The encoders to add to this group.
+                * @return This object (for method chaining).
+                * @throws IllegalArgumentException if any class does not 
extend from {@link Encoder}.
+                */
+               public Builder add(Class<?>...values) {
+                       encoders.addAll(0, 
asList(assertClassArrayArgIsType("values", Encoder.class, values)));
+                       return this;
+               }
+
+               /**
+                * Registers the specified encoders with this group.
+                *
+                * <p>
+                * Entries are added to the beginning of the list.
+                *
+                * @param values The encoders to add to this group.
+                * @return This object (for method chaining).
+                */
+               public Builder add(Encoder...values) {
+                       encoders.addAll(0, asList(values));
+                       return this;
+               }
+
+               /**
+                * Associates a bean store with this builder.
+                *
+                * <p>
+                * Used for instantiating encoders specified via classes.
+                *
+                * @param value The new value for this setting.
+                * @return This object (for method chaining).
+                */
+               public Builder beanStore(BeanStore value) {
+                       beanStore = value;
+                       return this;
+               }
+
+               /**
+                * Associates a parent builder with this builder.
+                *
+                * <p>
+                * When {@link Inherit} is passed to {@link #add(Class...)}, 
the entries in the specified
+                * group will be inserted into this group.
+                *
+                * <h5 class='section'>Example:</h5>
+                * <p class='bcode w800'>
+                *      <jc>// A group being inherited.</jc>
+                *      EncoderGroup <jv>group1</jv> = EncoderGroup
+                *              .<jsm>create</jsm>()
+                *              .add(GzipEncoder.<jk>class</jk>)
+                *              .build();
+                *
+                *      <jc>// A group inheriting another group.</jc>
+                *      <jc>// The group ends up containing [IdentityEncoder, 
GZipEncoder] in that order.</jc>
+                *      EncoderGroup <jv>group2</jv> = EncoderGroup
+                *              .<jsm>create</jsm>()
+                *              .inheritFrom(<jv>group1</jv>)
+                *              .add(IdentityEncoder.<jk>class</jk>, 
EncoderGroup.Inherit.<jk>class</jk>)
+                *              .build();
+                * </p>
+                *
+                * @param value The group to inherit from.
+                * @return This object (for method chaining).
+                */
+               public Builder inheritFrom(EncoderGroup.Builder value) {
+                       inheritFrom = value;
+                       return this;
+               }
+
+               /**
+                * Creates a new {@link EncoderGroup} object using a snapshot 
of the settings defined in this builder.
+                *
+                * <p>
+                * This method can be called multiple times to produce multiple 
encoder groups.
+                *
+                * @return A new {@link EncoderGroup} object.
+                */
+               public EncoderGroup build() {
+                       return new EncoderGroup(this);
+               }
+
+               /**
+                * Returns <jk>true</jk> if this builder is empty.
+                *
+                * @return <jk>true</jk> if this builder is empty.
+                */
+               public boolean isEmpty() {
+                       return encoders.isEmpty();
+               }
+
+               @Override /* Object */
+               public String toString() {
+                       return encoders.stream().map(x -> 
toString(x)).collect(joining(",","[","]"));
+               }
+
+               private static String toString(Object o) {
+                       if (o == null)
+                               return "null";
+                       if (o instanceof Class)
+                               return "class:" + ((Class<?>)o).getSimpleName();
+                       return "object:" + o.getClass().getSimpleName();
+               }
+       }
+
        /**
         * Returns the coding string for the matching encoder that can handle 
the specified <c>Accept-Encoding</c>
         * or <c>Content-Encoding</c> header value.
@@ -159,13 +307,4 @@ public final class EncoderGroup {
        public List<String> getSupportedEncodings() {
                return encodings;
        }
-
-       /**
-        * Returns the encoders in this group.
-        *
-        * @return An unmodifiable list of encoders in this group.
-        */
-       public List<Encoder> getEncoders() {
-               return encoders;
-       }
 }
diff --git 
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/encoders/EncoderGroupBuilder.java
 
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/encoders/EncoderGroupBuilder.java
deleted file mode 100644
index cd3a1de..0000000
--- 
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/encoders/EncoderGroupBuilder.java
+++ /dev/null
@@ -1,105 +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.encoders;
-
-import static org.apache.juneau.internal.ClassUtils.*;
-
-import java.util.*;
-
-import org.apache.juneau.collections.*;
-import org.apache.juneau.internal.*;
-
-/**
- * Builder class for creating instances of {@link EncoderGroup}.
- */
-public class EncoderGroupBuilder {
-
-       private final AList<Encoder> encoders;
-
-       /**
-        * Create an empty encoder group builder.
-        */
-       public EncoderGroupBuilder() {
-               this.encoders = AList.create();
-       }
-
-       /**
-        * Clone an existing encoder group builder.
-        *
-        * @param copyFrom The encoder group that we're copying settings and 
encoders from.
-        */
-       public EncoderGroupBuilder(EncoderGroup copyFrom) {
-               this.encoders = AList.create();
-               encoders.appendReverse(copyFrom.getEncoders());
-       }
-
-       /**
-        * Registers the specified encoders with this group.
-        *
-        * @param e The encoders to append to this group.
-        * @return This object (for method chaining).
-        */
-       public EncoderGroupBuilder append(Class<?>...e) {
-               for (int i = e.length-1; i >= 0; i--)
-                       encoders.add(castOrCreate(Encoder.class, e[i]));
-               return this;
-       }
-
-       /**
-        * Registers the specified encoders with this group.
-        *
-        * @param e The encoders to append to this group.
-        * @return This object (for method chaining).
-        */
-       public EncoderGroupBuilder append(Encoder...e) {
-               encoders.appendReverse(e);
-               return this;
-       }
-
-       /**
-        * Registers the specified encoders with this group.
-        *
-        * @param e The encoders to append to this group.
-        * @return This object (for method chaining).
-        */
-       public EncoderGroupBuilder append(List<Encoder> e) {
-               encoders.appendReverse(e);
-               return this;
-       }
-
-       /**
-        * Registers the encoders in the specified group with this group.
-        *
-        * @param eg The encoders to append to this group.
-        * @return This object (for method chaining).
-        */
-       public EncoderGroupBuilder append(EncoderGroup eg) {
-               append(eg.getEncoders());
-               return this;
-       }
-
-       /**
-        * Creates a new {@link EncoderGroup} object using a snapshot of the 
settings defined in this builder.
-        *
-        * <p>
-        * This method can be called multiple times to produce multiple encoder 
groups.
-        *
-        * @return A new {@link EncoderGroup} object.
-        */
-       public EncoderGroup build() {
-               List<Encoder> l = new ArrayList<>();
-               for (Object e : encoders)
-                       l.add(castOrCreate(Encoder.class, e));
-               return new 
EncoderGroup(ArrayUtils.toReverseArray(Encoder.class, l));
-       }
-}
diff --git 
a/juneau-examples/juneau-examples-rest-jetty/juneau-examples-rest-jetty.launch 
b/juneau-examples/juneau-examples-rest-jetty/juneau-examples-rest-jetty.launch
index 58b55a0..9b7b204 100644
--- 
a/juneau-examples/juneau-examples-rest-jetty/juneau-examples-rest-jetty.launch
+++ 
b/juneau-examples/juneau-examples-rest-jetty/juneau-examples-rest-jetty.launch
@@ -1,16 +1,16 @@
 <?xml version="1.0" encoding="UTF-8" standalone="no"?>
 <launchConfiguration type="org.eclipse.jdt.launching.localJavaApplication">
-<listAttribute key="org.eclipse.debug.core.MAPPED_RESOURCE_PATHS">
-<listEntry 
value="/juneau-examples-rest-jetty/src/main/java/org/apache/juneau/examples/rest/jetty/App.java"/>
-</listAttribute>
-<listAttribute key="org.eclipse.debug.core.MAPPED_RESOURCE_TYPES">
-<listEntry value="1"/>
-</listAttribute>
-<booleanAttribute key="org.eclipse.jdt.debug.ui.CONSIDER_INHERITED_MAIN" 
value="true"/>
-<booleanAttribute key="org.eclipse.jdt.debug.ui.INCLUDE_EXTERNAL_JARS" 
value="true"/>
-<booleanAttribute 
key="org.eclipse.jdt.launching.ATTR_USE_START_ON_FIRST_THREAD" value="true"/>
-<stringAttribute key="org.eclipse.jdt.launching.CLASSPATH_PROVIDER" 
value="org.eclipse.m2e.launchconfig.classpathProvider"/>
-<stringAttribute key="org.eclipse.jdt.launching.MAIN_TYPE" 
value="org.apache.juneau.examples.rest.jetty.App"/>
-<stringAttribute key="org.eclipse.jdt.launching.PROJECT_ATTR" 
value="juneau-examples-rest-jetty"/>
-<stringAttribute key="org.eclipse.jdt.launching.SOURCE_PATH_PROVIDER" 
value="org.eclipse.m2e.launchconfig.sourcepathProvider"/>
+    <listAttribute key="org.eclipse.debug.core.MAPPED_RESOURCE_PATHS">
+        <listEntry 
value="/juneau-examples-rest-jetty/src/main/java/org/apache/juneau/examples/rest/jetty/App.java"/>
+    </listAttribute>
+    <listAttribute key="org.eclipse.debug.core.MAPPED_RESOURCE_TYPES">
+        <listEntry value="1"/>
+    </listAttribute>
+    <booleanAttribute key="org.eclipse.jdt.debug.ui.CONSIDER_INHERITED_MAIN" 
value="true"/>
+    <booleanAttribute key="org.eclipse.jdt.debug.ui.INCLUDE_EXTERNAL_JARS" 
value="true"/>
+    <booleanAttribute 
key="org.eclipse.jdt.launching.ATTR_USE_START_ON_FIRST_THREAD" value="true"/>
+    <stringAttribute key="org.eclipse.jdt.launching.CLASSPATH_PROVIDER" 
value="org.eclipse.m2e.launchconfig.classpathProvider"/>
+    <stringAttribute key="org.eclipse.jdt.launching.MAIN_TYPE" 
value="org.apache.juneau.examples.rest.jetty.App"/>
+    <stringAttribute key="org.eclipse.jdt.launching.PROJECT_ATTR" 
value="juneau-examples-rest-jetty"/>
+    <stringAttribute key="org.eclipse.jdt.launching.SOURCE_PATH_PROVIDER" 
value="org.eclipse.m2e.launchconfig.sourcepathProvider"/>
 </launchConfiguration>
diff --git 
a/juneau-examples/juneau-examples-rest-springboot/juneau-examples-rest-springboot.launch
 
b/juneau-examples/juneau-examples-rest-springboot/juneau-examples-rest-springboot.launch
index a193a4a..29e66fc 100644
--- 
a/juneau-examples/juneau-examples-rest-springboot/juneau-examples-rest-springboot.launch
+++ 
b/juneau-examples/juneau-examples-rest-springboot/juneau-examples-rest-springboot.launch
@@ -1,17 +1,17 @@
 <?xml version="1.0" encoding="UTF-8" standalone="no"?>
 <launchConfiguration type="org.eclipse.jdt.launching.localJavaApplication">
-<listAttribute key="org.eclipse.debug.core.MAPPED_RESOURCE_PATHS">
-<listEntry 
value="/juneau-examples-rest-springboot/src/main/java/org/apache/juneau/examples/rest/springboot/App.java"/>
-</listAttribute>
-<listAttribute key="org.eclipse.debug.core.MAPPED_RESOURCE_TYPES">
-<listEntry value="1"/>
-</listAttribute>
-<booleanAttribute key="org.eclipse.jdt.debug.ui.CONSIDER_INHERITED_MAIN" 
value="true"/>
-<booleanAttribute key="org.eclipse.jdt.debug.ui.INCLUDE_EXTERNAL_JARS" 
value="true"/>
-<booleanAttribute 
key="org.eclipse.jdt.launching.ATTR_USE_START_ON_FIRST_THREAD" value="true"/>
-<stringAttribute key="org.eclipse.jdt.launching.CLASSPATH_PROVIDER" 
value="org.eclipse.m2e.launchconfig.classpathProvider"/>
-<stringAttribute key="org.eclipse.jdt.launching.JRE_CONTAINER" 
value="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8"/>
-<stringAttribute key="org.eclipse.jdt.launching.MAIN_TYPE" 
value="org.apache.juneau.examples.rest.springboot.App"/>
-<stringAttribute key="org.eclipse.jdt.launching.PROJECT_ATTR" 
value="juneau-examples-rest-springboot"/>
-<stringAttribute key="org.eclipse.jdt.launching.SOURCE_PATH_PROVIDER" 
value="org.eclipse.m2e.launchconfig.sourcepathProvider"/>
+    <listAttribute key="org.eclipse.debug.core.MAPPED_RESOURCE_PATHS">
+        <listEntry 
value="/juneau-examples-rest-springboot/src/main/java/org/apache/juneau/examples/rest/springboot/App.java"/>
+    </listAttribute>
+    <listAttribute key="org.eclipse.debug.core.MAPPED_RESOURCE_TYPES">
+        <listEntry value="1"/>
+    </listAttribute>
+    <booleanAttribute key="org.eclipse.jdt.debug.ui.CONSIDER_INHERITED_MAIN" 
value="true"/>
+    <booleanAttribute key="org.eclipse.jdt.debug.ui.INCLUDE_EXTERNAL_JARS" 
value="true"/>
+    <booleanAttribute 
key="org.eclipse.jdt.launching.ATTR_USE_START_ON_FIRST_THREAD" value="true"/>
+    <stringAttribute key="org.eclipse.jdt.launching.CLASSPATH_PROVIDER" 
value="org.eclipse.m2e.launchconfig.classpathProvider"/>
+    <stringAttribute key="org.eclipse.jdt.launching.JRE_CONTAINER" 
value="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8"/>
+    <stringAttribute key="org.eclipse.jdt.launching.MAIN_TYPE" 
value="org.apache.juneau.examples.rest.springboot.App"/>
+    <stringAttribute key="org.eclipse.jdt.launching.PROJECT_ATTR" 
value="juneau-examples-rest-springboot"/>
+    <stringAttribute key="org.eclipse.jdt.launching.SOURCE_PATH_PROVIDER" 
value="org.eclipse.m2e.launchconfig.sourcepathProvider"/>
 </launchConfiguration>
diff --git 
a/juneau-microservice/juneau-microservice-ftest/juneau-microservice-test.launch 
b/juneau-microservice/juneau-microservice-ftest/juneau-microservice-test.launch
index 9ce36ac..d42cc79 100644
--- 
a/juneau-microservice/juneau-microservice-ftest/juneau-microservice-test.launch
+++ 
b/juneau-microservice/juneau-microservice-ftest/juneau-microservice-test.launch
@@ -1,18 +1,18 @@
 <?xml version="1.0" encoding="UTF-8" standalone="no"?>
 <launchConfiguration type="org.eclipse.jdt.launching.localJavaApplication">
-<listAttribute key="org.eclipse.debug.core.MAPPED_RESOURCE_PATHS">
-<listEntry value="/juneau-microservice-ftest"/>
-</listAttribute>
-<listAttribute key="org.eclipse.debug.core.MAPPED_RESOURCE_TYPES">
-<listEntry value="4"/>
-</listAttribute>
-<booleanAttribute key="org.eclipse.jdt.debug.ui.CONSIDER_INHERITED_MAIN" 
value="true"/>
-<booleanAttribute key="org.eclipse.jdt.debug.ui.INCLUDE_EXTERNAL_JARS" 
value="true"/>
-<booleanAttribute 
key="org.eclipse.jdt.launching.ATTR_USE_START_ON_FIRST_THREAD" value="true"/>
-<stringAttribute key="org.eclipse.jdt.launching.CLASSPATH_PROVIDER" 
value="org.eclipse.m2e.launchconfig.classpathProvider"/>
-<stringAttribute key="org.eclipse.jdt.launching.JRE_CONTAINER" 
value="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8"/>
-<stringAttribute key="org.eclipse.jdt.launching.MAIN_TYPE" 
value="org.apache.juneau.microservice.jetty.JettyMicroservice"/>
-<stringAttribute key="org.eclipse.jdt.launching.PROGRAM_ARGUMENTS" 
value="juneau-microservice-test.cfg"/>
-<stringAttribute key="org.eclipse.jdt.launching.PROJECT_ATTR" 
value="juneau-microservice-ftest"/>
-<stringAttribute key="org.eclipse.jdt.launching.SOURCE_PATH_PROVIDER" 
value="org.eclipse.m2e.launchconfig.sourcepathProvider"/>
+    <listAttribute key="org.eclipse.debug.core.MAPPED_RESOURCE_PATHS">
+        <listEntry value="/juneau-microservice-ftest"/>
+    </listAttribute>
+    <listAttribute key="org.eclipse.debug.core.MAPPED_RESOURCE_TYPES">
+        <listEntry value="4"/>
+    </listAttribute>
+    <booleanAttribute key="org.eclipse.jdt.debug.ui.CONSIDER_INHERITED_MAIN" 
value="true"/>
+    <booleanAttribute key="org.eclipse.jdt.debug.ui.INCLUDE_EXTERNAL_JARS" 
value="true"/>
+    <booleanAttribute 
key="org.eclipse.jdt.launching.ATTR_USE_START_ON_FIRST_THREAD" value="true"/>
+    <stringAttribute key="org.eclipse.jdt.launching.CLASSPATH_PROVIDER" 
value="org.eclipse.m2e.launchconfig.classpathProvider"/>
+    <stringAttribute key="org.eclipse.jdt.launching.JRE_CONTAINER" 
value="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8"/>
+    <stringAttribute key="org.eclipse.jdt.launching.MAIN_TYPE" 
value="org.apache.juneau.microservice.jetty.JettyMicroservice"/>
+    <stringAttribute key="org.eclipse.jdt.launching.PROGRAM_ARGUMENTS" 
value="juneau-microservice-test.cfg"/>
+    <stringAttribute key="org.eclipse.jdt.launching.PROJECT_ATTR" 
value="juneau-microservice-ftest"/>
+    <stringAttribute key="org.eclipse.jdt.launching.SOURCE_PATH_PROVIDER" 
value="org.eclipse.m2e.launchconfig.sourcepathProvider"/>
 </launchConfiguration>
diff --git 
a/juneau-microservice/juneau-my-jetty-microservice/my-jetty-microservice.launch 
b/juneau-microservice/juneau-my-jetty-microservice/my-jetty-microservice.launch
index 20c5811..b5848e7 100644
--- 
a/juneau-microservice/juneau-my-jetty-microservice/my-jetty-microservice.launch
+++ 
b/juneau-microservice/juneau-my-jetty-microservice/my-jetty-microservice.launch
@@ -1,17 +1,17 @@
 <?xml version="1.0" encoding="UTF-8" standalone="no"?>
 <launchConfiguration type="org.eclipse.jdt.launching.localJavaApplication">
-<listAttribute key="org.eclipse.debug.core.MAPPED_RESOURCE_PATHS">
-<listEntry 
value="/juneau-my-jetty-microservice/src/main/java/org/apache/juneau/microservice/jetty/template/App.java"/>
-</listAttribute>
-<listAttribute key="org.eclipse.debug.core.MAPPED_RESOURCE_TYPES">
-<listEntry value="1"/>
-</listAttribute>
-<booleanAttribute key="org.eclipse.jdt.debug.ui.CONSIDER_INHERITED_MAIN" 
value="true"/>
-<booleanAttribute key="org.eclipse.jdt.debug.ui.INCLUDE_EXTERNAL_JARS" 
value="true"/>
-<booleanAttribute 
key="org.eclipse.jdt.launching.ATTR_USE_START_ON_FIRST_THREAD" value="true"/>
-<stringAttribute key="org.eclipse.jdt.launching.CLASSPATH_PROVIDER" 
value="org.eclipse.m2e.launchconfig.classpathProvider"/>
-<stringAttribute key="org.eclipse.jdt.launching.JRE_CONTAINER" 
value="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8"/>
-<stringAttribute key="org.eclipse.jdt.launching.MAIN_TYPE" 
value="org.apache.juneau.microservice.jetty.template.App"/>
-<stringAttribute key="org.eclipse.jdt.launching.PROJECT_ATTR" 
value="juneau-my-jetty-microservice"/>
-<stringAttribute key="org.eclipse.jdt.launching.SOURCE_PATH_PROVIDER" 
value="org.eclipse.m2e.launchconfig.sourcepathProvider"/>
+    <listAttribute key="org.eclipse.debug.core.MAPPED_RESOURCE_PATHS">
+        <listEntry 
value="/juneau-my-jetty-microservice/src/main/java/org/apache/juneau/microservice/jetty/template/App.java"/>
+    </listAttribute>
+    <listAttribute key="org.eclipse.debug.core.MAPPED_RESOURCE_TYPES">
+        <listEntry value="1"/>
+    </listAttribute>
+    <booleanAttribute key="org.eclipse.jdt.debug.ui.CONSIDER_INHERITED_MAIN" 
value="true"/>
+    <booleanAttribute key="org.eclipse.jdt.debug.ui.INCLUDE_EXTERNAL_JARS" 
value="true"/>
+    <booleanAttribute 
key="org.eclipse.jdt.launching.ATTR_USE_START_ON_FIRST_THREAD" value="true"/>
+    <stringAttribute key="org.eclipse.jdt.launching.CLASSPATH_PROVIDER" 
value="org.eclipse.m2e.launchconfig.classpathProvider"/>
+    <stringAttribute key="org.eclipse.jdt.launching.JRE_CONTAINER" 
value="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8"/>
+    <stringAttribute key="org.eclipse.jdt.launching.MAIN_TYPE" 
value="org.apache.juneau.microservice.jetty.template.App"/>
+    <stringAttribute key="org.eclipse.jdt.launching.PROJECT_ATTR" 
value="juneau-my-jetty-microservice"/>
+    <stringAttribute key="org.eclipse.jdt.launching.SOURCE_PATH_PROVIDER" 
value="org.eclipse.m2e.launchconfig.sourcepathProvider"/>
 </launchConfiguration>
diff --git 
a/juneau-microservice/juneau-my-springboot-microservice/my-springboot-microservice.launch
 
b/juneau-microservice/juneau-my-springboot-microservice/my-springboot-microservice.launch
index 2fbb1ff..3794504 100644
--- 
a/juneau-microservice/juneau-my-springboot-microservice/my-springboot-microservice.launch
+++ 
b/juneau-microservice/juneau-my-springboot-microservice/my-springboot-microservice.launch
@@ -1,17 +1,17 @@
 <?xml version="1.0" encoding="UTF-8" standalone="no"?>
 <launchConfiguration type="org.eclipse.jdt.launching.localJavaApplication">
-<listAttribute key="org.eclipse.debug.core.MAPPED_RESOURCE_PATHS">
-<listEntry 
value="/juneau-my-springboot-microservice/src/main/java/org/apache/juneau/microservice/springboot/template/App.java"/>
-</listAttribute>
-<listAttribute key="org.eclipse.debug.core.MAPPED_RESOURCE_TYPES">
-<listEntry value="1"/>
-</listAttribute>
-<booleanAttribute key="org.eclipse.jdt.debug.ui.CONSIDER_INHERITED_MAIN" 
value="true"/>
-<booleanAttribute key="org.eclipse.jdt.debug.ui.INCLUDE_EXTERNAL_JARS" 
value="true"/>
-<booleanAttribute 
key="org.eclipse.jdt.launching.ATTR_USE_START_ON_FIRST_THREAD" value="true"/>
-<stringAttribute key="org.eclipse.jdt.launching.CLASSPATH_PROVIDER" 
value="org.eclipse.m2e.launchconfig.classpathProvider"/>
-<stringAttribute key="org.eclipse.jdt.launching.JRE_CONTAINER" 
value="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8"/>
-<stringAttribute key="org.eclipse.jdt.launching.MAIN_TYPE" 
value="org.apache.juneau.microservice.springboot.template.App"/>
-<stringAttribute key="org.eclipse.jdt.launching.PROJECT_ATTR" 
value="juneau-my-springboot-microservice"/>
-<stringAttribute key="org.eclipse.jdt.launching.SOURCE_PATH_PROVIDER" 
value="org.eclipse.m2e.launchconfig.sourcepathProvider"/>
+    <listAttribute key="org.eclipse.debug.core.MAPPED_RESOURCE_PATHS">
+        <listEntry 
value="/juneau-my-springboot-microservice/src/main/java/org/apache/juneau/microservice/springboot/template/App.java"/>
+    </listAttribute>
+    <listAttribute key="org.eclipse.debug.core.MAPPED_RESOURCE_TYPES">
+        <listEntry value="1"/>
+    </listAttribute>
+    <booleanAttribute key="org.eclipse.jdt.debug.ui.CONSIDER_INHERITED_MAIN" 
value="true"/>
+    <booleanAttribute key="org.eclipse.jdt.debug.ui.INCLUDE_EXTERNAL_JARS" 
value="true"/>
+    <booleanAttribute 
key="org.eclipse.jdt.launching.ATTR_USE_START_ON_FIRST_THREAD" value="true"/>
+    <stringAttribute key="org.eclipse.jdt.launching.CLASSPATH_PROVIDER" 
value="org.eclipse.m2e.launchconfig.classpathProvider"/>
+    <stringAttribute key="org.eclipse.jdt.launching.JRE_CONTAINER" 
value="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8"/>
+    <stringAttribute key="org.eclipse.jdt.launching.MAIN_TYPE" 
value="org.apache.juneau.microservice.springboot.template.App"/>
+    <stringAttribute key="org.eclipse.jdt.launching.PROJECT_ATTR" 
value="juneau-my-springboot-microservice"/>
+    <stringAttribute key="org.eclipse.jdt.launching.SOURCE_PATH_PROVIDER" 
value="org.eclipse.m2e.launchconfig.sourcepathProvider"/>
 </launchConfiguration>
diff --git 
a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/ResponseProcessorList.java
 
b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/ResponseProcessorList.java
index ea593fe..a09c353 100644
--- 
a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/ResponseProcessorList.java
+++ 
b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/ResponseProcessorList.java
@@ -12,6 +12,9 @@
 // 
***************************************************************************************************************************
 package org.apache.juneau.rest;
 
+import static org.apache.juneau.assertions.Assertions.*;
+import static java.util.Arrays.*;
+
 import org.apache.juneau.*;
 import org.apache.juneau.collections.*;
 import org.apache.juneau.cp.*;
@@ -75,10 +78,10 @@ public class ResponseProcessorList {
                 *
                 * @param values The values to add.
                 * @return This object (for method chaining).
+                * @throws IllegalArgumentException if any class does not 
extend from {@link ResponseProcessor}.
                 */
-               @SuppressWarnings("unchecked")
-               public Builder append(Class<? extends 
ResponseProcessor>...values) {
-                       entries.append((Object[])values);
+               public Builder add(Class<?>...values) {
+                       
entries.addAll(asList(assertClassArrayArgIsType("values", 
ResponseProcessor.class, values)));
                        return this;
                }
 
@@ -89,7 +92,7 @@ public class ResponseProcessorList {
                 * @return This object (for method chaining).
                 */
                public Builder append(ResponseProcessor...values) {
-                       entries.append((Object[])values);
+                       entries.addAll(asList(values));
                        return this;
                }
 
diff --git 
a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestContext.java
 
b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestContext.java
index 6a2ebf7..0975e35 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
@@ -46,7 +46,6 @@ import org.apache.juneau.collections.*;
 import org.apache.juneau.config.*;
 import org.apache.juneau.cp.*;
 import org.apache.juneau.dto.swagger.Swagger;
-import org.apache.juneau.encoders.*;
 import org.apache.juneau.html.*;
 import org.apache.juneau.html.annotation.*;
 import org.apache.juneau.http.annotation.Response;
@@ -149,79 +148,6 @@ public class RestContext extends BeanContext {
        public static final String REST_beanStore = PREFIX + ".beanStore.o";
 
        /**
-        * Configuration property:  Compression encoders.
-        *
-        * <h5 class='section'>Property:</h5>
-        * <ul class='spaced-list'>
-        *      <li><b>ID:</b>  {@link 
org.apache.juneau.rest.RestContext#REST_encoders REST_encoders}
-        *      <li><b>Name:</b>  <js>"RestContext.encoders.o"</js>
-        *      <li><b>Data type:</b>  <c>List&lt;{@link 
org.apache.juneau.encoders.Encoder}|Class&lt;{@link 
org.apache.juneau.encoders.Encoder}&gt;&gt;</c>
-        *      <li><b>Default:</b>  empty list
-        *      <li><b>Session property:</b>  <jk>false</jk>
-        *      <li><b>Annotations:</b>
-        *              <ul>
-        *                      <li class='ja'>{@link 
org.apache.juneau.rest.annotation.Rest#encoders()}
-        *                      <li class='ja'>{@link 
org.apache.juneau.rest.annotation.RestOp#encoders()}
-        *              </ul>
-        *      <li><b>Methods:</b>
-        *              <ul>
-        *                      <li class='jm'>{@link 
org.apache.juneau.rest.RestContextBuilder#encoders(Class...)}
-        *                      <li class='jm'>{@link 
org.apache.juneau.rest.RestContextBuilder#encoders(Encoder...)}
-        *              </ul>
-        * </ul>
-        *
-        * <h5 class='section'>Description:</h5>
-        * <p>
-        * These can be used to enable various kinds of compression (e.g. 
<js>"gzip"</js>) on requests and responses.
-        *
-        * <h5 class='section'>Example:</h5>
-        * <p class='bcode w800'>
-        *      <jc>// Option #1 - Registered via annotation.</jc>
-        *      <ja>@Rest</ja>(encoders={GzipEncoder.<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>.encoders(GzipEncoder.<jk>class</jk>);
-        *
-        *                      <jc>// Same, but using property.</jc>
-        *                      
<jv>builder</jv>.addTo(<jsf>REST_encoders</jsf>, GzipEncoder.<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>.encoders(GzipEncoder.<jk>class</jk>);
-        *              }
-        *
-        *              <jc>// Override at the method level.</jc>
-        *              
<ja>@RestGet</ja>(encoders={MySpecialEncoder.<jk>class</jk>}, 
inherit={<js>"ENCODERS"</js>})
-        *              <jk>public</jk> Object myMethod() {...}
-        *      }
-        * </p>
-        *
-        * <ul class='notes'>
-        *      <li>
-        *              When defined as a class, the implementation must have 
one of the following constructors:
-        *              <ul>
-        *                      <li><code><jk>public</jk> T(BeanContext)</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 RestEncoders}
-        * </ul>
-        */
-       public static final String REST_encoders = PREFIX + ".encoders.lo";
-
-       /**
         * Configuration property:  File finder.
         *
         * <h5 class='section'>Property:</h5>
@@ -1020,7 +946,7 @@ public class RestContext extends BeanContext {
        private final Supplier<?> resource;
        private final Class<?> resourceClass;
 
-       private final RestContextBuilder builder;
+       final RestContextBuilder builder;
        private final boolean
                allowBodyParam,
                renderResponseStackTraces;
@@ -2038,12 +1964,11 @@ public class RestContext extends BeanContext {
         * @return The REST method parameter resolvers for this REST resource.
         * @throws Exception If parameter resolvers could not be instantiated.
         */
-       @SuppressWarnings("unchecked")
        protected RestOpArgList createHookMethodArgs(Object resource, 
ContextProperties properties, BeanStore beanStore) throws Exception {
 
                RestOpArgList.Builder x = RestOpArgList.create();
 
-               x.append(
+               x.add(
                        ConfigArg.class,
                        HeaderArg.class,
                        HttpServletRequestArg.class,
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 a72e2f7..6b0f918 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
@@ -12,6 +12,7 @@
 // 
***************************************************************************************************************************
 package org.apache.juneau.rest;
 
+import static org.apache.juneau.assertions.Assertions.*;
 import static org.apache.juneau.http.HttpHeaders.*;
 import static org.apache.juneau.internal.ExceptionUtils.*;
 import static org.apache.juneau.internal.StringUtils.*;
@@ -140,11 +141,11 @@ public class RestContextBuilder extends 
BeanContextBuilder implements ServletCon
        NamedAttributeList defaultRequestAttributes = 
NamedAttributeList.create();
        HeaderListBuilder defaultRequestHeaders = HeaderList.create();
        HeaderListBuilder defaultResponseHeaders = HeaderList.create();
+       EncoderGroup.Builder encoders = EncoderGroup.create();
 
        Enablement debugDefault, debug;
 
-       @SuppressWarnings("unchecked")
-       ResponseProcessorList.Builder responseProcessors = 
ResponseProcessorList.create().append(
+       ResponseProcessorList.Builder responseProcessors = 
ResponseProcessorList.create().add(
                ReaderProcessor.class,
                InputStreamProcessor.class,
                ThrowableProcessor.class,
@@ -158,8 +159,7 @@ public class RestContextBuilder extends BeanContextBuilder 
implements ServletCon
 
        List<Object> children = new ArrayList<>();
 
-       @SuppressWarnings("unchecked")
-       RestOpArgList.Builder restOpArgs = RestOpArgList.create().append(
+       RestOpArgList.Builder restOpArgs = RestOpArgList.create().add(
                AttributeArg.class,
                BodyArg.class,
                ConfigArg.class,
@@ -216,7 +216,7 @@ public class RestContextBuilder extends BeanContextBuilder 
implements ServletCon
                        // Default values.
                        partSerializer(OpenApiSerializer.class);
                        partParser(OpenApiParser.class);
-                       encoders(IdentityEncoder.INSTANCE);
+                       encoders(IdentityEncoder.class);
 
                        // Pass-through default values.
                        if (parentContext.isPresent()) {
@@ -1495,39 +1495,67 @@ public class RestContextBuilder extends 
BeanContextBuilder implements ServletCon
        }
 
        /**
-        * <i><l>RestContext</l> configuration property:&emsp;</i>  Compression 
encoders.
+        * Compression encoders.
         *
         * <p>
         * These can be used to enable various kinds of compression (e.g. 
<js>"gzip"</js>) on requests and responses.
         *
-        * <ul class='seealso'>
-        *      <li class='jf'>{@link RestContext#REST_encoders}
-        * </ul>
+        * <h5 class='section'>Example:</h5>
+        * <p class='bcode w800'>
+        *      <jc>// Option #1 - Registered via annotation.</jc>
+        *      <ja>@Rest</ja>(encoders={GzipEncoder.<jk>class</jk>})
+        *      <jk>public class</jk> MyResource {
         *
-        * @param values The values to add to this setting.
-        * @return This object (for method chaining).
-        */
-       @FluentSetter
-       public RestContextBuilder encoders(Class<?>...values) {
-               return prependTo(REST_encoders, values);
-       }
-
-       /**
-        * <i><l>RestContext</l> configuration property:&emsp;</i>  Compression 
encoders.
+        *              <jc>// Option #2 - Registered via builder passed in 
through resource constructor.</jc>
+        *              <jk>public</jk> MyResource(RestContextBuilder 
<jv>builder</jv>) <jk>throws</jk> Exception {
         *
-        * <p>
-        * Same as {@link #encoders(Class...)} except input a pre-constructed 
instances.
+        *                      <jc>// Using method on builder.</jc>
+        *                      
<jv>builder</jv>.encoders(GzipEncoder.<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>.encoders(GzipEncoder.<jk>class</jk>);
+        *              }
+        *
+        *              <jc>// Override at the method level.</jc>
+        *              
<ja>@RestGet</ja>(encoders={MySpecialEncoder.<jk>class</jk>, 
EncoderGroup.Inherit.<jk>class</jk>})
+        *              <jk>public</jk> Object myMethod() {...}
+        *      }
+        * </p>
+        *
+        * <ul class='notes'>
+        *      <li>
+        *              When defined as a class, the implementation must have 
one of the following constructors:
+        *              <ul>
+        *                      <li><code><jk>public</jk> T(BeanContext)</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='jf'>{@link RestContext#REST_encoders}
+        *      <li class='link'>{@doc RestEncoders}
+        *      <li class='ja'>{@link Rest#encoders()}
+        *      <li class='ja'>{@link RestOp#encoders()}
+        *      <li class='ja'>{@link RestGet#encoders()}
+        *      <li class='ja'>{@link RestPut#encoders()}
+        *      <li class='ja'>{@link RestPost#encoders()}
+        *      <li class='ja'>{@link RestDelete#encoders()}
         * </ul>
         *
         * @param values The values to add to this setting.
         * @return This object (for method chaining).
+        * @throws IllegalArgumentException if any class does not extend from 
{@link Encoder}.
         */
        @FluentSetter
-       public RestContextBuilder encoders(Encoder...values) {
-               return prependTo(REST_encoders, values);
+       public final RestContextBuilder encoders(Class<?>...values) {
+               encoders.add(values);
+               return this;
        }
 
        /**
@@ -2064,11 +2092,11 @@ public class RestContextBuilder extends 
BeanContextBuilder implements ServletCon
         *
         * @param values The values to add to this setting.
         * @return This object (for method chaining).
+        * @throws IllegalArgumentException if any class does not extend from 
{@link ResponseProcessor}.
         */
-       @SuppressWarnings("unchecked")
        @FluentSetter
-       public RestContextBuilder responseProcessors(Class<? extends 
ResponseProcessor>...values) {
-               responseProcessors.append(values);
+       public RestContextBuilder responseProcessors(Class<?>...values) {
+               responseProcessors.add(assertClassArrayArgIsType("values", 
ResponseProcessor.class, values));
                return this;
        }
 
@@ -2276,11 +2304,11 @@ public class RestContextBuilder extends 
BeanContextBuilder implements ServletCon
         *
         * @param values The values to add to this setting.
         * @return This object (for method chaining).
+        * @throws IllegalArgumentException if any class does not extend from 
{@link RestOpArg}.
         */
        @FluentSetter
-       @SuppressWarnings("unchecked")
-       public RestContextBuilder restOpArgs(Class<? extends 
RestOpArg>...values) {
-               restOpArgs.append(values);
+       public RestContextBuilder restOpArgs(Class<?>...values) {
+               restOpArgs.add(assertClassArrayArgIsType("values", 
RestOpArg.class, values));
                return this;
        }
 
diff --git 
a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestOpArgList.java
 
b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestOpArgList.java
index df47e77..95a02f0 100644
--- 
a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestOpArgList.java
+++ 
b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestOpArgList.java
@@ -12,6 +12,8 @@
 // 
***************************************************************************************************************************
 package org.apache.juneau.rest;
 
+import static org.apache.juneau.assertions.Assertions.*;
+
 import java.util.*;
 
 import org.apache.juneau.collections.*;
@@ -75,10 +77,10 @@ public class RestOpArgList {
                 *
                 * @param values The values to add.
                 * @return This object (for method chaining).
+                * @throws IllegalArgumentException if any class does not 
extend from {@link RestOpArg}.
                 */
-               @SuppressWarnings("unchecked")
-               public Builder append(Class<? extends RestOpArg>...values) {
-                       entries.addAll(0, Arrays.asList(values));
+               public Builder add(Class<?>...values) {
+                       entries.addAll(0, 
Arrays.asList(assertClassArrayArgIsType("values", RestOpArg.class, values)));
                        return this;
                }
        }
diff --git 
a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestOpContext.java
 
b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestOpContext.java
index 13cd929..7d3f4a5 100644
--- 
a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestOpContext.java
+++ 
b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestOpContext.java
@@ -174,7 +174,7 @@ public class RestOpContext extends BeanContext implements 
Comparable<RestOpConte
                        bs.addBean(UrlPathMatcher[].class, pathMatchers);
                        bs.addBean(UrlPathMatcher.class, pathMatchers.length > 
0 ? pathMatchers[0] : null);
 
-                       encoders = createEncoders(r, cp, bs);
+                       encoders = createEncoders(r, builder, bs);
                        bs.addBean(EncoderGroup.class, encoders);
 
                        jsonSchemaGenerator = createJsonSchemaGenerator(r, cp, 
bs);
@@ -376,9 +376,9 @@ public class RestOpContext extends BeanContext implements 
Comparable<RestOpConte
         * <p>
         * Instantiates based on the following logic:
         * <ul>
-        *      <li>Looks for {@link RestContext#REST_encoders} value set via 
any of the following:
+        *      <li>Looks for encoders set via any of the following:
         *              <ul>
-        *                      <li>{@link 
RestContextBuilder#encoders(Class...)}/{@link 
RestContextBuilder#encoders(Encoder...)}
+        *                      <li>{@link 
RestOpContextBuilder#encoders(Class...)}
         *                      <li>{@link RestOp#encoders()}.
         *                      <li>{@link Rest#encoders()}.
         *              </ul>
@@ -395,38 +395,28 @@ public class RestOpContext extends BeanContext implements 
Comparable<RestOpConte
         * </ul>
         *
         * @param resource The REST resource object.
-        * @param properties xxx
+        * @param builder The builder for this object.
         * @param beanStore The bean store to use for retrieving and creating 
beans.
         * @return The encoders for this REST resource method.
         * @throws Exception If encoders could not be instantiated.
-        * @see RestContext#REST_encoders
         */
-       protected EncoderGroup createEncoders(Object resource, 
ContextProperties properties, BeanStore beanStore) throws Exception {
-
-               Encoder[] x = properties.getInstanceArray(REST_encoders, 
Encoder.class, beanStore).orElse(null);
+       protected EncoderGroup createEncoders(Object resource, 
RestOpContextBuilder builder, BeanStore beanStore) throws Exception {
 
-               if (x == null)
-                       x = beanStore.getBean(Encoder[].class).orElse(null);
-
-               if (x == null)
-                       x = new Encoder[0];
+               EncoderGroup.Builder x = builder.encoders;
 
-               EncoderGroup g = EncoderGroup
-                       .create()
-                       .append(IdentityEncoder.INSTANCE)
-                       .append(x)
-                       .build();
+               if (x.isEmpty())
+                       x.add(EncoderGroup.Inherit.class);
 
-               g = BeanStore
+               x = BeanStore
                        .of(beanStore, resource)
-                       .addBean(EncoderGroup.class, g)
-                       .beanCreateMethodFinder(EncoderGroup.class, resource)
+                       .addBean(EncoderGroup.Builder.class, x)
+                       .beanCreateMethodFinder(EncoderGroup.Builder.class, 
resource)
                        .find("createEncoders", Method.class)
                        .thenFind("createEncoders")
-                       .withDefault(g)
+                       .withDefault(x)
                        .run();
 
-               return g;
+               return x.build();
        }
 
        /**
diff --git 
a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestOpContextBuilder.java
 
b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestOpContextBuilder.java
index fc22448..d52023e 100644
--- 
a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestOpContextBuilder.java
+++ 
b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestOpContextBuilder.java
@@ -13,6 +13,7 @@
 package org.apache.juneau.rest;
 
 import static java.util.Arrays.*;
+import static org.apache.juneau.assertions.Assertions.*;
 import static org.apache.juneau.rest.HttpRuntimeException.*;
 import java.lang.annotation.*;
 import java.util.*;
@@ -20,6 +21,7 @@ import org.apache.http.*;
 import org.apache.juneau.*;
 import org.apache.juneau.collections.*;
 import org.apache.juneau.cp.*;
+import org.apache.juneau.encoders.*;
 import org.apache.juneau.http.header.*;
 import org.apache.juneau.http.part.*;
 import org.apache.juneau.http.remote.*;
@@ -51,6 +53,7 @@ public class RestOpContextBuilder extends BeanContextBuilder {
        Set<String> roleGuard, rolesDeclared;
        RestGuardList.Builder guards = RestGuardList.create();
        RestConverterList.Builder converters = RestConverterList.create();
+       EncoderGroup.Builder encoders;
 
        Charset defaultCharset;
        Long maxInput;
@@ -93,6 +96,7 @@ public class RestOpContextBuilder extends BeanContextBuilder {
                this.defaultRequestHeaders = HeaderList.create();
                this.defaultResponseHeaders = HeaderList.create();
                this.restMatchers = RestMatcherList.create();
+               this.encoders = 
EncoderGroup.create().inheritFrom(context.builder.encoders).beanStore(beanStore);
 
                MethodInfo mi = MethodInfo.of(context.getResourceClass(), 
method);
 
@@ -291,11 +295,11 @@ public class RestOpContextBuilder extends 
BeanContextBuilder {
         *
         * @param values The values to add to this setting.
         * @return This object (for method chaining).
+        * @throws IllegalArgumentException if any class does not extend from 
{@link RestConverter}.
         */
-       @SuppressWarnings("unchecked")
        @FluentSetter
-       public RestOpContextBuilder converters(Class<? extends 
RestConverter>...values) {
-               converters.append(values);
+       public RestOpContextBuilder converters(Class<?>...values) {
+               converters.append(assertClassArrayArgIsType("values", 
RestConverter.class, values));
                return this;
        }
 
@@ -516,6 +520,70 @@ public class RestOpContextBuilder extends 
BeanContextBuilder {
        }
 
        /**
+        * Compression encoders.
+        *
+        * <p>
+        * These can be used to enable various kinds of compression (e.g. 
<js>"gzip"</js>) on requests and responses.
+        *
+        * <h5 class='section'>Example:</h5>
+        * <p class='bcode w800'>
+        *      <jc>// Option #1 - Registered via annotation.</jc>
+        *      <ja>@Rest</ja>(encoders={GzipEncoder.<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>.encoders(GzipEncoder.<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>.encoders(GzipEncoder.<jk>class</jk>);
+        *              }
+        *
+        *              <jc>// Override at the method level.</jc>
+        *              
<ja>@RestGet</ja>(encoders={MySpecialEncoder.<jk>class</jk>}, 
inherit={<js>"ENCODERS"</js>})
+        *              <jk>public</jk> Object myMethod() {...}
+        *      }
+        * </p>
+        *
+        * <ul class='notes'>
+        *      <li>
+        *              When defined as a class, the implementation must have 
one of the following constructors:
+        *              <ul>
+        *                      <li><code><jk>public</jk> T(BeanContext)</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 RestEncoders}
+        *      <li class='ja'>{@link Rest#encoders()}
+        *      <li class='ja'>{@link RestOp#encoders()}
+        *      <li class='ja'>{@link RestGet#encoders()}
+        *      <li class='ja'>{@link RestPut#encoders()}
+        *      <li class='ja'>{@link RestPost#encoders()}
+        *      <li class='ja'>{@link RestDelete#encoders()}
+        * </ul>
+        *
+        * @param values The values to add to this setting.
+        * @return This object (for method chaining).
+        * @throws IllegalArgumentException if any class does not extend from 
{@link Encoder}.
+        */
+       @FluentSetter
+       public final RestOpContextBuilder encoders(Class<?>...values) {
+               encoders.add(assertClassArrayArgIsType("values", Encoder.class, 
values));
+               return this;
+       }
+
+       /**
         * Guards.
         *
         * <p>
@@ -579,11 +647,11 @@ public class RestOpContextBuilder extends 
BeanContextBuilder {
         *
         * @param values The values to add to this setting.
         * @return This object (for method chaining).
+        * @throws IllegalArgumentException if any class does not extend from 
{@link RestGuard}.
         */
-       @SuppressWarnings("unchecked")
        @FluentSetter
-       public RestOpContextBuilder guards(Class<? extends RestGuard>...values) 
{
-               guards.append(values);
+       public RestOpContextBuilder guards(Class<?>...values) {
+               guards.append(assertClassArrayArgIsType("values", 
RestGuard.class, values));
                return this;
        }
 
@@ -723,11 +791,11 @@ public class RestOpContextBuilder extends 
BeanContextBuilder {
         *
         * @param values The new values for this setting.
         * @return This object (for method chaining).
+        * @throws IllegalArgumentException if any class does not extend from 
{@link RestMatcher}.
         */
-       @SuppressWarnings("unchecked")
        @FluentSetter
-       public RestOpContextBuilder matchers(Class<? extends 
RestMatcher>...values) {
-               restMatchers.append(values);
+       public RestOpContextBuilder matchers(Class<?>...values) {
+               restMatchers.append(assertClassArrayArgIsType("values", 
RestMatcher.class, values));
                return this;
        }
 
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 46c86a9..20431b2 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
@@ -621,7 +621,8 @@ public @interface Rest {
         * These can be used to enable various kinds of compression (e.g. 
<js>"gzip"</js>) on requests and responses.
         *
         * <ul class='seealso'>
-        *      <li class='jf'>{@link RestContext#REST_encoders}
+        *      <li class='jm'>{@link RestContextBuilder#encoders(Class...)}
+        *      <li class='jm'>{@link RestOpContextBuilder#encoders(Class...)}
         * </ul>
         */
        Class<? extends Encoder>[] encoders() default {};
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 69e3313..046298b 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
@@ -1053,6 +1053,7 @@ public class RestAnnotation {
                        b.responseProcessors(a.responseProcessors());
                        b.children((Object[])a.children());
                        b.restOpArgs(a.restOpArgs());
+                       b.encoders(a.encoders());
                        type(a.contextClass()).ifPresent(x -> 
b.contextClass(x));
                        string(a.uriContext()).ifPresent(x -> b.uriContext(x));
                        string(a.uriAuthority()).ifPresent(x -> 
b.uriAuthority(x));
@@ -1102,7 +1103,6 @@ public class RestAnnotation {
                        b.set(REST_parsers, 
merge(ConverterUtils.toType(b.peek(REST_parsers), Object[].class), 
a.parsers()));
                        type(a.partSerializer()).ifPresent(x -> 
b.set(REST_partSerializer, x));
                        type(a.partParser()).ifPresent(x -> 
b.set(REST_partParser, x));
-                       b.prependTo(REST_encoders, a.encoders());
                        strings(a.produces()).map(MediaType::of).forEach(x -> 
b.produces(x));
                        strings(a.consumes()).map(MediaType::of).forEach(x -> 
b.consumes(x));
                        b.converters(a.converters());
diff --git 
a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/annotation/RestDelete.java
 
b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/annotation/RestDelete.java
index d5e0f93..5489a3f 100644
--- 
a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/annotation/RestDelete.java
+++ 
b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/annotation/RestDelete.java
@@ -22,6 +22,7 @@ import org.apache.juneau.*;
 import org.apache.juneau.annotation.*;
 import org.apache.juneau.rest.*;
 import org.apache.juneau.dto.swagger.*;
+import org.apache.juneau.encoders.*;
 
 /**
  * Identifies a REST DELETE operation Java method on a {@link RestServlet} 
implementation class.
@@ -330,10 +331,10 @@ public @interface RestDelete {
         * </ul>
         *
         * <ul class='seealso'>
-        *      <li class='jf'>{@link RestContext#REST_encoders}
+        *      <li class='jm'>{@link RestOpContextBuilder#encoders(Class...)}
         * </ul>
         */
-       Class<?>[] encoders() default {};
+       Class<? extends Encoder>[] encoders() default {};
 
        /**
         * Method-level guards.
diff --git 
a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/annotation/RestDeleteAnnotation.java
 
b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/annotation/RestDeleteAnnotation.java
index b250b8a..812acdb 100644
--- 
a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/annotation/RestDeleteAnnotation.java
+++ 
b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/annotation/RestDeleteAnnotation.java
@@ -14,8 +14,6 @@ package org.apache.juneau.rest.annotation;
 
 import static org.apache.juneau.http.HttpHeaders.*;
 import static org.apache.juneau.internal.ArrayUtils.*;
-import static org.apache.juneau.rest.RestContext.*;
-import static org.apache.juneau.rest.util.RestUtils.*;
 import static org.apache.juneau.http.HttpParts.*;
 
 import java.lang.annotation.*;
@@ -23,7 +21,7 @@ import java.nio.charset.*;
 
 import org.apache.juneau.*;
 import org.apache.juneau.annotation.*;
-import org.apache.juneau.internal.*;
+import org.apache.juneau.encoders.*;
 import org.apache.juneau.reflect.*;
 import org.apache.juneau.rest.*;
 import org.apache.juneau.svl.*;
@@ -59,7 +57,7 @@ public class RestDeleteAnnotation {
                Class<? extends RestGuard>[] guards = new Class[0];
                Class<? extends RestMatcher>[] matchers = new Class[0];
                Class<? extends RestOpContext> contextClass = 
RestOpContext.Null.class;
-               Class<?>[] encoders=new Class<?>[0];
+               Class<? extends Encoder>[] encoders = new Class[0];
                OpSwagger swagger = OpSwaggerAnnotation.DEFAULT;
                String clientVersion="", debug="", defaultAccept="", 
defaultCharset="", rolesDeclared="", roleGuard="", summary="", value="";
                String[] defaultQueryData={}, defaultRequestAttributes={}, 
defaultRequestHeaders={}, defaultResponseHeaders={}, description={}, path={};
@@ -196,7 +194,7 @@ public class RestDeleteAnnotation {
                 * @param value The new value for this property.
                 * @return This object (for method chaining).
                 */
-               public Builder encoders(Class<?>...value) {
+               public Builder encoders(Class<? extends Encoder>...value) {
                        this.encoders = value;
                        return this;
                }
@@ -311,7 +309,7 @@ public class RestDeleteAnnotation {
                private final Class<? extends RestGuard>[] guards;
                private final Class<? extends RestMatcher>[] matchers;
                private final Class<? extends RestOpContext> contextClass;
-               private final Class<?>[] encoders;
+               private final Class<? extends Encoder>[] encoders;
                private final OpSwagger swagger;
                private final String clientVersion, debug, defaultAccept, 
defaultCharset, rolesDeclared, roleGuard, summary, value;
                private final String[] defaultQueryData, 
defaultRequestAttributes, defaultRequestHeaders, defaultResponseHeaders, 
description, path;
@@ -391,7 +389,7 @@ public class RestDeleteAnnotation {
                }
 
                @Override /* RestDelete */
-               public Class<?>[] encoders() {
+               public Class<? extends Encoder>[] encoders() {
                        return encoders;
                }
 
@@ -456,7 +454,7 @@ public class RestDeleteAnnotation {
 
                        b.httpMethod("delete");
 
-                       b.set(REST_encoders, 
merge(ConverterUtils.toType(b.peek(REST_encoders), Object[].class), 
a.encoders()));
+                       b.encoders(a.encoders());
                        type(a.contextClass()).ifPresent(x -> 
b.contextClass(x));
                        strings(a.defaultRequestHeaders()).map(x -> 
stringHeader(x)).forEach(x -> b.defaultRequestHeaders(x));
                        strings(a.defaultResponseHeaders()).map(x -> 
stringHeader(x)).forEach(x -> b.defaultResponseHeaders(x));
diff --git 
a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/annotation/RestGet.java
 
b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/annotation/RestGet.java
index 1ce1962..46bbf19 100644
--- 
a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/annotation/RestGet.java
+++ 
b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/annotation/RestGet.java
@@ -22,6 +22,7 @@ import org.apache.juneau.*;
 import org.apache.juneau.annotation.*;
 import org.apache.juneau.rest.*;
 import org.apache.juneau.dto.swagger.*;
+import org.apache.juneau.encoders.*;
 import org.apache.juneau.http.header.*;
 
 /**
@@ -345,10 +346,10 @@ public @interface RestGet {
         * </ul>
         *
         * <ul class='seealso'>
-        *      <li class='jf'>{@link RestContext#REST_encoders}
+        *      <li class='jm'>{@link RestOpContextBuilder#encoders(Class...)}
         * </ul>
         */
-       Class<?>[] encoders() default {};
+       Class<? extends Encoder>[] encoders() default {};
 
        /**
         * Method-level guards.
diff --git 
a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/annotation/RestGetAnnotation.java
 
b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/annotation/RestGetAnnotation.java
index 8ba3d1c..a1be0bc 100644
--- 
a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/annotation/RestGetAnnotation.java
+++ 
b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/annotation/RestGetAnnotation.java
@@ -23,6 +23,7 @@ import java.nio.charset.*;
 
 import org.apache.juneau.*;
 import org.apache.juneau.annotation.*;
+import org.apache.juneau.encoders.*;
 import org.apache.juneau.http.header.*;
 import org.apache.juneau.internal.*;
 import org.apache.juneau.reflect.*;
@@ -61,7 +62,8 @@ public class RestGetAnnotation {
                Class<? extends RestGuard>[] guards = new Class[0];
                Class<? extends RestMatcher>[] matchers = new Class[0];
                Class<? extends RestOpContext> contextClass = 
RestOpContext.Null.class;
-               Class<?>[] encoders=new Class<?>[0], serializers=new 
Class<?>[0];
+               Class<? extends Encoder>[] encoders = new Class[0];
+               Class<?>[] serializers=new Class<?>[0];
                OpSwagger swagger = OpSwaggerAnnotation.DEFAULT;
                String clientVersion="", debug="", defaultAccept="", 
defaultCharset="", rolesDeclared="", roleGuard="", summary="", value="";
                String[] defaultQueryData={}, defaultRequestAttributes={}, 
defaultRequestHeaders={}, defaultResponseHeaders={}, description={}, path={}, 
produces={};
@@ -209,7 +211,7 @@ public class RestGetAnnotation {
                 * @param value The new value for this property.
                 * @return This object (for method chaining).
                 */
-               public Builder encoders(Class<?>...value) {
+               public Builder encoders(Class<? extends Encoder>...value) {
                        this.encoders = value;
                        return this;
                }
@@ -347,7 +349,8 @@ public class RestGetAnnotation {
                private final Class<? extends RestGuard>[] guards;
                private final Class<? extends RestMatcher>[] matchers;
                private final Class<? extends RestOpContext> contextClass;
-               private final Class<?>[] encoders, serializers;
+               private final Class<? extends Encoder>[] encoders;
+               private final Class<?>[] serializers;
                private final OpSwagger swagger;
                private final String clientVersion, debug, defaultAccept, 
defaultCharset, rolesDeclared, roleGuard, summary, value;
                private final String[] defaultQueryData, 
defaultRequestAttributes, defaultRequestHeaders, defaultResponseHeaders, 
description, path, produces;
@@ -435,7 +438,7 @@ public class RestGetAnnotation {
                }
 
                @Override /* RestGet */
-               public Class<?>[] encoders() {
+               public Class<? extends Encoder>[] encoders() {
                        return encoders;
                }
 
@@ -511,7 +514,7 @@ public class RestGetAnnotation {
                        b.httpMethod("get");
 
                        b.set(REST_serializers, 
merge(ConverterUtils.toType(b.peek(REST_serializers), Object[].class), 
a.serializers()));
-                       b.set(REST_encoders, 
merge(ConverterUtils.toType(b.peek(REST_encoders), Object[].class), 
a.encoders()));
+                       b.encoders(a.encoders());
                        type(a.contextClass()).ifPresent(x -> 
b.contextClass(x));
                        strings(a.produces()).map(MediaType::of).forEach(x -> 
b.produces(x));
                        strings(a.defaultRequestHeaders()).map(x -> 
stringHeader(x)).forEach(x -> b.defaultRequestHeaders(x));
diff --git 
a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/annotation/RestOp.java
 
b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/annotation/RestOp.java
index 24adede..3840d2c 100644
--- 
a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/annotation/RestOp.java
+++ 
b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/annotation/RestOp.java
@@ -24,6 +24,7 @@ import org.apache.juneau.rest.*;
 import org.apache.juneau.http.header.*;
 import org.apache.juneau.http.remote.*;
 import org.apache.juneau.dto.swagger.*;
+import org.apache.juneau.encoders.*;
 
 /**
  * Identifies a REST operation Java method on a {@link RestServlet} 
implementation class.
@@ -400,10 +401,10 @@ public @interface RestOp {
         * </ul>
         *
         * <ul class='seealso'>
-        *      <li class='jf'>{@link RestContext#REST_encoders}
+        *      <li class='jm'>{@link RestOpContextBuilder#encoders(Class...)}
         * </ul>
         */
-       Class<?>[] encoders() default {};
+       Class<? extends Encoder>[] encoders() default {};
 
        /**
         * Method-level guards.
diff --git 
a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/annotation/RestOpAnnotation.java
 
b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/annotation/RestOpAnnotation.java
index f13662b..1da5e4a 100644
--- 
a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/annotation/RestOpAnnotation.java
+++ 
b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/annotation/RestOpAnnotation.java
@@ -23,6 +23,7 @@ import java.nio.charset.*;
 
 import org.apache.juneau.*;
 import org.apache.juneau.annotation.*;
+import org.apache.juneau.encoders.*;
 import org.apache.juneau.http.header.*;
 import org.apache.juneau.internal.*;
 import org.apache.juneau.reflect.*;
@@ -61,7 +62,8 @@ public class RestOpAnnotation {
                Class<? extends RestGuard>[] guards = new Class[0];
                Class<? extends RestMatcher>[] matchers = new Class[0];
                Class<? extends RestOpContext> contextClass = 
RestOpContext.Null.class;
-               Class<?>[] encoders=new Class<?>[0], parsers=new Class<?>[0], 
serializers=new Class<?>[0];
+               Class<? extends Encoder>[] encoders = new Class[0];
+               Class<?>[] parsers=new Class<?>[0], serializers=new Class<?>[0];
                OpSwagger swagger = OpSwaggerAnnotation.DEFAULT;
                String clientVersion="", debug="", defaultAccept="", 
defaultCharset="", defaultContentType="", maxInput="", method="", 
rolesDeclared="", roleGuard="", summary="", value="";
                String[] consumes={}, defaultFormData={}, defaultQueryData={}, 
defaultRequestAttributes={}, defaultRequestHeaders={}, 
defaultResponseHeaders={}, description={}, path={}, produces={};
@@ -242,7 +244,7 @@ public class RestOpAnnotation {
                 * @param value The new value for this property.
                 * @return This object (for method chaining).
                 */
-               public Builder encoders(Class<?>...value) {
+               public Builder encoders(Class<? extends Encoder>...value) {
                        this.encoders = value;
                        return this;
                }
@@ -413,7 +415,8 @@ public class RestOpAnnotation {
                private final Class<? extends RestGuard>[] guards;
                private final Class<? extends RestMatcher>[] matchers;
                private final Class<? extends RestOpContext> contextClass;
-               private final Class<?>[] encoders, parsers, serializers;
+               private final Class<? extends Encoder>[] encoders;
+               private final Class<?>[] parsers, serializers;
                private final OpSwagger swagger;
                private final String clientVersion, debug, defaultAccept, 
defaultCharset, defaultContentType, maxInput, method, rolesDeclared, roleGuard, 
summary, value;
                private final String[] consumes, defaultFormData, 
defaultQueryData, defaultRequestAttributes, defaultRequestHeaders, 
defaultResponseHeaders, description, path, produces;
@@ -522,7 +525,7 @@ public class RestOpAnnotation {
                }
 
                @Override /* RestOp */
-               public Class<?>[] encoders() {
+               public Class<? extends Encoder>[] encoders() {
                        return encoders;
                }
 
@@ -612,7 +615,7 @@ public class RestOpAnnotation {
 
                        b.set(REST_serializers, 
merge(ConverterUtils.toType(b.peek(REST_serializers), Object[].class), 
a.serializers()));
                        b.set(REST_parsers, 
merge(ConverterUtils.toType(b.peek(REST_parsers), Object[].class), 
a.parsers()));
-                       b.set(REST_encoders, 
merge(ConverterUtils.toType(b.peek(REST_encoders), Object[].class), 
a.encoders()));
+                       b.encoders(a.encoders());
                        type(a.contextClass()).ifPresent(x -> 
b.contextClass(x));
                        strings(a.produces()).map(MediaType::of).forEach(x -> 
b.produces(x));
                        strings(a.consumes()).map(MediaType::of).forEach(x -> 
b.consumes(x));
diff --git 
a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/annotation/RestPost.java
 
b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/annotation/RestPost.java
index 7572e09..20f6feb 100644
--- 
a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/annotation/RestPost.java
+++ 
b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/annotation/RestPost.java
@@ -22,6 +22,7 @@ import org.apache.juneau.*;
 import org.apache.juneau.annotation.*;
 import org.apache.juneau.rest.*;
 import org.apache.juneau.dto.swagger.*;
+import org.apache.juneau.encoders.*;
 import org.apache.juneau.http.header.*;
 
 /**
@@ -402,10 +403,10 @@ public @interface RestPost {
         * </ul>
         *
         * <ul class='seealso'>
-        *      <li class='jf'>{@link RestContext#REST_encoders}
+        *      <li class='jm'>{@link RestOpContextBuilder#encoders(Class...)}
         * </ul>
         */
-       Class<?>[] encoders() default {};
+       Class<? extends Encoder>[] encoders() default {};
 
        /**
         * Method-level guards.
diff --git 
a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/annotation/RestPostAnnotation.java
 
b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/annotation/RestPostAnnotation.java
index e19b197..aaba217 100644
--- 
a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/annotation/RestPostAnnotation.java
+++ 
b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/annotation/RestPostAnnotation.java
@@ -23,6 +23,7 @@ import java.nio.charset.*;
 
 import org.apache.juneau.*;
 import org.apache.juneau.annotation.*;
+import org.apache.juneau.encoders.*;
 import org.apache.juneau.http.header.*;
 import org.apache.juneau.internal.*;
 import org.apache.juneau.reflect.*;
@@ -61,7 +62,8 @@ public class RestPostAnnotation {
                Class<? extends RestGuard>[] guards = new Class[0];
                Class<? extends RestMatcher>[] matchers = new Class[0];
                Class<? extends RestOpContext> contextClass = 
RestOpContext.Null.class;
-               Class<?>[] encoders=new Class<?>[0], parsers=new Class<?>[0], 
serializers=new Class<?>[0];
+               Class<? extends Encoder>[] encoders = new Class[0];
+               Class<?>[] parsers=new Class<?>[0], serializers=new Class<?>[0];
                OpSwagger swagger = OpSwaggerAnnotation.DEFAULT;
                String clientVersion="", debug="", defaultAccept="", 
defaultCharset="", defaultContentType="", maxInput="", rolesDeclared="", 
roleGuard="", summary="", value="";
                String[] consumes={}, defaultFormData={}, defaultQueryData={}, 
defaultRequestAttributes={}, defaultRequestHeaders={}, 
defaultResponseHeaders={}, description={}, path={}, produces={};
@@ -242,7 +244,7 @@ public class RestPostAnnotation {
                 * @param value The new value for this property.
                 * @return This object (for method chaining).
                 */
-               public Builder encoders(Class<?>...value) {
+               public Builder encoders(Class<? extends Encoder>...value) {
                        this.encoders = value;
                        return this;
                }
@@ -402,7 +404,8 @@ public class RestPostAnnotation {
                private final Class<? extends RestGuard>[] guards;
                private final Class<? extends RestMatcher>[] matchers;
                private final Class<? extends RestOpContext> contextClass;
-               private final Class<?>[] encoders, parsers, serializers;
+               private final Class<? extends Encoder>[] encoders;
+               private final Class<?>[] parsers, serializers;
                private final OpSwagger swagger;
                private final String clientVersion, debug, defaultAccept, 
defaultCharset, defaultContentType, maxInput, rolesDeclared, roleGuard, 
summary, value;
                private final String[] consumes, defaultFormData, 
defaultQueryData, defaultRequestAttributes, defaultRequestHeaders, 
defaultResponseHeaders, description, path, produces;
@@ -510,7 +513,7 @@ public class RestPostAnnotation {
                }
 
                @Override /* RestPost */
-               public Class<?>[] encoders() {
+               public Class<? extends Encoder>[] encoders() {
                        return encoders;
                }
 
@@ -597,7 +600,7 @@ public class RestPostAnnotation {
 
                        b.set(REST_serializers, 
merge(ConverterUtils.toType(b.peek(REST_serializers), Object[].class), 
a.serializers()));
                        b.set(REST_parsers, 
merge(ConverterUtils.toType(b.peek(REST_parsers), Object[].class), 
a.parsers()));
-                       b.set(REST_encoders, 
merge(ConverterUtils.toType(b.peek(REST_encoders), Object[].class), 
a.encoders()));
+                       b.encoders(a.encoders());
                        type(a.contextClass()).ifPresent(x -> 
b.contextClass(x));
                        strings(a.produces()).map(MediaType::of).forEach(x -> 
b.produces(x));
                        strings(a.consumes()).map(MediaType::of).forEach(x -> 
b.consumes(x));
diff --git 
a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/annotation/RestPut.java
 
b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/annotation/RestPut.java
index 8915b6d..79f181e 100644
--- 
a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/annotation/RestPut.java
+++ 
b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/annotation/RestPut.java
@@ -22,6 +22,7 @@ import org.apache.juneau.*;
 import org.apache.juneau.annotation.*;
 import org.apache.juneau.rest.*;
 import org.apache.juneau.dto.swagger.*;
+import org.apache.juneau.encoders.*;
 import org.apache.juneau.http.header.*;
 
 /**
@@ -402,10 +403,10 @@ public @interface RestPut {
         * </ul>
         *
         * <ul class='seealso'>
-        *      <li class='jf'>{@link RestContext#REST_encoders}
+        *      <li class='jm'>{@link RestOpContextBuilder#encoders(Class...)}
         * </ul>
         */
-       Class<?>[] encoders() default {};
+       Class<? extends Encoder>[] encoders() default {};
 
        /**
         * Method-level guards.
diff --git 
a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/annotation/RestPutAnnotation.java
 
b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/annotation/RestPutAnnotation.java
index 64fa2c6..a5d7bd0 100644
--- 
a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/annotation/RestPutAnnotation.java
+++ 
b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/annotation/RestPutAnnotation.java
@@ -23,6 +23,7 @@ import java.nio.charset.*;
 
 import org.apache.juneau.*;
 import org.apache.juneau.annotation.*;
+import org.apache.juneau.encoders.*;
 import org.apache.juneau.http.header.*;
 import org.apache.juneau.internal.*;
 import org.apache.juneau.reflect.*;
@@ -61,7 +62,8 @@ public class RestPutAnnotation {
                Class<? extends RestGuard>[] guards = new Class[0];
                Class<? extends RestMatcher>[] matchers = new Class[0];
                Class<? extends RestOpContext> contextClass = 
RestOpContext.Null.class;
-               Class<?>[] encoders=new Class<?>[0], parsers=new Class<?>[0], 
serializers=new Class<?>[0];
+               Class<? extends Encoder>[] encoders = new Class[0];
+               Class<?>[] parsers=new Class<?>[0], serializers=new Class<?>[0];
                OpSwagger swagger = OpSwaggerAnnotation.DEFAULT;
                String clientVersion="", debug="", defaultAccept="", 
defaultCharset="", defaultContentType="", maxInput="", rolesDeclared="", 
roleGuard="", summary="", value="";
                String[] consumes={}, defaultFormData={}, defaultQueryData={}, 
defaultRequestAttributes={}, defaultRequestHeaders={}, 
defaultResponseHeaders={}, description={}, path={}, produces={};
@@ -242,7 +244,7 @@ public class RestPutAnnotation {
                 * @param value The new value for this property.
                 * @return This object (for method chaining).
                 */
-               public Builder encoders(Class<?>...value) {
+               public Builder encoders(Class<? extends Encoder>...value) {
                        this.encoders = value;
                        return this;
                }
@@ -402,7 +404,8 @@ public class RestPutAnnotation {
                private final Class<? extends RestGuard>[] guards;
                private final Class<? extends RestMatcher>[] matchers;
                private final Class<? extends RestOpContext> contextClass;
-               private final Class<?>[] encoders, parsers, serializers;
+               private final Class<? extends Encoder>[] encoders;
+               private final Class<?>[] parsers, serializers;
                private final OpSwagger swagger;
                private final String clientVersion, debug, defaultAccept, 
defaultCharset, defaultContentType, maxInput, rolesDeclared, roleGuard, 
summary, value;
                private final String[] consumes, defaultFormData, 
defaultQueryData, defaultRequestAttributes, defaultRequestHeaders, 
defaultResponseHeaders, description, path, produces;
@@ -510,7 +513,7 @@ public class RestPutAnnotation {
                }
 
                @Override /* RestPut */
-               public Class<?>[] encoders() {
+               public Class<? extends Encoder>[] encoders() {
                        return encoders;
                }
 
@@ -597,7 +600,7 @@ public class RestPutAnnotation {
 
                        b.set(REST_serializers, 
merge(ConverterUtils.toType(b.peek(REST_serializers), Object[].class), 
a.serializers()));
                        b.set(REST_parsers, 
merge(ConverterUtils.toType(b.peek(REST_parsers), Object[].class), 
a.parsers()));
-                       b.set(REST_encoders, 
merge(ConverterUtils.toType(b.peek(REST_encoders), Object[].class), 
a.encoders()));
+                       b.encoders(a.encoders());
                        type(a.contextClass()).ifPresent(x -> 
b.contextClass(x));
                        strings(a.produces()).map(MediaType::of).forEach(x -> 
b.produces(x));
                        strings(a.consumes()).map(MediaType::of).forEach(x -> 
b.consumes(x));
diff --git 
a/juneau-utest/src/test/java/org/apache/juneau/encoders/EncoderGroupTest.java 
b/juneau-utest/src/test/java/org/apache/juneau/encoders/EncoderGroupTest.java
index 4cc804c..1e264ec 100755
--- 
a/juneau-utest/src/test/java/org/apache/juneau/encoders/EncoderGroupTest.java
+++ 
b/juneau-utest/src/test/java/org/apache/juneau/encoders/EncoderGroupTest.java
@@ -26,7 +26,7 @@ public class EncoderGroupTest {
        @Test
        public void testEncoderGroupMatching() throws Exception {
 
-               EncoderGroup g = EncoderGroup.create().append(Encoder1.class, 
Encoder2.class, Encoder3.class).build();
+               EncoderGroup g = EncoderGroup.create().add(Encoder1.class, 
Encoder2.class, Encoder3.class).build();
                assertObject(g.getEncoder("gzip1")).isType(Encoder1.class);
                assertObject(g.getEncoder("gzip2")).isType(Encoder2.class);
                assertObject(g.getEncoder("gzip2a")).isType(Encoder2.class);
@@ -64,18 +64,18 @@ public class EncoderGroupTest {
        
//====================================================================================================
        @Test
        public void testInheritence() throws Exception {
-               EncoderGroupBuilder gb = null;
+               EncoderGroup.Builder gb = null;
                EncoderGroup g = null;
 
-               gb = EncoderGroup.create().append(E1.class, E2.class);
+               gb = EncoderGroup.create().add(E1.class, E2.class);
                g = gb.build();
                
assertObject(g.getSupportedEncodings()).asJson().is("['E1','E2','E2a']");
 
-               gb = g.copy().append(E3.class, E4.class);
+               gb.add(E3.class, E4.class);
                g = gb.build();
                
assertObject(g.getSupportedEncodings()).asJson().is("['E3','E4','E4a','E1','E2','E2a']");
 
-               gb = g.copy().append(E5.class);
+               gb.add(E5.class);
                g = gb.build();
                
assertObject(g.getSupportedEncodings()).asJson().is("['E5','E3','E4','E4a','E1','E2','E2a']");
        }

Reply via email to