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

commit bb624d386490c0cced1a4fdaae9fb8186b05b197
Author: JamesBognar <[email protected]>
AuthorDate: Thu Sep 9 09:20:47 2021 -0400

    Context API refactoring.
---
 .../java/org/apache/juneau/AnnotationApplier.java  |  16 -
 .../org/apache/juneau/encoders/EncoderGroup.java   |  76 +++--
 .../java/org/apache/juneau/parser/ParserGroup.java | 374 +++++++++++++++++++--
 .../apache/juneau/parser/ParserGroupBuilder.java   | 206 ------------
 .../apache/juneau/serializer/SerializerGroup.java  |  98 ++++--
 .../juneau/rest/client/RestClientBuilder.java      |   6 +-
 .../org/apache/juneau/rest/jaxrs/BaseProvider.java |   2 +-
 .../java/org/apache/juneau/rest/BasicRestJena.java |   1 -
 .../org/apache/juneau/rest/BasicRestJenaGroup.java |   1 -
 .../apache/juneau/rest/BasicRestServletJena.java   |   1 -
 .../juneau/rest/BasicRestServletJenaGroup.java     |   1 -
 .../java/org/apache/juneau/rest/RestContext.java   |  99 ------
 .../org/apache/juneau/rest/RestContextBuilder.java | 258 ++++----------
 .../java/org/apache/juneau/rest/RestOpContext.java |  55 ++-
 .../apache/juneau/rest/RestOpContextBuilder.java   | 129 ++++---
 .../org/apache/juneau/rest/annotation/Rest.java    | 122 +++++--
 .../juneau/rest/annotation/RestAnnotation.java     |   7 +-
 .../apache/juneau/rest/annotation/RestDelete.java  |  43 ++-
 .../rest/annotation/RestDeleteAnnotation.java      |   1 -
 .../org/apache/juneau/rest/annotation/RestGet.java |  90 +++--
 .../juneau/rest/annotation/RestGetAnnotation.java  |   2 -
 .../org/apache/juneau/rest/annotation/RestOp.java  | 142 +++++---
 .../juneau/rest/annotation/RestOpAnnotation.java   |   6 +-
 .../apache/juneau/rest/annotation/RestPost.java    | 137 +++++---
 .../juneau/rest/annotation/RestPostAnnotation.java |   7 +-
 .../org/apache/juneau/rest/annotation/RestPut.java | 136 +++++---
 .../juneau/rest/annotation/RestPutAnnotation.java  |   7 +-
 .../org/apache/juneau/rest/util/RestUtils.java     |  45 ---
 .../org/apache/juneau/parser/ParserGroupTest.java  |  10 +-
 .../juneau/rest/annotation/Restx_Parsers_Test.java |   2 +-
 .../apache/juneau/testutils/MockReaderParser.java  |  10 +-
 31 files changed, 1131 insertions(+), 959 deletions(-)

diff --git 
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/AnnotationApplier.java
 
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/AnnotationApplier.java
index 43d213d..2512812 100644
--- 
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/AnnotationApplier.java
+++ 
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/AnnotationApplier.java
@@ -211,26 +211,10 @@ public abstract class AnnotationApplier<A extends 
Annotation, B> {
         * @return The array wrapped in an {@link Optional}.
         */
        protected Optional<Class<?>[]> classes(Class<?>[] in) {
-               for (int i = 0; i < in.length; i++)
-                       if (in[i].getSimpleName().equals("None"))
-                               return Optional.of(Arrays.stream(in).filter(x 
-> ! x.getSimpleName().equals("None")).toArray(Class[]::new));
                return Optional.ofNullable(in.length == 0 ? null : in);
        }
 
        /**
-        * Returns a class entry if the class array contains a class with a 
simple name of <js>"None"</js>.
-        *
-        * @param in The class array.
-        * @return The class entry with simple name <js>"None"</js>.
-        */
-       protected Optional<Class<?>> none(Class<?>[] in) {
-               for (int i = 0; i < in.length; i++)
-                       if (in[i].getSimpleName().equals("None"))
-                               return Optional.of(in[i]);
-               return Optional.empty();
-       }
-
-       /**
         * Convenience method for detecting if an array is empty.
         *
         * @param value The array to check.
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 12acb00..11d1201 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
@@ -67,16 +67,25 @@ import org.apache.juneau.http.header.*;
 public final class EncoderGroup {
 
        /**
-        * An identifier that a group of encoders should inherit from another 
group.
+        * An identifier that the previous encoders in this group should be 
inherited.
+        * <p>
+        * Used by {@link Builder#set(Class...)}
         */
        public static abstract class Inherit extends Encoder {}
 
+       /**
+        * An identifier that the previous encoders in this group should not be 
inherited.
+        * <p>
+        * Used by {@link Builder#add(Class...)}
+        */
+       public static abstract class NoInherit extends Encoder {}
+
        // Maps Accept-Encoding headers to matching encoders.
        private final ConcurrentHashMap<String,EncoderMatch> cache = new 
ConcurrentHashMap<>();
 
        private final List<String> encodings;
        private final Encoder[] encodingsEncoders;
-       private final Encoder[] encoders;
+       private final Encoder[] entries;
 
        /**
         * Instantiates a new clean-slate {@link EncoderGroup.Builder} object.
@@ -96,11 +105,11 @@ public final class EncoderGroup {
         * @param builder The builder for this object.
         */
        protected EncoderGroup(Builder builder) {
-               encoders = builder.encoders.stream().map(x -> 
instantiate(builder.beanStore, x)).toArray(Encoder[]::new);
+               entries = builder.entries.stream().map(x -> 
instantiate(builder.beanStore, x)).toArray(Encoder[]::new);
 
                List<String> lc = AList.create();
                List<Encoder> l = AList.create();
-               for (Encoder e : encoders) {
+               for (Encoder e : entries) {
                        for (String c: e.getCodings()) {
                                lc.add(c);
                                l.add(e);
@@ -126,16 +135,16 @@ public final class EncoderGroup {
         * Builder class for this object.
         */
        public static class Builder {
-               List<Object> encoders;
+               List<Object> entries;
                Builder inheritFrom;
                BeanStore beanStore = BeanStore.create().build();
 
                Builder() {
-                       encoders = AList.create();
+                       entries = AList.create();
                }
 
                Builder(Builder copyFrom) {
-                       encoders = AList.of(copyFrom.encoders);
+                       entries = AList.of(copyFrom.entries);
                }
 
                /**
@@ -150,14 +159,17 @@ public final class EncoderGroup {
                 */
                public Builder add(Class<?>...values) {
                        List<Object> l = AList.create();
-                       for (Class<?> e : values) {
-                               if (Encoder.class.isAssignableFrom(e)) {
-                                       l.add(e);
-                               } else {
-                                       throw illegalArgumentException("Invalid 
type passed to EncoderGroup.Builder.add(): " + e.getName());
+                       for (Class<?> v : values)
+                               if (v.getSimpleName().equals("NoInherit"))
+                                       clear();
+                       for (Class<?> v : values) {
+                               if (Encoder.class.isAssignableFrom(v)) {
+                                       l.add(v);
+                               } else if (! 
v.getSimpleName().equals("NoInherit")) {
+                                       throw illegalArgumentException("Invalid 
type passed to EncoderGroup.Builder.add(): " + v.getName());
                                }
                        }
-                       encoders.addAll(0, l);
+                       entries.addAll(0, l);
                        return this;
                }
 
@@ -177,16 +189,16 @@ public final class EncoderGroup {
                 */
                public Builder set(Class<?>...values) {
                        List<Object> l = AList.create();
-                       for (Class<?> e : values) {
-                               if (e.getSimpleName().equals("Inherit")) {
-                                       l.addAll(encoders);
-                               } else if (Encoder.class.isAssignableFrom(e)) {
-                                       l.add(e);
+                       for (Class<?> v : values) {
+                               if (v.getSimpleName().equals("Inherit")) {
+                                       l.addAll(entries);
+                               } else if (Encoder.class.isAssignableFrom(v)) {
+                                       l.add(v);
                                } else {
-                                       throw illegalArgumentException("Invalid 
type passed to EncoderGroup.Builder.set(): " + e.getName());
+                                       throw illegalArgumentException("Invalid 
type passed to EncoderGroup.Builder.set(): " + v.getName());
                                }
                        }
-                       encoders = l;
+                       entries = l;
                        return this;
                }
 
@@ -200,7 +212,7 @@ public final class EncoderGroup {
                 * @return This object (for method chaining).
                 */
                public Builder add(Encoder...values) {
-                       encoders.addAll(0, asList(values));
+                       entries.addAll(0, asList(values));
                        return this;
                }
 
@@ -210,7 +222,7 @@ public final class EncoderGroup {
                 * @return This object (for method chaining).
                 */
                public Builder clear() {
-                       encoders.clear();
+                       entries.clear();
                        return this;
                }
 
@@ -246,12 +258,28 @@ public final class EncoderGroup {
                 * @return <jk>true</jk> if this builder is empty.
                 */
                public boolean isEmpty() {
-                       return encoders.isEmpty();
+                       return entries.isEmpty();
+               }
+
+               /**
+                * Returns direct access to the {@link Encoder} objects and 
classes in this builder.
+                *
+                * <p>
+                * Provided to allow for any extraneous modifications to the 
list not accomplishable via other methods on this builder such
+                * as re-ordering/adding/removing entries.
+                *
+                * <p>
+                * Note that it is up to the user to ensure that the list only 
contains {@link Encoder} objects and classes.
+                *
+                * @return The inner list of entries in this builder.
+                */
+               public List<Object> inner() {
+                       return entries;
                }
 
                @Override /* Object */
                public String toString() {
-                       return encoders.stream().map(x -> 
toString(x)).collect(joining(",","[","]"));
+                       return entries.stream().map(x -> 
toString(x)).collect(joining(",","[","]"));
                }
 
                private static String toString(Object o) {
diff --git 
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/parser/ParserGroup.java
 
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/parser/ParserGroup.java
index 1bb2b28..4313590 100644
--- 
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/parser/ParserGroup.java
+++ 
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/parser/ParserGroup.java
@@ -13,17 +13,20 @@
 package org.apache.juneau.parser;
 
 import static org.apache.juneau.http.HttpHeaders.*;
+import static org.apache.juneau.internal.ExceptionUtils.*;
 import static java.util.Arrays.*;
 import static java.util.Collections.*;
-
+import static java.util.stream.Collectors.*;
 
 import java.util.*;
 import java.util.concurrent.*;
+import java.util.function.*;
+import java.util.stream.*;
 
+import org.apache.juneau.*;
 import org.apache.juneau.annotation.*;
 import org.apache.juneau.collections.*;
 import org.apache.juneau.http.header.*;
-import org.apache.juneau.internal.*;
 
 /**
  * Represents a group of {@link Parser Parsers} that can be looked up by media 
type.
@@ -80,9 +83,28 @@ import org.apache.juneau.internal.*;
 public final class ParserGroup {
 
        /**
-        * An unmodifiable empty parser group.
+        * An identifier that the previous entries in this group should be 
inherited.
+        * <p>
+        * Used by {@link Builder#set(Class...)}
         */
-       public static final ParserGroup EMPTY = create().build();
+       @SuppressWarnings("javadoc")
+       public static abstract class Inherit extends Parser {
+               protected Inherit(ParserBuilder builder) {
+                       super(builder);
+               }
+       }
+
+       /**
+        * An identifier that the previous entries in this group should not be 
inherited.
+        * <p>
+        * Used by {@link Builder#add(Class...)}
+        */
+       @SuppressWarnings("javadoc")
+       public static abstract class NoInherit extends Parser {
+               protected NoInherit(ParserBuilder builder) {
+                       super(builder);
+               }
+       }
 
        // Maps Content-Type headers to matches.
        private final ConcurrentHashMap<String,ParserMatch> cache = new 
ConcurrentHashMap<>();
@@ -90,18 +112,15 @@ public final class ParserGroup {
        private final List<MediaType> mediaTypes;
        private final List<Parser> mediaTypeParsers;
 
-       final Parser[] parsers;
+       final Parser[] entries;
 
        /**
-        * Instantiates a new clean-slate {@link ParserGroupBuilder} object.
-        *
-        * <p>
-        * This is equivalent to simply calling <code><jk>new</jk> 
ParserGroupBuilder()</code>.
+        * Instantiates a new clean-slate {@link Builder} object.
         *
-        * @return A new {@link ParserGroupBuilder} object.
+        * @return A new {@link Builder} object.
         */
-       public static ParserGroupBuilder create() {
-               return new ParserGroupBuilder();
+       public static Builder create() {
+               return new Builder();
        }
 
        /**
@@ -109,24 +128,16 @@ public final class ParserGroup {
         *
         * @param builder The builder for this bean.
         */
-       public ParserGroup(ParserGroupBuilder builder) {
-               List<Parser> x = new ArrayList<>();
-               for (Object p : builder.parsers) {
-                       if (p instanceof ParserBuilder) {
-                               x.add(((ParserBuilder)p).build());
-                       } else {
-                               x.add((Parser)p);
-                       }
-               }
+       public ParserGroup(Builder builder) {
 
-               this.parsers = ArrayUtils.toReverseArray(Parser.class, x);
+               this.entries = builder.entries.stream().map(x -> 
build(x)).toArray(Parser[]::new);
 
                AList<MediaType> lmt = AList.create();
                AList<Parser> l = AList.create();
-               for (Parser p : parsers) {
-                       for (MediaType m: p.getMediaTypes()) {
+               for (Parser e : entries) {
+                       for (MediaType m: e.getMediaTypes()) {
                                lmt.add(m);
-                               l.add(p);
+                               l.add(e);
                        }
                }
 
@@ -134,13 +145,318 @@ public final class ParserGroup {
                this.mediaTypeParsers = l.unmodifiable();
        }
 
+       private Parser build(Object o) {
+               if (o instanceof Parser)
+                       return (Parser)o;
+               return ((ParserBuilder)o).build();
+       }
+
        /**
         * Creates a copy of this parser group.
         *
         * @return A new copy of this parser group.
         */
-       public ParserGroupBuilder copy() {
-               return new ParserGroupBuilder(this);
+       public Builder copy() {
+               return new Builder(this);
+       }
+
+       /**
+        * Builder class for creating instances of {@link ParserGroup}.
+        */
+       public static class Builder {
+
+               List<Object> entries;
+               private BeanContextBuilder bcBuilder;
+
+               /**
+                * Create an empty parser group builder.
+                */
+               protected Builder() {
+                       this.entries = AList.create();
+               }
+
+               /**
+                * Clone an existing parser group.
+                *
+                * @param copyFrom The parser group that we're copying settings 
and parsers from.
+                */
+               protected Builder(ParserGroup copyFrom) {
+                       this.entries = 
AList.create().append(asList(copyFrom.entries));
+               }
+
+               /**
+                * Clone an existing parser group builder.
+                *
+                * <p>
+                * Parser builders will be cloned during this process.
+                *
+                * @param copyFrom The parser group that we're copying settings 
and parsers from.
+                */
+               protected Builder(Builder copyFrom) {
+                       bcBuilder = copyFrom.bcBuilder == null ? null : 
copyFrom.bcBuilder.copy();
+                       entries = AList.create();
+                       copyFrom.entries.stream().map(x -> 
copyBuilder(x)).forEach(x -> entries.add(x));
+               }
+
+               private Object copyBuilder(Object o) {
+                       if (o instanceof ParserBuilder) {
+                               ParserBuilder x = (ParserBuilder)o;
+                               x = x.copy();
+                               if (bcBuilder != null)
+                                       x.beanContextBuilder(bcBuilder);
+                               return x;
+                       }
+                       return o;
+               }
+
+               /**
+                * Copy creator.
+                *
+                * @return A new mutable copy of this builder.
+                */
+               public Builder copy() {
+                       return new Builder(this);
+               }
+
+               /**
+                * Creates a new {@link ParserGroup} object using a snapshot of 
the settings defined in this builder.
+                *
+                * <p>
+                * This method can be called multiple times to produce multiple 
parser groups.
+                *
+                * @return A new {@link ParserGroup} object.
+                */
+               public ParserGroup build() {
+                       return new ParserGroup(this);
+               }
+
+               /**
+                * Associates an existing bean context builder with all parser 
builders in this group.
+                *
+                * @param value The bean contest builder to associate.
+                * @return This object (for method chaining).
+                */
+               public Builder beanContextBuilder(BeanContextBuilder value) {
+                       bcBuilder = value;
+                       forEach(x -> x.beanContextBuilder(value));
+                       return this;
+               }
+
+               /**
+                * Adds the specified parsers to this group.
+                *
+                * <p>
+                * Entries are added in-order to the beginning of the list in 
the group.
+                *
+                * <p>
+                * The {@link NoInherit} class can be used to clear out the 
existing list of parsers before adding the new entries.
+                *
+                * <h5 class='section'>Example:</h5>
+                * <p class='bcode w800'>
+                *      ParserGroup.Builder <jv>builder</jv> = 
ParserGroup.<jsm>create</jsm>();  <jc>// Create an empty builder.</jc>
+                *
+                *      <jv>builder</jv>.add(FooParser.<jk>class</jk>);  <jc>// 
Now contains:  [FooParser]</jc>
+                *
+                *      <jv>builder</jv>.add(BarParser.<jk>class</jk>, 
BazParser.<jk>class</jk>);  <jc>// Now contains:  
[BarParser,BazParser,FooParser]</jc>
+                *
+                *      <jv>builder</jv>.add(NoInherit.<jk>class</jk>, 
QuxParser.<jk>class</jk>);  <jc>// Now contains:  [QuxParser]</jc>
+                * </p>
+                *
+                * @param values The parsers to add to this group.
+                * @return This object (for method chaining).
+                * @throws IllegalArgumentException If one or more values do 
not extend from {@link Parser}.
+                */
+               public Builder add(Class<?>...values) {
+                       List<Object> l = new ArrayList<>();
+                       for (Class<?> v : values)
+                               if (v.getSimpleName().equals("NoInherit"))
+                                       clear();
+                       for (Class<?> v : values) {
+                               if (Parser.class.isAssignableFrom(v)) {
+                                       l.add(createBuilder(v));
+                               } else if (! 
v.getSimpleName().equals("NoInherit")) {
+                                       throw runtimeException("Invalid type 
passed to ParserGroup.Builder.add(): " + v.getName());
+                               }
+                       }
+                       entries.addAll(0, l);
+                       return this;
+               }
+
+               /**
+                * Sets the specified parsers for this group.
+                *
+                * <p>
+                * Existing values are overwritten.
+                *
+                * <p>
+                * The {@link Inherit} class can be used to insert existing 
entries in this group into the position specified.
+                *
+                * <h5 class='section'>Example:</h5>
+                * <p class='bcode w800'>
+                *      ParserGroup.Builder <jv>builder</jv> = 
ParserGroup.<jsm>create</jsm>();  <jc>// Create an empty builder.</jc>
+                *
+                *      <jv>builder</jv>.set(FooParser.<jk>class</jk>);  <jc>// 
Now contains:  [FooParser]</jc>
+                *
+                *      <jv>builder</jv>.set(BarParser.<jk>class</jk>, 
BazParser.<jk>class</jk>);  <jc>// Now contains:  [BarParser,BazParser]</jc>
+                *
+                *      <jv>builder</jv>.set(Inherit.<jk>class</jk>, 
QuxParser.<jk>class</jk>);  <jc>// Now contains:  
[BarParser,BazParser,QuxParser]</jc>
+                * </p>
+                *
+                * @param values The parsers to set in this group.
+                * @return This object (for method chaining).
+                * @throws IllegalArgumentException If one or more values do 
not extend from {@link Parser} or named <js>"Inherit"</js>.
+                */
+               public Builder set(Class<?>...values) {
+                       List<Object> l = new ArrayList<>();
+                       for (Class<?> v : values) {
+                               if (v.getSimpleName().equals("Inherit")) {
+                                       l.addAll(entries);
+                               } else if (Parser.class.isAssignableFrom(v)) {
+                                       l.add(createBuilder(v));
+                               } else {
+                                       throw runtimeException("Invalid type 
passed to ParserGrouup.Builder.set(): " + v.getName());
+                               }
+                       }
+                       entries = l;
+                       return this;
+               }
+
+               private Object createBuilder(Object o) {
+                       if (o instanceof Class) {
+                               @SuppressWarnings("unchecked")
+                               ParserBuilder b = 
Parser.createParserBuilder((Class<? extends Parser>)o);
+                               if (bcBuilder != null)
+                                       b.beanContextBuilder(bcBuilder);
+                               o = b;
+                       }
+                       return o;
+               }
+
+               /**
+                * Registers the specified parsers with this group.
+                *
+                * <p>
+                * When passing in pre-instantiated parsers to this group, 
applying properties and transforms to the group
+                * do not affect them.
+                *
+                * @param s The parsers to append to this group.
+                * @return This object (for method chaining).
+                */
+               public Builder add(Parser...s) {
+                       entries.addAll(0, asList(s));
+                       return this;
+               }
+
+               /**
+                * Clears out any existing parsers in this group.
+                *
+                * @return This object (for method chaining).
+                */
+               public Builder clear() {
+                       entries.clear();
+                       return this;
+               }
+
+               /**
+                * Returns <jk>true</jk> if at least one of the specified 
annotations can be applied to at least one parser builder in this group.
+                *
+                * @param work The work to check.
+                * @return <jk>true</jk> if at least one of the specified 
annotations can be applied to at least one parser builder in this group.
+                */
+               public boolean canApply(List<AnnotationWork> work) {
+                       for (Object o : entries)
+                               if (o instanceof ParserBuilder)
+                                       if (((ParserBuilder)o).canApply(work))
+                                               return true;
+                       return false;
+               }
+
+               /**
+                * Applies the specified annotations to all applicable parser 
builders in this group.
+                *
+                * @param work The annotations to apply.
+                * @return This object (for method chaining).
+                */
+               public Builder apply(List<AnnotationWork> work) {
+                       return forEach(x -> x.apply(work));
+               }
+
+               /**
+                * Performs an action on all parser builders in this group.
+                *
+                * @param action The action to perform.
+                * @return This object (for method chaining).
+                */
+               public Builder forEach(Consumer<ParserBuilder> action) {
+                       builders(ParserBuilder.class).forEach(action);
+                       return this;
+               }
+
+               /**
+                * Performs an action on all writer parser builders in this 
group.
+                *
+                * @param action The action to perform.
+                * @return This object (for method chaining).
+                */
+               public Builder forEachRP(Consumer<ReaderParserBuilder> action) {
+                       return forEach(ReaderParserBuilder.class, action);
+               }
+
+               /**
+                * Performs an action on all output stream parser builders in 
this group.
+                *
+                * @param action The action to perform.
+                * @return This object (for method chaining).
+                */
+               public Builder forEachISP(Consumer<InputStreamParserBuilder> 
action) {
+                       return forEach(InputStreamParserBuilder.class, action);
+               }
+
+               /**
+                * Performs an action on all parser builders of the specified 
type in this group.
+                *
+                * @param type The parser builder type.
+                * @param action The action to perform.
+                * @return This object (for method chaining).
+                */
+               public <T extends ParserBuilder> Builder forEach(Class<T> type, 
Consumer<T> action) {
+                       builders(type).forEach(action);
+                       return this;
+               }
+
+               /**
+                * Returns direct access to the {@link Parser} and {@link 
ParserBuilder} objects in this builder.
+                *
+                * <p>
+                * Provided to allow for any extraneous modifications to the 
list not accomplishable via other methods on this builder such
+                * as re-ordering/adding/removing entries.
+                *
+                * <p>
+                * Note that it is up to the user to ensure that the list only 
contains {@link Parser} and {@link ParserBuilder} objects.
+                *
+                * @return The inner list of entries in this builder.
+                */
+               public List<Object> inner() {
+                       return entries;
+               }
+
+               @SuppressWarnings("unchecked")
+               private <T extends ParserBuilder> Stream<T> builders(Class<T> 
type) {
+                       return entries.stream().filter(x -> 
type.isInstance(x)).map(x -> (T)x);
+               }
+
+               @Override /* Object */
+               public String toString() {
+                       return entries.stream().map(x -> 
toString(x)).collect(joining(",","[","]"));
+               }
+
+               private String toString(Object o) {
+                       if (o == null)
+                               return "null";
+                       if (o instanceof ParserBuilder)
+                               return "builder:" + o.getClass().getName();
+                       return "parser:" + o.getClass().getName();
+               }
        }
 
        /**
@@ -218,7 +534,7 @@ public final class ParserGroup {
         * @return An unmodifiable list of parsers in this group.
         */
        public List<Parser> getParsers() {
-               return unmodifiableList(asList(parsers));
+               return unmodifiableList(asList(entries));
        }
 
        /**
@@ -227,6 +543,6 @@ public final class ParserGroup {
         * @return <jk>true</jk> if this group contains no parsers.
         */
        public boolean isEmpty() {
-               return parsers.length == 0;
+               return entries.length == 0;
        }
 }
diff --git 
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/parser/ParserGroupBuilder.java
 
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/parser/ParserGroupBuilder.java
deleted file mode 100644
index 9acf380..0000000
--- 
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/parser/ParserGroupBuilder.java
+++ /dev/null
@@ -1,206 +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.parser;
-
-import java.util.*;
-import java.util.function.*;
-import java.util.stream.*;
-
-import org.apache.juneau.*;
-import org.apache.juneau.collections.*;
-import org.apache.juneau.internal.*;
-
-/**
- * Builder class for creating instances of {@link ParserGroup}.
- */
-@FluentSetters
-public class ParserGroupBuilder {
-
-       final AList<Object> parsers;
-       private BeanContextBuilder bcBuilder;
-
-       /**
-        * Create an empty parser group builder.
-        */
-       protected ParserGroupBuilder() {
-               this.parsers = AList.create();
-       }
-
-       /**
-        * Copy constructor.
-        *
-        * @param copyFrom The bean to copy from.
-        */
-       protected ParserGroupBuilder(ParserGroup copyFrom) {
-               this.parsers = 
AList.create().appendReverse(copyFrom.getParsers());
-       }
-
-       /**
-        * Copy constructor.
-        *
-        * @param copyFrom The builder to copy from.
-        */
-       protected ParserGroupBuilder(ParserGroupBuilder copyFrom) {
-               bcBuilder = copyFrom.bcBuilder.copy();
-               parsers = AList.create();
-               copyFrom.parsers.stream().map(x -> copyBuilder(x)).forEach(x -> 
parsers.add(x));
-       }
-
-       private Object copyBuilder(Object o) {
-               if (o instanceof ParserBuilder)
-                       return 
((ParserBuilder)o).copy().beanContextBuilder(bcBuilder);
-               return o;
-       }
-
-       /**
-        * Creates a new {@link ParserGroup} object using a snapshot of the 
settings defined in this builder.
-        *
-        * <p>
-        * This method can be called multiple times to produce multiple parser 
groups.
-        *
-        * @return A new {@link ParserGroup} object.
-        */
-       public ParserGroup build() {
-               return new ParserGroup(this);
-       }
-
-       /**
-        * Associates an existing bean context builder with all serializer 
builders in this group.
-        *
-        * @param value The bean contest builder to associate.
-        * @return This object (for method chaining).
-        */
-       public ParserGroupBuilder beanContextBuilder(BeanContextBuilder value) {
-               bcBuilder = value;
-               forEach(x -> x.beanContextBuilder(value));
-               return this;
-       }
-
-       /**
-        * Registers the specified parsers with this group.
-        *
-        * @param p The parsers to append to this group.
-        * @return This object (for method chaining).
-        */
-       public ParserGroupBuilder append(Class<?>...p) {
-               parsers.appendReverse(instantiate(Arrays.asList(p)));
-               return this;
-       }
-
-       /**
-        * Registers the specified parsers with this group.
-        *
-        * <p>
-        * When passing in pre-instantiated parsers to this group, applying 
properties and transforms to the group
-        * do not affect them.
-        *
-        * @param p The parsers to append to this group.
-        * @return This object (for method chaining).
-        */
-       public ParserGroupBuilder append(Parser...p) {
-               parsers.appendReverse(instantiate(Arrays.asList(p)));
-               return this;
-       }
-
-       /**
-        * Registers the specified parsers with this group.
-        *
-        * <p>
-        * Objects can either be instances of parsers or parser classes.
-        *
-        * @param p The parsers to append to this group.
-        * @return This object (for method chaining).
-        */
-       public ParserGroupBuilder append(List<Object> p) {
-               parsers.appendReverse(instantiate(p));
-               return this;
-       }
-
-       /**
-        * Registers the specified parsers with this group.
-        *
-        * <p>
-        * Objects can either be instances of parsers or parser classes.
-        *
-        * @param p The parsers to append to this group.
-        * @return This object (for method chaining).
-        */
-       public ParserGroupBuilder append(Object...p) {
-               parsers.appendReverse(instantiate(Arrays.asList(p)));
-               return this;
-       }
-
-       /**
-        * Performs an action on all parser builders in this group.
-        *
-        * @param action The action to perform.
-        * @return This object (for method chaining).
-        */
-       public ParserGroupBuilder forEach(Consumer<ParserBuilder> action) {
-               builders(ParserBuilder.class).forEach(action);
-               return this;
-       }
-
-       /**
-        * Performs an action on all reader parser builders in this group.
-        *
-        * @param action The action to perform.
-        * @return This object (for method chaining).
-        */
-       public ParserGroupBuilder forEachRP(Consumer<ReaderParserBuilder> 
action) {
-               return forEach(ReaderParserBuilder.class, action);
-       }
-
-       /**
-        * Performs an action on all input stream parser builders in this group.
-        *
-        * @param action The action to perform.
-        * @return This object (for method chaining).
-        */
-       public ParserGroupBuilder forEachISP(Consumer<InputStreamParserBuilder> 
action) {
-               return forEach(InputStreamParserBuilder.class, action);
-       }
-
-       /**
-        * Performs an action on all parser builders of the specified type in 
this group.
-        *
-        * @param type The parser builder type.
-        * @param action The action to perform.
-        * @return This object (for method chaining).
-        */
-       public <T extends ParserBuilder> ParserGroupBuilder forEach(Class<T> 
type, Consumer<T> action) {
-               builders(type).forEach(action);
-               return this;
-       }
-
-       @SuppressWarnings("unchecked")
-       private List<Object> instantiate(List<?> l) {
-               List<Object> l2 = new ArrayList<>(l.size());
-               for (int i = 0; i < l.size(); i++) {
-                       Object o = l.get(i);
-                       if (o instanceof Class) {
-                               ParserBuilder b = 
Parser.createParserBuilder((Class<? extends Parser>)o);
-                               if (bcBuilder != null)
-                                       b.beanContextBuilder(bcBuilder);
-                               o = b;
-                       }
-                       l2.add(o);
-               }
-               return l2;
-       }
-
-       @SuppressWarnings("unchecked")
-       private <T extends ParserBuilder> Stream<T> builders(Class<T> type) {
-               return parsers.stream().filter(x -> type.isInstance(x)).map(x 
-> (T)x);
-       }
-}
diff --git 
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/serializer/SerializerGroup.java
 
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/serializer/SerializerGroup.java
index 2e115c3..e175b2c 100644
--- 
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/serializer/SerializerGroup.java
+++ 
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/serializer/SerializerGroup.java
@@ -75,7 +75,9 @@ import org.apache.juneau.http.header.*;
 public final class SerializerGroup {
 
        /**
-        * An identifier that a group of serializers should be inherited.
+        * An identifier that the previous entries in this group should be 
inherited.
+        * <p>
+        * Used by {@link Builder#set(Class...)}
         */
        @SuppressWarnings("javadoc")
        public static abstract class Inherit extends Serializer {
@@ -85,11 +87,13 @@ public final class SerializerGroup {
        }
 
        /**
-        * An identifier that a group of serializers should not be inherited.
+        * An identifier that the previous entries in this group should not be 
inherited.
+        * <p>
+        * Used by {@link Builder#add(Class...)}
         */
        @SuppressWarnings("javadoc")
-       public static abstract class None extends Serializer {
-               protected None(SerializerBuilder builder) {
+       public static abstract class NoInherit extends Serializer {
+               protected NoInherit(SerializerBuilder builder) {
                        super(builder);
                }
        }
@@ -101,7 +105,7 @@ public final class SerializerGroup {
        private final List<Serializer> mediaTypeRangeSerializers;
 
        private final List<MediaType> mediaTypesList;
-       final Serializer[] serializers;
+       final Serializer[] entries;
 
        /**
         * Instantiates a new clean-slate {@link Builder} object.
@@ -119,17 +123,17 @@ public final class SerializerGroup {
         */
        protected SerializerGroup(Builder builder) {
 
-               this.serializers = builder.serializers.stream().map(x -> 
build(x)).toArray(Serializer[]::new);
+               this.entries = builder.entries.stream().map(x -> 
build(x)).toArray(Serializer[]::new);
 
                AList<MediaRange> lmtr = AList.create();
                ASet<MediaType> lmt = ASet.of();
                AList<Serializer> l = AList.create();
-               for (Serializer s : serializers) {
-                       for (MediaRange m: s.getMediaTypeRanges().getRanges()) {
+               for (Serializer e : entries) {
+                       for (MediaRange m: e.getMediaTypeRanges().getRanges()) {
                                lmtr.add(m);
-                               l.add(s);
+                               l.add(e);
                        }
-                       for (MediaType mt : s.getAcceptMediaTypes())
+                       for (MediaType mt : e.getAcceptMediaTypes())
                                lmt.add(mt);
                }
 
@@ -158,14 +162,14 @@ public final class SerializerGroup {
         */
        public static class Builder {
 
-               List<Object> serializers;
+               List<Object> entries;
                private BeanContextBuilder bcBuilder;
 
                /**
                 * Create an empty serializer group builder.
                 */
                protected Builder() {
-                       this.serializers = AList.create();
+                       this.entries = AList.create();
                }
 
                /**
@@ -174,7 +178,7 @@ public final class SerializerGroup {
                 * @param copyFrom The serializer group that we're copying 
settings and serializers from.
                 */
                protected Builder(SerializerGroup copyFrom) {
-                       this.serializers = 
AList.create().append(asList(copyFrom.serializers));
+                       this.entries = 
AList.create().append(asList(copyFrom.entries));
                }
 
                /**
@@ -187,8 +191,8 @@ public final class SerializerGroup {
                 */
                protected Builder(Builder copyFrom) {
                        bcBuilder = copyFrom.bcBuilder == null ? null : 
copyFrom.bcBuilder.copy();
-                       serializers = AList.create();
-                       copyFrom.serializers.stream().map(x -> 
copyBuilder(x)).forEach(x -> serializers.add(x));
+                       entries = AList.create();
+                       copyFrom.entries.stream().map(x -> 
copyBuilder(x)).forEach(x -> entries.add(x));
                }
 
                private Object copyBuilder(Object o) {
@@ -241,6 +245,20 @@ public final class SerializerGroup {
                 * <p>
                 * Entries are added in-order to the beginning of the list in 
the group.
                 *
+                * <p>
+                * The {@link NoInherit} class can be used to clear out the 
existing list of serializers before adding the new entries.
+                *
+                * <h5 class='section'>Example:</h5>
+                * <p class='bcode w800'>
+                *      SerializerGroup.Builder <jv>builder</jv> = 
SerializerGroup.<jsm>create</jsm>();  <jc>// Create an empty builder.</jc>
+                *
+                *      <jv>builder</jv>.add(FooSerializer.<jk>class</jk>);  
<jc>// Now contains:  [FooSerializer]</jc>
+                *
+                *      <jv>builder</jv>.add(BarSerializer.<jk>class</jk>, 
BazSerializer.<jk>class</jk>);  <jc>// Now contains:  
[BarParser,BazSerializer,FooSerializer]</jc>
+                *
+                *      <jv>builder</jv>.add(NoInherit.<jk>class</jk>, 
QuxSerializer.<jk>class</jk>);  <jc>// Now contains:  [QuxSerializer]</jc>
+                * </p>
+                *
                 * @param values The serializers to add to this group.
                 * @return This object (for method chaining).
                 * @throws IllegalArgumentException If one or more values do 
not extend from {@link Serializer}.
@@ -254,7 +272,7 @@ public final class SerializerGroup {
                                        throw runtimeException("Invalid type 
passed to SerializeGroup.Builder.add(): " + e.getName());
                                }
                        }
-                       serializers.addAll(0, l);
+                       entries.addAll(0, l);
                        return this;
                }
 
@@ -265,8 +283,18 @@ public final class SerializerGroup {
                 * Existing values are overwritten.
                 *
                 * <p>
-                * If {@link Inherit} (or any other class whose simple name is 
<js>"Inherit"</js>) is specified, then the existing values are copied
-                * into the final list in the position they appear in the 
values.
+                * The {@link Inherit} class can be used to insert existing 
entries in this group into the position specified.
+                *
+                * <h5 class='section'>Example:</h5>
+                * <p class='bcode w800'>
+                *      SerializerGroup.Builder <jv>builder</jv> = 
SerializerGroup.<jsm>create</jsm>();  <jc>// Create an empty builder.</jc>
+                *
+                *      <jv>builder</jv>.set(FooSerializer.<jk>class</jk>);  
<jc>// Now contains:  [FooSerializer]</jc>
+                *
+                *      <jv>builder</jv>.set(BarSerializer.<jk>class</jk>, 
BazSerializer.<jk>class</jk>);  <jc>// Now contains:  
[BarParser,BazSerializer]</jc>
+                *
+                *      <jv>builder</jv>.set(Inherit.<jk>class</jk>, 
QuxSerializer.<jk>class</jk>);  <jc>// Now contains:  
[BarParser,BazSerializer,QuxSerializer]</jc>
+                * </p>
                 *
                 * @param values The serializers to set in this group.
                 * @return This object (for method chaining).
@@ -276,14 +304,14 @@ public final class SerializerGroup {
                        List<Object> l = new ArrayList<>();
                        for (Class<?> e : values) {
                                if (e.getSimpleName().equals("Inherit")) {
-                                       l.addAll(serializers);
+                                       l.addAll(entries);
                                } else if 
(Serializer.class.isAssignableFrom(e)) {
                                        l.add(createBuilder(e));
                                } else {
                                        throw runtimeException("Invalid type 
passed to SerializeGroup.Builder.set(): " + e.getName());
                                }
                        }
-                       serializers = l;
+                       entries = l;
                        return this;
                }
 
@@ -309,7 +337,7 @@ public final class SerializerGroup {
                 * @return This object (for method chaining).
                 */
                public Builder add(Serializer...s) {
-                       serializers.addAll(0, asList(s));
+                       entries.addAll(0, asList(s));
                        return this;
                }
 
@@ -319,7 +347,7 @@ public final class SerializerGroup {
                 * @return This object (for method chaining).
                 */
                public Builder clear() {
-                       serializers.clear();
+                       entries.clear();
                        return this;
                }
 
@@ -330,7 +358,7 @@ public final class SerializerGroup {
                 * @return <jk>true</jk> if at least one of the specified 
annotations can be applied to at least one serializer builder in this group.
                 */
                public boolean canApply(List<AnnotationWork> work) {
-                       for (Object o : serializers)
+                       for (Object o : entries)
                                if (o instanceof SerializerBuilder)
                                        if 
(((SerializerBuilder)o).canApply(work))
                                                return true;
@@ -390,14 +418,30 @@ public final class SerializerGroup {
                        return this;
                }
 
+               /**
+                * Returns direct access to the {@link Serializer} and {@link 
SerializerBuilder} objects in this builder.
+                *
+                * <p>
+                * Provided to allow for any extraneous modifications to the 
list not accomplishable via other methods on this builder such
+                * as re-ordering/adding/removing entries.
+                *
+                * <p>
+                * Note that it is up to the user to ensure that the list only 
contains {@link Serializer} and {@link SerializerBuilder} objects.
+                *
+                * @return The inner list of entries in this builder.
+                */
+               public List<Object> inner() {
+                       return entries;
+               }
+
                @SuppressWarnings("unchecked")
                private <T extends SerializerBuilder> Stream<T> 
builders(Class<T> type) {
-                       return serializers.stream().filter(x -> 
type.isInstance(x)).map(x -> (T)x);
+                       return entries.stream().filter(x -> 
type.isInstance(x)).map(x -> (T)x);
                }
 
                @Override /* Object */
                public String toString() {
-                       return serializers.stream().map(x -> 
toString(x)).collect(joining(",","[","]"));
+                       return entries.stream().map(x -> 
toString(x)).collect(joining(",","[","]"));
                }
 
                private String toString(Object o) {
@@ -540,7 +584,7 @@ public final class SerializerGroup {
         * @return An unmodifiable list of serializers in this group.
         */
        public List<Serializer> getSerializers() {
-               return unmodifiableList(asList(serializers));
+               return unmodifiableList(asList(entries));
        }
 
        /**
@@ -549,6 +593,6 @@ public final class SerializerGroup {
         * @return <jk>true</jk> if this group contains no serializers.
         */
        public boolean isEmpty() {
-               return serializers.length == 0;
+               return entries.length == 0;
        }
 }
diff --git 
a/juneau-rest/juneau-rest-client/src/main/java/org/apache/juneau/rest/client/RestClientBuilder.java
 
b/juneau-rest/juneau-rest-client/src/main/java/org/apache/juneau/rest/client/RestClientBuilder.java
index 37eb26b..f4767b2 100644
--- 
a/juneau-rest/juneau-rest-client/src/main/java/org/apache/juneau/rest/client/RestClientBuilder.java
+++ 
b/juneau-rest/juneau-rest-client/src/main/java/org/apache/juneau/rest/client/RestClientBuilder.java
@@ -97,7 +97,7 @@ public class RestClientBuilder extends BeanContextableBuilder 
{
        private boolean pooled;
 
        SerializerGroup.Builder serializerGroupBuilder;
-       ParserGroupBuilder parserGroupBuilder;
+       ParserGroup.Builder parserGroupBuilder;
 
        SerializerBuilder partSerializerBuilder;
        ParserBuilder partParserBuilder;
@@ -3038,7 +3038,7 @@ public class RestClientBuilder extends 
BeanContextableBuilder {
        @SuppressWarnings("unchecked")
        @FluentSetter
        public RestClientBuilder parsers(Class<? extends Parser>...value) {
-               parserGroupBuilder.append(value);
+               parserGroupBuilder.add(value);
                return this;
        }
 
@@ -3077,7 +3077,7 @@ public class RestClientBuilder extends 
BeanContextableBuilder {
         */
        @FluentSetter
        public RestClientBuilder parsers(Parser...value) {
-               parserGroupBuilder.append(value);
+               parserGroupBuilder.add(value);
                return this;
        }
 
diff --git 
a/juneau-rest/juneau-rest-server-jaxrs/src/main/java/org/apache/juneau/rest/jaxrs/BaseProvider.java
 
b/juneau-rest/juneau-rest-server-jaxrs/src/main/java/org/apache/juneau/rest/jaxrs/BaseProvider.java
index 3b4a479..c30c4c4 100644
--- 
a/juneau-rest/juneau-rest-server-jaxrs/src/main/java/org/apache/juneau/rest/jaxrs/BaseProvider.java
+++ 
b/juneau-rest/juneau-rest-server-jaxrs/src/main/java/org/apache/juneau/rest/jaxrs/BaseProvider.java
@@ -58,7 +58,7 @@ public class BaseProvider implements 
MessageBodyReader<Object>, MessageBodyWrite
                                .build();
 
                        parsers = ParserGroup.create()
-                               .append(jp.parsers())
+                               .add(jp.parsers())
                                .forEach(x -> x.swaps((Object[])jp.swaps()))
                                .forEach(x -> x.set(properties))
                                .build();
diff --git 
a/juneau-rest/juneau-rest-server-rdf/src/main/java/org/apache/juneau/rest/BasicRestJena.java
 
b/juneau-rest/juneau-rest-server-rdf/src/main/java/org/apache/juneau/rest/BasicRestJena.java
index 3ca1d2c..f58fd43 100644
--- 
a/juneau-rest/juneau-rest-server-rdf/src/main/java/org/apache/juneau/rest/BasicRestJena.java
+++ 
b/juneau-rest/juneau-rest-server-rdf/src/main/java/org/apache/juneau/rest/BasicRestJena.java
@@ -30,7 +30,6 @@ import org.apache.juneau.rest.annotation.*;
                N3Serializer.class
        },
        parsers={
-               Inherit.class,
                RdfXmlParser.class,
                TurtleParser.class,
                NTripleParser.class,
diff --git 
a/juneau-rest/juneau-rest-server-rdf/src/main/java/org/apache/juneau/rest/BasicRestJenaGroup.java
 
b/juneau-rest/juneau-rest-server-rdf/src/main/java/org/apache/juneau/rest/BasicRestJenaGroup.java
index cdbaba3..f37c920 100644
--- 
a/juneau-rest/juneau-rest-server-rdf/src/main/java/org/apache/juneau/rest/BasicRestJenaGroup.java
+++ 
b/juneau-rest/juneau-rest-server-rdf/src/main/java/org/apache/juneau/rest/BasicRestJenaGroup.java
@@ -30,7 +30,6 @@ import org.apache.juneau.rest.annotation.*;
                N3Serializer.class
        },
        parsers={
-               Inherit.class,
                RdfXmlParser.class,
                TurtleParser.class,
                NTripleParser.class,
diff --git 
a/juneau-rest/juneau-rest-server-rdf/src/main/java/org/apache/juneau/rest/BasicRestServletJena.java
 
b/juneau-rest/juneau-rest-server-rdf/src/main/java/org/apache/juneau/rest/BasicRestServletJena.java
index 7d72f78..dbf8f29 100755
--- 
a/juneau-rest/juneau-rest-server-rdf/src/main/java/org/apache/juneau/rest/BasicRestServletJena.java
+++ 
b/juneau-rest/juneau-rest-server-rdf/src/main/java/org/apache/juneau/rest/BasicRestServletJena.java
@@ -28,7 +28,6 @@ import org.apache.juneau.rest.annotation.*;
                N3Serializer.class
        },
        parsers={
-               Inherit.class,
                RdfXmlParser.class,
                TurtleParser.class,
                NTripleParser.class,
diff --git 
a/juneau-rest/juneau-rest-server-rdf/src/main/java/org/apache/juneau/rest/BasicRestServletJenaGroup.java
 
b/juneau-rest/juneau-rest-server-rdf/src/main/java/org/apache/juneau/rest/BasicRestServletJenaGroup.java
index 35d79f1..1bcefd3 100644
--- 
a/juneau-rest/juneau-rest-server-rdf/src/main/java/org/apache/juneau/rest/BasicRestServletJenaGroup.java
+++ 
b/juneau-rest/juneau-rest-server-rdf/src/main/java/org/apache/juneau/rest/BasicRestServletJenaGroup.java
@@ -28,7 +28,6 @@ import org.apache.juneau.rest.annotation.*;
                N3Serializer.class
        },
        parsers={
-               Inherit.class,
                RdfXmlParser.class,
                TurtleParser.class,
                NTripleParser.class,
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 5e6886b..057474c 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
@@ -52,14 +52,11 @@ import org.apache.juneau.http.annotation.Response;
 import org.apache.juneau.httppart.*;
 import org.apache.juneau.httppart.bean.*;
 import org.apache.juneau.internal.*;
-import org.apache.juneau.json.*;
 import org.apache.juneau.jsonschema.*;
 import org.apache.juneau.marshall.*;
-import org.apache.juneau.msgpack.*;
 import org.apache.juneau.mstat.*;
 import org.apache.juneau.oapi.*;
 import org.apache.juneau.parser.*;
-import org.apache.juneau.plaintext.*;
 import org.apache.juneau.reflect.*;
 import org.apache.juneau.rest.annotation.*;
 import org.apache.juneau.rest.args.*;
@@ -70,9 +67,7 @@ import org.apache.juneau.rest.util.*;
 import org.apache.juneau.rest.vars.*;
 import org.apache.juneau.svl.*;
 import org.apache.juneau.uon.*;
-import org.apache.juneau.urlencoding.*;
 import org.apache.juneau.utils.*;
-import org.apache.juneau.xml.*;
 
 /**
  * Contains all the configuration on a REST resource and the entry points for 
handling REST calls.
@@ -377,100 +372,6 @@ public class RestContext extends BeanContext {
        public static final String REST_messages = PREFIX + ".messages.lo";
 
        /**
-        * Configuration property:  Parsers.
-        *
-        * <h5 class='section'>Property:</h5>
-        * <ul class='spaced-list'>
-        *      <li><b>ID:</b>  {@link 
org.apache.juneau.rest.RestContext#REST_parsers REST_parsers}
-        *      <li><b>Name:</b>  <js>"RestContext.parsers.lo"</js>
-        *      <li><b>Data type:</b>  <c>List&lt;{@link 
org.apache.juneau.parser.Parser}|Class&lt;{@link 
org.apache.juneau.parser.Parser}&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#parsers()}
-        *                      <li class='ja'>{@link 
org.apache.juneau.rest.annotation.RestOp#parsers()}
-        *              </ul>
-        *      <li><b>Methods:</b>
-        *              <ul>
-        *                      <li class='jm'>{@link 
org.apache.juneau.rest.RestContextBuilder#parsers(Parser...)}
-        *                      <li class='jm'>{@link 
org.apache.juneau.rest.RestContextBuilder#parsers(Class...)}
-        *                      <li class='jm'>{@link 
org.apache.juneau.rest.RestContextBuilder#parsersReplace(Parser...)}
-        *              </ul>
-        * </ul>
-        *
-        * <h5 class='section'>Description:</h5>
-        * <p>
-        * Adds class-level parsers to this resource.
-        *
-        * <p>
-        * Parsers are used to convert the body of HTTP requests into POJOs.
-        * <br>Any of the Juneau framework parsers can be used in this setting.
-        * <br>The parser selected is based on the request <c>Content-Type</c> 
header matched against the values returned by the following method
-        * using a best-match algorithm:
-        * <ul class='javatree'>
-        *      <li class='jm'>{@link Parser#getMediaTypes()}
-        * </ul>
-        *
-        * <h5 class='section'>Example:</h5>
-        * <p class='bcode w800'>
-        *      <jc>// Option #1 - Defined via annotation.</jc>
-        *      <ja>@Rest</ja>(parsers={JsonParser.<jk>class</jk>, 
XmlParser.<jk>class</jk>})
-        *      <jk>public class</jk> MyResource {
-        *
-        *              <jc>// Option #2 - Defined 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>.parsers(JsonParser.<jk>class</jk>, XmlParser.<jk>class</jk>);
-        *
-        *                      <jc>// Same, but use pre-instantiated 
parsers.</jc>
-        *                      
<jv>builder</jv>.parsers(JsonParser.<jsf>DEFAULT</jsf>, 
XmlParser.<jsf>DEFAULT</jsf>);
-        *
-        *                      <jc>// Same, but using property.</jc>
-        *                      <jv>builder</jv>.set(<jsf>REST_parsers</jsf>, 
JsonParser.<jk>class</jk>, XmlParser.<jk>class</jk>);
-        *              }
-        *
-        *              <jc>// Option #3 - Defined via builder passed in 
through init method.</jc>
-        *              <ja>@RestHook</ja>(<jsf>INIT</jsf>)
-        *              <jk>public void</jk> init(RestContextBuilder 
<jv>builder</jv>) <jk>throws</jk> Exception {
-        *                      
<jv>builder</jv>.parsers(JsonParser.<jk>class</jk>, XmlParser.<jk>class</jk>);
-        *              }
-        *
-        *              <jc>// Override at the method level.</jc>
-        *              <ja>@RestPost</ja>(parsers={HtmlParser.<jk>class</jk>})
-        *              <jk>public</jk> Object myMethod(<ja>@Body</ja> MyPojo 
<jv>myPojo</jv>) {
-        *                      <jc>// Do something with your parsed POJO.</jc>
-        *              }
-        *      }
-        * </p>
-        *
-        * <ul class='notes'>
-        *      <li>
-        *              When defined as a class, properties/transforms defined 
on the resource/method are inherited.
-        *      <li>
-        *              When defined as an instance, properties/transforms 
defined on the resource/method are NOT inherited.
-        *      <li>
-        *              Typically, you'll want your resource to extend directly 
from {@link BasicRestServlet} which comes
-        *              preconfigured with the following parsers:
-        *              <ul>
-        *                      <li class='jc'>{@link JsonParser}
-        *                      <li class='jc'>{@link XmlParser}
-        *                      <li class='jc'>{@link HtmlParser}
-        *                      <li class='jc'>{@link UonParser}
-        *                      <li class='jc'>{@link UrlEncodingParser}
-        *                      <li class='jc'>{@link MsgPackParser}
-        *                      <li class='jc'>{@link PlainTextParser}
-        *              </ul>
-        * </ul>
-        *
-        * <ul class='seealso'>
-        *      <li class='link'>{@doc RestParsers}
-        * </ul>
-        */
-       public static final String REST_parsers = PREFIX + ".parsers.lo";
-
-       /**
         * Configuration property:  HTTP part parser.
         *
         * <h5 class='section'>Property:</h5>
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 a74405c..2673203 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
@@ -143,6 +143,7 @@ public class RestContextBuilder extends BeanContextBuilder 
implements ServletCon
        HeaderListBuilder defaultResponseHeaders = HeaderList.create();
        EncoderGroup.Builder encoders = 
EncoderGroup.create().add(IdentityEncoder.INSTANCE);
        SerializerGroup.Builder serializers = SerializerGroup.create();
+       ParserGroup.Builder parsers = ParserGroup.create();
 
        Enablement debugDefault, debug;
 
@@ -505,6 +506,78 @@ public class RestContextBuilder extends BeanContextBuilder 
implements ServletCon
                return varResolverBuilder;
        }
 
+       /**
+        * Returns the serializer group builder containing the serializers for 
marshalling POJOs into response bodies.
+        *
+        * <p>
+        * Serializer are used to convert POJOs to HTTP response bodies.
+        * <br>Any of the Juneau framework serializers can be used in this 
setting.
+        * <br>The serializer selected is based on the request <c>Accept</c> 
header matched against the values returned by the following method
+        * using a best-match algorithm:
+        * <ul class='javatree'>
+        *      <li class='jm'>{@link Serializer#getMediaTypeRanges()}
+        * </ul>
+        *
+        * <p>
+        * The builder is initialized with serializers defined via the {@link 
Rest#serializers()} annotation.  That annotation is applied
+        * from parent-to-child order with child entries given priority over 
parent entries.
+        *
+        * <ul class='seealso'>
+        *      <li class='link'>{@doc RestSerializers}
+        * </ul>
+        *
+        * @return The serializer group builder for this context builder.
+        */
+       public SerializerGroup.Builder getSerializers() {
+               return serializers;
+       }
+
+       /**
+        * Returns the parser group builder containing the parsers for 
converting HTTP request bodies into POJOs.
+        *
+        * <p>
+        * Parsers are used to convert the body of HTTP requests into POJOs.
+        * <br>Any of the Juneau framework parsers can be used in this setting.
+        * <br>The parser selected is based on the request <c>Content-Type</c> 
header matched against the values returned by the following method
+        * using a best-match algorithm:
+        * <ul class='javatree'>
+        *      <li class='jm'>{@link Parser#getMediaTypes()}
+        * </ul>
+        *
+        * <p>
+        * The builder is initialized with parsers defined via the {@link 
Rest#parsers()} annotation.  That annotation is applied
+        * from parent-to-child order with child entries given priority over 
parent entries.
+        *
+        * <ul class='seealso'>
+        *      <li class='link'>{@doc RestParsers}
+        * </ul>
+        *
+        * @return The parser group builder for this context builder.
+        */
+       public ParserGroup.Builder getParsers() {
+               return parsers;
+       }
+
+       /**
+        * Returns the encoder group builder containing the encoders for 
compressing/decompressing input and output streams.
+        *
+        * <p>
+        * These can be used to enable various kinds of compression (e.g. 
<js>"gzip"</js>) on requests and responses.
+        *
+        * <p>
+        * The builder is initialized with encoders defined via the {@link 
Rest#encoders()} annotation.  That annotation is applied
+        * from parent-to-child order with child entries given priority over 
parent entries.
+        *
+        * <ul class='seealso'>
+        *      <li class='link'>{@doc RestEncoders}
+        * </ul>
+        *
+        * @return The encoder group builder for this context builder.
+        */
+       public EncoderGroup.Builder getEncoders() {
+               return encoders;
+       }
+
        
//----------------------------------------------------------------------------------------------------
        // Properties
        
//----------------------------------------------------------------------------------------------------
@@ -1497,67 +1570,6 @@ public class RestContextBuilder extends 
BeanContextBuilder implements ServletCon
        }
 
        /**
-        * 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>.getEncoders().add(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>.getEncoders().add(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='link'>{@doc RestEncoders}
-        *      <li class='jm'>{@link RestOpContextBuilder#getEncoders()}
-        *      <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>
-        *
-        * @return The encoder group builder for this context builder.
-        */
-       public EncoderGroup.Builder getEncoders() {
-               return encoders;
-       }
-
-       /**
         * Configuration property:  File finder.
         *
         * <p>
@@ -1763,64 +1775,6 @@ public class RestContextBuilder extends 
BeanContextBuilder implements ServletCon
        }
 
        /**
-        * <i><l>RestContext</l> configuration property:&emsp;</i>  Parsers.
-        *
-        * <p>
-        * Adds class-level parsers to this resource.
-        *
-        * <ul class='seealso'>
-        *      <li class='jf'>{@link RestContext#REST_parsers}
-        * </ul>
-        *
-        * @param values The values to add to this setting.
-        * @return This object (for method chaining).
-        */
-       @FluentSetter
-       public RestContextBuilder parsers(Class<?>...values) {
-               return prependTo(REST_parsers, values);
-       }
-
-       /**
-        * <i><l>RestContext</l> configuration property:&emsp;</i>  Parsers.
-        *
-        * <p>
-        * Same as {@link #parsers(Class...)} except input is pre-constructed 
instances.
-        *
-        * <p>
-        * Parser instances are considered set-in-stone and do NOT inherit 
properties and transforms defined on the
-        * resource class or method.
-        *
-        * <ul class='seealso'>
-        *      <li class='jf'>{@link RestContext#REST_parsers}
-        * </ul>
-        *
-        * @param values The values to add to this setting.
-        * @return This object (for method chaining).
-        */
-       @FluentSetter
-       public RestContextBuilder parsers(Parser...values) {
-               return prependTo(REST_parsers, values);
-       }
-
-       /**
-        * <i><l>RestContext</l> configuration property:&emsp;</i>  Parsers.
-        *
-        * <p>
-        * Same as {@link #parsers(Class...)} except allows you to overwrite 
the previous value.
-        *
-        * <ul class='seealso'>
-        *      <li class='jf'>{@link RestContext#REST_parsers}
-        * </ul>
-        *
-        * @param values The values to add to this setting.
-        * @return This object (for method chaining).
-        */
-       @FluentSetter
-       public RestContextBuilder parsersReplace(Parser...values) {
-               return set(REST_parsers, values);
-       }
-
-       /**
         * <i><l>RestContext</l> configuration property:&emsp;</i>  HTTP part 
parser.
         *
         * <p>
@@ -2389,71 +2343,6 @@ public class RestContextBuilder extends 
BeanContextBuilder implements ServletCon
        }
 
        /**
-        * The serializers to use to serialize POJOs into response bodies.
-        *
-        * <p>
-        * Serializer are used to convert POJOs to HTTP response bodies.
-        * <br>Any of the Juneau framework serializers can be used in this 
setting.
-        * <br>The serializer selected is based on the request <c>Accept</c> 
header matched against the values returned by the following method
-        * using a best-match algorithm:
-        * <ul class='javatree'>
-        *      <li class='jm'>{@link Serializer#getMediaTypeRanges()}
-        * </ul>
-        *
-        * <h5 class='section'>Example:</h5>
-        * <p class='bcode w800'>
-        *      <jc>// Option #1 - Defined via annotation.</jc>
-        *      <ja>@Rest</ja>(serializers={JsonSerializer.<jk>class</jk>, 
XmlSerializer.<jk>class</jk>})
-        *      <jk>public class</jk> MyResource {
-        *
-        *              <jc>// Option #2 - Defined 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>.getSerializers().add(JsonSerializer.<jk>class</jk>, 
XmlSerializer.<jk>class</jk>);
-        *
-        *                      <jc>// Same, but use pre-instantiated 
serializers.</jc>
-        *                      
<jv>builder</jv>.getSerializers().add(JsonSerializer.<jsf>DEFAULT</jsf>, 
XmlSerializer.<jsf>DEFAULT</jsf>);
-        *              }
-        *
-        *              <jc>// Option #3 - Defined via builder passed in 
through init method.</jc>
-        *              <ja>@RestHook</ja>(<jsf>INIT</jsf>)
-        *              <jk>public void</jk> init(RestContextBuilder 
<jv>builder</jv>) <jk>throws</jk> Exception {
-        *                      
<jv>builder</jv>.getSerializers().add(JsonSerializer.<jk>class</jk>, 
XmlSerializer.<jk>class</jk>);
-        *              }
-        *
-        *              <jc>// Override at the method level.</jc>
-        *              
<ja>@RestGet</ja>(serializers={HtmlSerializer.<jk>class</jk>})
-        *              <jk>public</jk> MyPojo myMethod() {
-        *                      <jc>// Return a POJO to be serialized.</jc>
-        *                      <jk>return new</jk> MyPojo();
-        *              }
-        *      }
-        * </p>
-        *
-        * <ul class='notes'>
-        *      <li>
-        *              Typically, you'll want your resource to extend directly 
from {@link BasicRestServlet} which comes
-        *              preconfigured with a predefined set of serializers.
-        * </ul>
-        *
-        * <ul class='seealso'>
-        *      <li class='link'>{@doc RestSerializers}
-        *      <li class='ja'>{@link RestOpContextBuilder#getSerializers()}
-        *      <li class='ja'>{@link Rest#serializers()}
-        *      <li class='ja'>{@link RestOp#serializers()}
-        *      <li class='ja'>{@link RestGet#serializers()}
-        *      <li class='ja'>{@link RestPut#serializers()}
-        *      <li class='ja'>{@link RestPost#serializers()}
-        * </ul>
-        *
-        * @return The serializer group builder for this context builder.
-        */
-       public SerializerGroup.Builder getSerializers() {
-               return serializers;
-       }
-
-       /**
         * Supported accept media types.
         *
         * <p>
@@ -2933,6 +2822,7 @@ public class RestContextBuilder extends 
BeanContextBuilder implements ServletCon
        public RestContextBuilder apply(List<AnnotationWork> work) {
                super.apply(work);
                serializers.apply(work);
+               parsers.apply(work);
                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 f118c56..7776c8a 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
@@ -151,7 +151,7 @@ public class RestOpContext extends BeanContext implements 
Comparable<RestOpConte
                        serializers = createSerializers(r, builder, bs);
                        bs.addBean(SerializerGroup.class, serializers);
 
-                       parsers = createParsers(r, cp, bs);
+                       parsers = createParsers(r, builder, bs);
                        bs.addBean(ParserGroup.class, parsers);
 
                        partSerializer = createPartSerializer(r, cp, bs);
@@ -370,7 +370,7 @@ public class RestOpContext extends BeanContext implements 
Comparable<RestOpConte
        }
 
        /**
-        * Instantiates the encoders for this REST resource method.
+        * Instantiates the entries for this REST resource method.
         *
         * <p>
         * Instantiates based on the following logic:
@@ -474,9 +474,9 @@ public class RestOpContext extends BeanContext implements 
Comparable<RestOpConte
         * <p>
         * Instantiates based on the following logic:
         * <ul>
-        *      <li>Looks for {@link RestContext#REST_parsers} value set via 
any of the following:
+        *      <li>Looks for parsers set via any of the following:
         *              <ul>
-        *                      <li>{@link 
RestContextBuilder#parsers(Class...)}/{@link 
RestContextBuilder#parsers(Parser...)}
+        *                      <li>{@link RestContextBuilder#getParsers()}.
         *                      <li>{@link Rest#parsers()}.
         *              </ul>
         *      <li>Looks for a static or non-static <c>createParsers()</> 
method that returns <c>{@link Parser}[]</c> on the
@@ -491,42 +491,32 @@ public class RestOpContext extends BeanContext implements 
Comparable<RestOpConte
         * </ul>
         *
         * @param resource The REST resource object.
-        * @param properties The property store of this method.
+        * @param builder The builder for this object.
         * @param beanStore The bean store to use for retrieving and creating 
beans.
         * @return The parsers for this REST resource.
         * @throws Exception If parsers could not be instantiated.
-        * @see RestContext#REST_parsers
         */
-       protected ParserGroup createParsers(Object resource, ContextProperties 
properties, BeanStore beanStore) throws Exception {
+       protected ParserGroup createParsers(Object resource, 
RestOpContextBuilder builder, BeanStore beanStore) throws Exception {
 
                ParserGroup g = 
beanStore.getBean(ParserGroup.class).orElse(null);
 
-               if (g == null) {
-                       Object[] x = properties.getArray(REST_parsers, 
Object.class).orElse(null);
-
-                       if (x == null)
-                               x = 
beanStore.getBean(Parser[].class).orElse(null);
-
-                       if (x == null)
-                               x = new Parser[0];
+               if (g != null)
+                       return g;
 
-                       g = ParserGroup
-                               .create()
-                               .append(x)
-                               .forEach(y -> y.apply(properties))
-                               .build();
-               }
+               ParserGroup.Builder x = builder.parsers;
+               if (x == null)
+                       x = builder.restContext.builder.parsers;
 
-               g = BeanStore
+               x = BeanStore
                        .of(beanStore, resource)
-                       .addBean(ParserGroup.class, g)
-                       .beanCreateMethodFinder(ParserGroup.class, resource)
+                       .addBean(ParserGroup.Builder.class, x)
+                       .beanCreateMethodFinder(ParserGroup.Builder.class, 
resource)
                        .find("createParsers", Method.class)
                        .thenFind("createParsers")
-                       .withDefault(g)
+                       .withDefault(x)
                        .run();
 
-               return g;
+               return x.build();
        }
 
        /**
@@ -1008,29 +998,28 @@ public class RestOpContext extends BeanContext 
implements Comparable<RestOpConte
                return pathMatchers[0].toString();
        }
 
-
        /**
-        * Bean property getter:  <property>serializers</property>.
+        * Returns the serializers to use for this method.
         *
-        * @return The value of the <property>serializers</property> property 
on this bean, or <jk>null</jk> if it is not set.
+        * @return The serializers to use for this method.
         */
        public SerializerGroup getSerializers() {
                return serializers;
        }
 
        /**
-        * Bean property getter:  <property>parsers</property>.
+        * Returns the parsers to use for this method.
         *
-        * @return The value of the <property>parsers</property> property on 
this bean, or <jk>null</jk> if it is not set.
+        * @return The parsers to use for this method.
         */
        public ParserGroup getParsers() {
                return parsers;
        }
 
        /**
-        * Bean property getter:  <property>encoders</property>.
+        * Returns the compression encoders to use for this method.
         *
-        * @return The value of the <property>encoders</property> property on 
this bean, or <jk>null</jk> if it is not set.
+        * @return The compression encoders to use for this method.
         */
        public EncoderGroup getEncoders() {
                return encoders;
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 2ec5966..e7b8137 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
@@ -27,6 +27,7 @@ import org.apache.juneau.http.part.*;
 import org.apache.juneau.http.remote.*;
 import org.apache.juneau.http.response.*;
 import org.apache.juneau.internal.*;
+import org.apache.juneau.parser.*;
 import org.apache.juneau.reflect.*;
 import org.apache.juneau.rest.annotation.*;
 import org.apache.juneau.rest.converters.*;
@@ -56,6 +57,7 @@ public class RestOpContextBuilder extends BeanContextBuilder {
        RestConverterList.Builder converters = RestConverterList.create();
        EncoderGroup.Builder encoders;
        SerializerGroup.Builder serializers;
+       ParserGroup.Builder parsers;
 
        Charset defaultCharset;
        Long maxInput;
@@ -111,6 +113,8 @@ public class RestOpContextBuilder extends 
BeanContextBuilder {
 
                        if (context.builder.serializers.canApply(al))
                                getSerializers().apply(al);
+                       if (context.builder.parsers.canApply(al))
+                               getParsers().apply(al);
 
                } catch (Exception e) {
                        throw toHttpException(e, InternalServerError.class);
@@ -138,6 +142,78 @@ public class RestOpContextBuilder extends 
BeanContextBuilder {
                return this;
        }
 
+       /**
+        * Returns the serializer group builder containing the serializers for 
marshalling POJOs into response bodies.
+        *
+        * <p>
+        * This method can be used to override serializers defined at the class 
level via {@link RestContextBuilder#getSerializers()}.
+        * On first call, the builder from the class context is copied into a 
modifiable builder for this method.
+        * If never called, then the builder from the class context is used.
+        *
+        * <p>
+        * The builder is initialized with serializers defined via the {@link 
RestOp#serializers()} (and related) annotation.
+        * That annotation is applied from parent-to-child order with child 
entries given priority over parent entries.
+        *
+        * <ul class='seealso'>
+        *      <li class='link'>{@doc RestSerializers}
+        * </ul>
+        *
+        * @return The serializer group builder for this context builder.
+        */
+       public SerializerGroup.Builder getSerializers() {
+               if (serializers == null)
+                       serializers = restContext.builder.serializers.copy();
+               return serializers;
+       }
+
+       /**
+        * Returns the parser group builder containing the parsers for 
converting request bodies into POJOs.
+        *
+        * <p>
+        * This method can be used to override parsers defined at the class 
level via {@link RestContextBuilder#getParsers()}.
+        * On first call, the builder from the class context is copied into a 
modifiable builder for this method.
+        * If never called, then the builder from the class context is used.
+        *
+        * <p>
+        * The builder is initialized with parsers defined via the {@link 
RestOp#parsers()} (and related) annotation.
+        * That annotation is applied from parent-to-child order with child 
entries given priority over parent entries.
+        *
+        * <ul class='seealso'>
+        *      <li class='link'>{@doc RestParsers}
+        * </ul>
+        *
+        * @return The parser group builder for this context builder.
+        */
+       public ParserGroup.Builder getParsers() {
+               if (parsers == null)
+                       parsers = restContext.builder.parsers.copy();
+               return parsers;
+       }
+
+       /**
+        * Returns the parser group builder containing the parsers for 
converting HTTP request bodies into POJOs.
+        *
+        * <p>
+        * This method can be used to override encoders defined at the class 
level via {@link RestContextBuilder#getEncoders()}.
+        * On first call, the builder from the class context is copied into a 
modifiable builder for this method.
+        * If never called, then the builder from the class context is used.
+        *
+        * <p>
+        * The builder is initialized with encoders defined via the {@link 
Rest#parsers()} annotation.
+        * That annotation is applied from parent-to-child order with child 
entries given priority over parent entries.
+        *
+        * <ul class='seealso'>
+        *      <li class='link'>{@doc RestEncoders}
+        * </ul>
+        *
+        * @return The encoder group builder for this context builder.
+        */
+       public EncoderGroup.Builder getEncoders() {
+               if (encoders == null)
+                       encoders = restContext.builder.encoders.copy();
+               return encoders;
+       }
+
        
//----------------------------------------------------------------------------------------------------
        // Properties
        
//----------------------------------------------------------------------------------------------------
@@ -525,36 +601,6 @@ public class RestOpContextBuilder extends 
BeanContextBuilder {
        }
 
        /**
-        * Compression encoders.
-        *
-        * <p>
-        * This method overwrites any encoders defined at the class level.
-        * If never called, then the encoders are automatically inherited from 
the class level.
-        *
-        * <p>
-        * If {@link org.apache.juneau.encoders.EncoderGroup.Inherit} (or any 
other class whose simple name is <js>"Inherit"</js>) is specified, then the 
existing values are copied
-        * into the final list in the position they appear in the values.
-        *
-        * <ul class='seealso'>
-        *      <li class='link'>{@doc RestEncoders}
-        *      <li class='jm'>{@link RestContextBuilder#getEncoders()}
-        *      <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>
-        *
-        * @return The encoder group builder for the context builder.
-        */
-       public EncoderGroup.Builder getEncoders() {
-               if (encoders == null)
-                       encoders = restContext.builder.encoders.copy();
-               return encoders;
-       }
-
-       /**
         * Guards.
         *
         * <p>
@@ -989,29 +1035,6 @@ public class RestOpContextBuilder extends 
BeanContextBuilder {
        }
 
        /**
-        * Specifies the serializers for this REST method.
-        *
-        * <p>
-        * This method overwrites any serializers defined at the class level.
-        * If never called, then the serializers are automatically inherited 
from the class level.
-        *
-        * <p>
-        * If {@link org.apache.juneau.serializer.SerializerGroup.Inherit} (or 
any other class whose simple name is <js>"Inherit"</js>) is specified, then the 
existing values are copied
-        * into the final list in the position they appear in the values.
-        *
-        * <ul class='seealso'>
-        *      <li class='link'>{@doc RestSerializers}
-        * </ul>
-        *
-        * @return The serializer group builder for this context builder.
-        */
-       public SerializerGroup.Builder getSerializers() {
-               if (serializers == null)
-                       serializers = restContext.builder.serializers.copy();
-               return serializers;
-       }
-
-       /**
         * Supported content media types.
         *
         * <p>
diff --git 
a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/annotation/Rest.java
 
b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/annotation/Rest.java
index e8dfc03..63182cf 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
@@ -26,6 +26,7 @@ import org.apache.juneau.cp.*;
 import org.apache.juneau.encoders.*;
 import org.apache.juneau.http.header.*;
 import org.apache.juneau.httppart.*;
+import org.apache.juneau.parser.*;
 import org.apache.juneau.rest.*;
 import org.apache.juneau.rest.logging.*;
 import org.apache.juneau.rest.vars.*;
@@ -617,14 +618,41 @@ public @interface Rest {
        String[] description() default {};
 
        /**
-        * Compression encoders.
+        * Specifies the compression encoders for this resource.
         *
         * <p>
-        * These can be used to enable various kinds of compression (e.g. 
<js>"gzip"</js>) on requests and responses.
+        * Encoders are used to enable various kinds of compression (e.g. 
<js>"gzip"</js>) on requests and responses.
+        *
+        * <p>
+        * Encoders are automatically inherited from {@link Rest#encoders()} 
annotations on parent classes with the encoders on child classes
+        * prepended to the encoder group.
+        * The {@link org.apache.juneau.encoders.EncoderGroup.NoInherit} class 
can be used to prevent inheriting from the parent class.
+        *
+        * <h5 class='section'>Example:</h5>
+        * <p class='bcode w800'>
+        *      <jc>// Define a REST resource that handles GZIP 
compression.</jc>
+        *      <ja>@Rest</ja>(
+        *              encoders={
+        *                      GzipEncoder.<jk>class</jk>
+        *              }
+        *      )
+        *      <jk>public class</jk> MyResource {
+        *              ...
+        *      }
+        * </p>
+        *
+        * <p>
+        * The encoders can also be tailored at the method level using {@link 
RestOp#encoders()} (and related annotations).
+        *
+        * <p>
+        * The programmatic equivalent to this annotation is:
+        * <p class='bcode w800'>
+        *      RestContextBuilder <jv>builder</jv> = 
RestContext.<jsm>create</jsm>(<jv>resource</jv>);
+        *      <jv>builder</jv>.getEncoders().add(<jv>classes</jv>);
+        * </p>
         *
         * <ul class='seealso'>
-        *      <li class='jm'>{@link RestContextBuilder#getEncoders()}
-        *      <li class='jm'>{@link RestOpContextBuilder#getEncoders()}
+        *      <li class='link'>{@doc RestEncoders}
         * </ul>
         */
        Class<? extends Encoder>[] encoders() default {};
@@ -745,20 +773,48 @@ public @interface Rest {
        Class<?>[] onClass() default {};
 
        /**
-        * Parsers.
+        * Specifies the parsers for converting HTTP request bodies into POJOs.
         *
         * <p>
-        * If no value is specified, the parsers are inherited from parent 
class.
-        * <br>Otherwise, this value overrides the parsers defined on the 
parent class.
+        * Parsers are used to convert the body of HTTP requests into POJOs.
+        * <br>Any of the Juneau framework parsers can be used in this setting.
+        * <br>The parser selected is based on the request <c>Content-Type</c> 
header matched against the values returned by the following method
+        * using a best-match algorithm:
+        * <ul class='javatree'>
+        *      <li class='jm'>{@link Parser#getMediaTypes()}
+        * </ul>
         *
         * <p>
-        * Use {@link Inherit} to inherit parsers defined on the parent class.
+        * Parsers are automatically inherited from {@link Rest#parsers()} 
annotations on parent classes with the parsers on child classes
+        * prepended to the parser group.
+        * The {@link org.apache.juneau.parser.ParserGroup.NoInherit} class can 
be used to prevent inheriting from the parent class.
+        *
+        * <h5 class='section'>Example:</h5>
+        * <p class='bcode w800'>
+        *      <jc>// Define a REST resource that can consume JSON and 
XML.</jc>
+        *      <ja>@Rest</ja>(
+        *              parsers={
+        *                      JsonParser.<jk>class</jk>,
+        *                      XmlParser.<jk>class</jk>
+        *              }
+        *      )
+        *      <jk>public class</jk> MyResource {
+        *              ...
+        *      }
+        * </p>
         *
         * <p>
-        * Use {@link None} to suppress inheriting parsers defined on the 
parent class.
+        * The parsers can also be tailored at the method level using {@link 
RestOp#parsers()} (and related annotations).
+        *
+        * <p>
+        * The programmatic equivalent to this annotation is:
+        * <p class='bcode w800'>
+        *      RestContextBuilder <jv>builder</jv> = 
RestContext.<jsm>create</jsm>(<jv>resource</jv>);
+        *      <jv>builder</jv>.getParsers().add(<jv>classes</jv>);
+        * </p>
         *
         * <ul class='seealso'>
-        *      <li class='jf'>{@link RestContext#REST_parsers}
+        *      <li class='link'>{@doc RestParsers}
         * </ul>
         */
        Class<?>[] parsers() default {};
@@ -1092,15 +1148,29 @@ public @interface Rest {
        String rolesDeclared() default "";
 
        /**
-        * The serializers to use to serialize POJOs into response bodies.
+        * Specifies the serializers for POJOs into HTTP response bodies.
+        *
+        * <p>
+        * Serializer are used to convert POJOs to HTTP response bodies.
+        * <br>Any of the Juneau framework serializers can be used in this 
setting.
+        * <br>The serializer selected is based on the request <c>Accept</c> 
header matched against the values returned by the following method
+        * using a best-match algorithm:
+        * <ul class='javatree'>
+        *      <li class='jm'>{@link Serializer#getMediaTypeRanges()}
+        * </ul>
+        *
+        * <p>
+        * Serializers are automatically inherited from {@link 
Rest#serializers()} annotations on parent classes with the serializers on child 
classes
+        * prepended to the serializer group.
+        * The {@link org.apache.juneau.serializer.SerializerGroup.NoInherit} 
class can be used to prevent inheriting from the parent class.
         *
         * <h5 class='section'>Example:</h5>
         * <p class='bcode w800'>
-        *      <jc>// Add support for serializing POJOs to JSON or XML.</jc>
+        *      <jc>// Define a REST resource that can produce JSON and 
XML.</jc>
         *      <ja>@Rest</ja>(
         *              serializers={
-        *                      JsonSerializer.<jk>class</jk>,
-        *                      XmlSerializer.<jk>class</jk>
+        *                      JsonParser.<jk>class</jk>,
+        *                      XmlParser.<jk>class</jk>
         *              }
         *      )
         *      <jk>public class</jk> MyResource {
@@ -1109,25 +1179,17 @@ public @interface Rest {
         * </p>
         *
         * <p>
-        * Values are added from parent-to-child order.  Child values are 
automatically inserted before parent values so that they take precedence.
-        * <br>
-        * Use {@link None} to suppress inheriting serializers defined on the 
parent class.
+        * The serializers can also be tailored at the method level using 
{@link RestOp#serializers()} (and related annotations).
         *
-        * <h5 class='section'>Example:</h5>
-        *      <jc>// Don't inherit serializers from parent class.</jc>
-        *      <ja>@Rest</ja>(
-        *              serializers={
-        *                      None.<jk>class</jk>,
-        *                      JsonSerializer.<jk>class</jk>
-        *              }
-        *      )
-        *      <jk>public class</jk> MyChildResource <jk>extends</jk> 
MyParentResource {
-        *              ...
-        *      }
+        * <p>
+        * The programmatic equivalent to this annotation is:
+        * <p class='bcode w800'>
+        *      RestContextBuilder <jv>builder</jv> = 
RestContext.<jsm>create</jsm>(<jv>resource</jv>);
+        *      <jv>builder</jv>.getSerializers().add(<jv>classes</jv>);
+        * </p>
         *
         * <ul class='seealso'>
-        *      <li class='jm'>{@link RestContextBuilder#getSerializers()}
-        *      <li class='jm'>{@link RestOpContextBuilder#getSerializers()}
+        *      <li class='link'>{@doc RestSerializers}
         * </ul>
         */
        Class<? extends Serializer>[] serializers() 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 d7498be..6adbaf6 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
@@ -15,8 +15,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 java.lang.annotation.*;
 import java.nio.charset.*;
 
@@ -26,7 +24,6 @@ import org.apache.juneau.cp.*;
 import org.apache.juneau.encoders.*;
 import org.apache.juneau.http.header.*;
 import org.apache.juneau.httppart.*;
-import org.apache.juneau.internal.*;
 import org.apache.juneau.reflect.*;
 import org.apache.juneau.rest.*;
 import org.apache.juneau.rest.logging.*;
@@ -1044,8 +1041,8 @@ public class RestAnnotation {
                        Rest a = ai.getAnnotation();
                        ClassInfo c = ai.getClassOn();
 
-                       none(a.serializers()).ifPresent(x -> 
b.getSerializers().clear());
                        classes(a.serializers()).ifPresent(x -> 
b.getSerializers().add(x));
+                       classes(a.parsers()).ifPresent(x -> 
b.getParsers().add(x));
                        type(a.partSerializer()).ifPresent(x -> 
b.set(REST_partSerializer, x));
                        type(a.partParser()).ifPresent(x -> 
b.set(REST_partParser, x));
                        strings(a.produces()).map(MediaType::of).forEach(x -> 
b.produces(x));
@@ -1058,7 +1055,6 @@ public class RestAnnotation {
                        b.responseProcessors(a.responseProcessors());
                        b.children((Object[])a.children());
                        b.restOpArgs(a.restOpArgs());
-                       none(a.encoders()).ifPresent(x -> 
b.getEncoders().clear());
                        classes(a.encoders()).ifPresent(x -> 
b.getEncoders().add(x));
                        type(a.contextClass()).ifPresent(x -> 
b.contextClass(x));
                        string(a.uriContext()).ifPresent(x -> b.uriContext(x));
@@ -1105,7 +1101,6 @@ public class RestAnnotation {
                public void apply(AnnotationInfo<Rest> ai, RestOpContextBuilder 
b) {
                        Rest a = ai.getAnnotation();
 
-                       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));
                        strings(a.produces()).map(MediaType::of).forEach(x -> 
b.produces(x));
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 2307584..8bb1377 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
@@ -316,23 +316,46 @@ public @interface RestDelete {
        String[] description() default {};
 
        /**
-        * Compression encoders.
+        * Specifies the compression encoders for this method.
         *
         * <p>
-        * Use this annotation when the list of encoders assigned to a method 
differs from the list of encoders assigned at
-        * the servlet level.
+        * Encoders are used to enable various kinds of compression (e.g. 
<js>"gzip"</js>) on requests and responses.
         *
         * <p>
-        * These can be used to enable various kinds of compression (e.g. 
<js>"gzip"</js>) on requests and responses.
+        * This value overrides encoders specified at the class level using 
{@link Rest#encoders()}.
+        * The {@link org.apache.juneau.encoders.EncoderGroup.Inherit} class 
can be used to include values from the parent class.
         *
-        * <ul class='notes'>
-        *      <li>
-        *              Use {@link 
org.apache.juneau.encoders.EncoderGroup.Inherit} to inherit encoders from the 
resource class.
-        * </ul>
+        * <h5 class='section'>Example:</h5>
+        * <p class='bcode w800'>
+        *      <jc>// Define a REST resource that handles GZIP 
compression.</jc>
+        *      <ja>@Rest</ja>(
+        *              encoders={
+        *                      GzipEncoder.<jk>class</jk>
+        *              }
+        *      )
+        *      <jk>public class</jk> MyResource {
+        *
+        *              <jc>// Define a REST method that can also use a custom 
encoder.</jc>
+        *              <ja>@RestDelete</ja>(
+        *                      encoders={
+        *                              EncoderGroup.Inherit.<jk>class</jk>, 
MyEncoder.<jk>class</jk>
+        *                      }
+        *              )
+        *              <jk>public</jk> String doDelete() {
+        *                      ...
+        *              }
+        *      }
+        * </p>
+        *
+        * <p>
+        * The programmatic equivalent to this annotation is:
+        * <p class='bcode w800'>
+        *      RestOpContextBuilder <jv>builder</jv> = 
RestOpContextBuilder.<jsm>create</jsm>(<jv>method</jv>,<jv>restContext</jv>);
+        *      <jv>builder</jv>.getEncoders().set(<jv>classes</jv>);
+        * </p>
         *
         * <ul class='seealso'>
-        *      <li class='jm'>{@link RestContextBuilder#getEncoders()}
-        *      <li class='jm'>{@link RestOpContextBuilder#getEncoders()}
+        *      <li class='link'>{@doc RestEncoders}
         * </ul>
         */
        Class<? extends Encoder>[] encoders() default {};
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 d36e8b0..3571351 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
@@ -454,7 +454,6 @@ public class RestDeleteAnnotation {
 
                        b.httpMethod("delete");
 
-                       none(a.encoders()).ifPresent(x -> 
b.getEncoders().clear());
                        classes(a.encoders()).ifPresent(x -> 
b.getEncoders().set(x));
                        type(a.contextClass()).ifPresent(x -> 
b.contextClass(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/RestGet.java
 
b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/annotation/RestGet.java
index 179e732..a063d8a 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
@@ -332,23 +332,47 @@ public @interface RestGet {
        String[] description() default {};
 
        /**
-        * Compression encoders.
+        * Specifies the compression encoders for this method.
         *
         * <p>
-        * Use this annotation when the list of encoders assigned to a method 
differs from the list of encoders assigned at
-        * the servlet level.
+        * Encoders are used to enable various kinds of compression (e.g. 
<js>"gzip"</js>) on requests and responses.
         *
         * <p>
-        * These can be used to enable various kinds of compression (e.g. 
<js>"gzip"</js>) on requests and responses.
+        * This value overrides encoders specified at the class level using 
{@link Rest#encoders()}.
+        * The {@link org.apache.juneau.encoders.EncoderGroup.Inherit} class 
can be used to include values from the parent class.
         *
-        * <ul class='notes'>
-        *      <li>
-        *              Use {@link 
org.apache.juneau.encoders.EncoderGroup.Inherit} to inherit encoders from the 
resource class.
-        * </ul>
+        * <h5 class='section'>Example:</h5>
+        * <p class='bcode w800'>
+        *      <jc>// Define a REST resource that handles GZIP 
compression.</jc>
+        *      <ja>@Rest</ja>(
+        *              encoders={
+        *                      GzipEncoder.<jk>class</jk>
+        *              }
+        *      )
+        *      <jk>public class</jk> MyResource {
+        *
+        *              <jc>// Define a REST method that can also use a custom 
encoder.</jc>
+        *              <ja>@RestGet</ja>(
+        *                      method=<jsf>GET</jsf>,
+        *                      encoders={
+        *                              EncoderGroup.Inherit.<jk>class</jk>, 
MyEncoder.<jk>class</jk>
+        *                      }
+        *              )
+        *              <jk>public</jk> MyBean doGet() {
+        *                      ...
+        *              }
+        *      }
+        * </p>
+        *
+        * <p>
+        * The programmatic equivalent to this annotation is:
+        * <p class='bcode w800'>
+        *      RestOpContextBuilder <jv>builder</jv> = 
RestOpContextBuilder.<jsm>create</jsm>(<jv>method</jv>,<jv>restContext</jv>);
+        *      <jv>builder</jv>.getEncoders().set(<jv>classes</jv>);
+        * </p>
         *
         * <ul class='seealso'>
-        *      <li class='jm'>{@link RestContextBuilder#getEncoders()}
-        *      <li class='jm'>{@link RestOpContextBuilder#getEncoders()}
+        *      <li class='link'>{@doc RestEncoders}
         * </ul>
         */
        Class<? extends Encoder>[] encoders() default {};
@@ -519,47 +543,53 @@ public @interface RestGet {
        String rolesDeclared() default "";
 
        /**
-        * The serializers to use to serialize POJOs into response bodies.
+        * Specifies the serializers for marshalling POJOs into response bodies 
for this method.
         *
         * <p>
-        * If no value is specified, the serializers are inherited from the 
class.
-        * <br>Otherwise, this value overrides the serializers defined on the 
class.
+        * Serializer are used to convert POJOs to HTTP response bodies.
+        * <br>Any of the Juneau framework serializers can be used in this 
setting.
+        * <br>The serializer selected is based on the request <c>Accept</c> 
header matched against the values returned by the following method
+        * using a best-match algorithm:
+        * <ul class='javatree'>
+        *      <li class='jm'>{@link Serializer#getMediaTypeRanges()}
+        * </ul>
         *
         * <p>
-        * Use {@link org.apache.juneau.serializer.SerializerGroup.Inherit} to 
inherit serializers defined on the class.
+        * This value overrides serializers specified at the class level using 
{@link Rest#serializers()}.
+        * The {@link org.apache.juneau.serializer.SerializerGroup.Inherit} 
class can be used to include values from the parent class.
         *
         * <h5 class='section'>Example:</h5>
         * <p class='bcode w800'>
+        *      <jc>// Define a REST resource that can produce JSON and 
HTML.</jc>
         *      <ja>@Rest</ja>(
         *              serializers={
-        *                      JsonSerializer.<jk>class</jk>
+        *                      JsonParser.<jk>class</jk>,
+        *                      HtmlParser.<jk>class</jk>
         *              }
         *      )
-        *      <jk>public class</jk> MyResource <jk>extends</jk> RestServlet {
-        *
-        *              <ja>@RestGet</ja>(
-        *                      path=<js>"/foo"</js>,
-        *                      serializers=XmlSerializer.<jk>class</jk>  
<jc>// Override serializers on class.</jc>
-        *              )
-        *              <jk>public</jk> Object doGetOnlyXml() {
-        *                      ...
-        *              }
+        *      <jk>public class</jk> MyResource {
         *
+        *              <jc>// Define a REST method that can also produce 
XML.</jc>
         *              <ja>@RestGet</ja>(
-        *                      path=<js>"/bar"</js>,
-        *                      
serializers={SerializerGroup.Inherit.<jk>class<jk>, 
XmlSerializer.<jk>class</jk>}  <jc>// Add to serializers on class.</jc>
+        *                      parsers={
+        *                              SerializerGroup.Inherit.<jk>class</jk>, 
XmlParser.<jk>class</jk>
+        *                      }
         *              )
-        *              <jk>public</jk> Object doGetEither() {
+        *              <jk>public</jk> MyBean doGet() {
         *                      ...
         *              }
         *      }
         * </p>
         *
+        * <p>
+        * The programmatic equivalent to this annotation is:
+        * <p class='bcode w800'>
+        *      RestOpContextBuilder <jv>builder</jv> = 
RestOpContextBuilder.<jsm>create</jsm>(<jv>method</jv>,<jv>restContext</jv>);
+        *      <jv>builder</jv>.getSerializers().set(<jv>classes</jv>);
+        * </p>
+        *
         * <ul class='seealso'>
         *      <li class='link'>{@doc RestSerializers}
-        *      <li class='ja'>{@link Rest#serializers()}
-        *      <li class='jm'>{@link RestContextBuilder#getSerializers()}
-        *      <li class='jm'>{@link RestOpContextBuilder#getSerializers()}
         * </ul>
         */
        Class<? extends Serializer>[] serializers() default {};
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 cc351e2..e12b293 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
@@ -511,9 +511,7 @@ public class RestGetAnnotation {
 
                        b.httpMethod("get");
 
-                       none(a.serializers()).ifPresent(x -> 
b.getSerializers().clear());
                        classes(a.serializers()).ifPresent(x -> 
b.getSerializers().set(x));
-                       none(a.encoders()).ifPresent(x -> 
b.getEncoders().clear());
                        classes(a.encoders()).ifPresent(x -> 
b.getEncoders().set(x));
                        type(a.contextClass()).ifPresent(x -> 
b.contextClass(x));
                        strings(a.produces()).map(MediaType::of).forEach(x -> 
b.produces(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 c05dde9..237429e 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.serializer.*;
 import org.apache.juneau.http.header.*;
 import org.apache.juneau.http.remote.*;
+import org.apache.juneau.parser.*;
 import org.apache.juneau.dto.swagger.*;
 import org.apache.juneau.encoders.*;
 
@@ -387,23 +388,47 @@ public @interface RestOp {
        String[] description() default {};
 
        /**
-        * Compression encoders.
+        * Specifies the compression encoders for this method.
         *
         * <p>
-        * Use this annotation when the list of encoders assigned to a method 
differs from the list of encoders assigned at
-        * the servlet level.
+        * Encoders are used to enable various kinds of compression (e.g. 
<js>"gzip"</js>) on requests and responses.
         *
         * <p>
-        * These can be used to enable various kinds of compression (e.g. 
<js>"gzip"</js>) on requests and responses.
+        * This value overrides encoders specified at the class level using 
{@link Rest#encoders()}.
+        * The {@link org.apache.juneau.encoders.EncoderGroup.Inherit} class 
can be used to include values from the parent class.
         *
-        * <ul class='notes'>
-        *      <li>
-        *              Use {@link 
org.apache.juneau.encoders.EncoderGroup.Inherit} to inherit encoders from the 
resource class.
-        * </ul>
+        * <h5 class='section'>Example:</h5>
+        * <p class='bcode w800'>
+        *      <jc>// Define a REST resource that handles GZIP 
compression.</jc>
+        *      <ja>@Rest</ja>(
+        *              encoders={
+        *                      GzipEncoder.<jk>class</jk>
+        *              }
+        *      )
+        *      <jk>public class</jk> MyResource {
+        *
+        *              <jc>// Define a REST method that can also use a custom 
encoder.</jc>
+        *              <ja>@RestOp</ja>(
+        *                      method=<jsf>GET</jsf>,
+        *                      encoders={
+        *                              EncoderGroup.Inherit.<jk>class</jk>, 
MyEncoder.<jk>class</jk>
+        *                      }
+        *              )
+        *              <jk>public</jk> MyBean doGet() {
+        *                      ...
+        *              }
+        *      }
+        * </p>
+        *
+        * <p>
+        * The programmatic equivalent to this annotation is:
+        * <p class='bcode w800'>
+        *      RestOpContextBuilder <jv>builder</jv> = 
RestOpContextBuilder.<jsm>create</jsm>(<jv>method</jv>,<jv>restContext</jv>);
+        *      <jv>builder</jv>.getEncoders().set(<jv>classes</jv>);
+        * </p>
         *
         * <ul class='seealso'>
-        *      <li class='jm'>{@link RestContextBuilder#getEncoders()}
-        *      <li class='jm'>{@link RestOpContextBuilder#getEncoders()}
+        *      <li class='link'>{@doc RestEncoders}
         * </ul>
         */
        Class<? extends Encoder>[] encoders() default {};
@@ -523,34 +548,54 @@ public @interface RestOp {
        String[] on() default {};
 
        /**
-        * Parsers.
-        *
-        * <p>
-        * If no value is specified, the parsers are inherited from the class.
-        * <br>Otherwise, this value overrides the parsers defined on the class.
+        * Specifies the parsers for converting HTTP request bodies into POJOs 
for this method.
         *
         * <p>
-        * Use {@link Inherit} to inherit parsers defined on the class.
+        * Parsers are used to convert the body of HTTP requests into POJOs.
+        * <br>Any of the Juneau framework parsers can be used in this setting.
+        * <br>The parser selected is based on the request <c>Content-Type</c> 
header matched against the values returned by the following method
+        * using a best-match algorithm:
+        * <ul class='javatree'>
+        *      <li class='jm'>{@link Parser#getMediaTypes()}
+        * </ul>
         *
         * <p>
-        * Use {@link None} to suppress inheriting parsers defined on the class.
+        * This value overrides parsers specified at the class level using 
{@link Rest#parsers()}.
+        * The {@link org.apache.juneau.parser.ParserGroup.Inherit} class can 
be used to include values from the parent class.
         *
+        * <h5 class='section'>Example:</h5>
         * <p class='bcode w800'>
-        *      <jk>public class</jk> MyResource <jk>extends</jk> RestServlet {
+        *      <jc>// Define a REST resource that can consume JSON and 
HTML.</jc>
+        *      <ja>@Rest</ja>(
+        *              parsers={
+        *                      JsonParser.<jk>class</jk>,
+        *                      HtmlParser.<jk>class</jk>
+        *              }
+        *      )
+        *      <jk>public class</jk> MyResource {
         *
+        *              <jc>// Define a REST method that can also consume 
XML.</jc>
         *              <ja>@RestOp</ja>(
-        *                      method=<jsf>PUT</jsf>,
-        *                      path=<js>"/foo"</js>,
-        *                      parsers=MySpecialParser.<jk>class</jk>
+        *                      method=<jsf>POST</jsf>,
+        *                      parsers={
+        *                              ParserGroup.Inherit.<jk>class</jk>, 
XmlParser.<jk>class</jk>
+        *                      }
         *              )
-        *              <jk>public</jk> Object doGetWithSpecialAcceptType() {
-        *                      <jc>// Handle request for special Accept 
type</jc>
+        *              <jk>public void</jk> doPost(MyBean <jv>bean</jv>) {
+        *                      ...
         *              }
         *      }
         * </p>
         *
+        * <p>
+        * The programmatic equivalent to this annotation is:
+        * <p class='bcode w800'>
+        *      RestOpContextBuilder <jv>builder</jv> = 
RestOpContextBuilder.<jsm>create</jsm>(<jv>method</jv>,<jv>restContext</jv>);
+        *      <jv>builder</jv>.getParsers().set(<jv>classes</jv>);
+        * </p>
+        *
         * <ul class='seealso'>
-        *      <li class='jf'>{@link RestContext#REST_parsers}
+        *      <li class='link'>{@doc RestParsers}
         * </ul>
         */
        Class<?>[] parsers() default {};
@@ -722,49 +767,54 @@ public @interface RestOp {
        String rolesDeclared() default "";
 
        /**
-        * The serializers to use to serialize POJOs into response bodies.
+        * Specifies the serializers for marshalling POJOs into response bodies 
for this method.
         *
         * <p>
-        * If no value is specified, the serializers are inherited from the 
class.
-        * <br>Otherwise, this value overrides the serializers defined on the 
class.
+        * Serializer are used to convert POJOs to HTTP response bodies.
+        * <br>Any of the Juneau framework serializers can be used in this 
setting.
+        * <br>The serializer selected is based on the request <c>Accept</c> 
header matched against the values returned by the following method
+        * using a best-match algorithm:
+        * <ul class='javatree'>
+        *      <li class='jm'>{@link Serializer#getMediaTypeRanges()}
+        * </ul>
         *
         * <p>
-        * Use {@link org.apache.juneau.serializer.SerializerGroup.Inherit} to 
inherit serializers defined on the class.
+        * This value overrides serializers specified at the class level using 
{@link Rest#serializers()}.
+        * The {@link org.apache.juneau.serializer.SerializerGroup.Inherit} 
class can be used to include values from the parent class.
         *
         * <h5 class='section'>Example:</h5>
         * <p class='bcode w800'>
+        *      <jc>// Define a REST resource that can produce JSON and 
HTML.</jc>
         *      <ja>@Rest</ja>(
         *              serializers={
-        *                      JsonSerializer.<jk>class</jk>
+        *                      JsonParser.<jk>class</jk>,
+        *                      HtmlParser.<jk>class</jk>
         *              }
         *      )
-        *      <jk>public class</jk> MyResource <jk>extends</jk> RestServlet {
-        *
-        *              <ja>@RestOp</ja>(
-        *                      method=<js>"get"</js>,
-        *                      path=<js>"/foo"</js>,
-        *                      serializers=XmlSerializer.<jk>class</jk>  
<jc>// Override serializers on class.</jc>
-        *              )
-        *              <jk>public</jk> Object doGetOnlyXml() {
-        *                      ...
-        *              }
+        *      <jk>public class</jk> MyResource {
         *
+        *              <jc>// Define a REST method that can also produce 
XML.</jc>
         *              <ja>@RestOp</ja>(
-        *                      method=<js>"get"</js>,
-        *                      path=<js>"/bar"</js>,
-        *                      
serializers={SerializerGroup.Inherit.<jk>class<jk>, 
XmlSerializer.<jk>class</jk>}  <jc>// Add to serializers on class.</jc>
+        *                      method=<jsf>POST</jsf>,
+        *                      parsers={
+        *                              SerializerGroup.Inherit.<jk>class</jk>, 
XmlParser.<jk>class</jk>
+        *                      }
         *              )
-        *              <jk>public</jk> Object doGetEither() {
+        *              <jk>public void</jk> doPost(MyBean <jv>bean</jv>) {
         *                      ...
         *              }
         *      }
         * </p>
         *
+        * <p>
+        * The programmatic equivalent to this annotation is:
+        * <p class='bcode w800'>
+        *      RestOpContextBuilder <jv>builder</jv> = 
RestOpContextBuilder.<jsm>create</jsm>(<jv>method</jv>,<jv>restContext</jv>);
+        *      <jv>builder</jv>.getSerializers().set(<jv>classes</jv>);
+        * </p>
+        *
         * <ul class='seealso'>
         *      <li class='link'>{@doc RestSerializers}
-        *      <li class='ja'>{@link Rest#serializers()}
-        *      <li class='jm'>{@link RestContextBuilder#getSerializers()}
-        *      <li class='jm'>{@link RestOpContextBuilder#getSerializers()}
         * </ul>
         */
        Class<? extends Serializer>[] serializers() default {};
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 0c1866a..9a3c8ca 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
@@ -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.*;
@@ -616,10 +614,8 @@ public class RestOpAnnotation {
                public void apply(AnnotationInfo<RestOp> ai, 
RestOpContextBuilder b) {
                        RestOp a = ai.getAnnotation();
 
-                       none(a.serializers()).ifPresent(x -> 
b.getSerializers().clear());
                        classes(a.serializers()).ifPresent(x -> 
b.getSerializers().set(x));
-                       b.set(REST_parsers, 
merge(ConverterUtils.toType(b.peek(REST_parsers), Object[].class), 
a.parsers()));
-                       none(a.encoders()).ifPresent(x -> 
b.getEncoders().clear());
+                       classes(a.parsers()).ifPresent(x -> 
b.getParsers().set(x));
                        classes(a.encoders()).ifPresent(x -> 
b.getEncoders().set(x));
                        type(a.contextClass()).ifPresent(x -> 
b.contextClass(x));
                        strings(a.produces()).map(MediaType::of).forEach(x -> 
b.produces(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 5ef7feb..f8b88a0 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
@@ -25,6 +25,7 @@ import org.apache.juneau.serializer.*;
 import org.apache.juneau.dto.swagger.*;
 import org.apache.juneau.encoders.*;
 import org.apache.juneau.http.header.*;
+import org.apache.juneau.parser.*;
 
 /**
  * Identifies a REST POST operation Java method on a {@link RestServlet} 
implementation class.
@@ -389,22 +390,46 @@ public @interface RestPost {
        String[] description() default {};
 
        /**
-        * Compression encoders.
+        * Specifies the compression encoders for this method.
         *
         * <p>
-        * Use this annotation when the list of encoders assigned to a method 
differs from the list of encoders assigned at
-        * the servlet level.
+        * Encoders are used to enable various kinds of compression (e.g. 
<js>"gzip"</js>) on requests and responses.
         *
         * <p>
-        * These can be used to enable various kinds of compression (e.g. 
<js>"gzip"</js>) on requests and responses.
+        * This value overrides encoders specified at the class level using 
{@link Rest#encoders()}.
+        * The {@link org.apache.juneau.encoders.EncoderGroup.Inherit} class 
can be used to include values from the parent class.
         *
-        * <ul class='notes'>
-        *      <li>
-        *              Use {@link 
org.apache.juneau.encoders.EncoderGroup.Inherit} to inherit encoders from the 
resource class.
-        * </ul>
+        * <h5 class='section'>Example:</h5>
+        * <p class='bcode w800'>
+        *      <jc>// Define a REST resource that handles GZIP 
compression.</jc>
+        *      <ja>@Rest</ja>(
+        *              encoders={
+        *                      GzipEncoder.<jk>class</jk>
+        *              }
+        *      )
+        *      <jk>public class</jk> MyResource {
+        *
+        *              <jc>// Define a REST method that can also use a custom 
encoder.</jc>
+        *              <ja>@RestPost</ja>(
+        *                      encoders={
+        *                              EncoderGroup.Inherit.<jk>class</jk>, 
MyEncoder.<jk>class</jk>
+        *                      }
+        *              )
+        *              <jk>public void</jk> doPost(MyBean <jv>bean</jv>) {
+        *                      ...
+        *              }
+        *      }
+        * </p>
+        *
+        * <p>
+        * The programmatic equivalent to this annotation is:
+        * <p class='bcode w800'>
+        *      RestOpContextBuilder <jv>builder</jv> = 
RestOpContextBuilder.<jsm>create</jsm>(<jv>method</jv>,<jv>restContext</jv>);
+        *      <jv>builder</jv>.getEncoders().set(<jv>classes</jv>);
+        * </p>
         *
         * <ul class='seealso'>
-        *      <li class='jm'>{@link RestOpContextBuilder#getEncoders()}
+        *      <li class='link'>{@doc RestEncoders}
         * </ul>
         */
        Class<? extends Encoder>[] encoders() default {};
@@ -475,33 +500,53 @@ public @interface RestPost {
        String[] on() default {};
 
        /**
-        * Parsers.
-        *
-        * <p>
-        * If no value is specified, the parsers are inherited from the class.
-        * <br>Otherwise, this value overrides the parsers defined on the class.
+        * Specifies the parsers for converting HTTP request bodies into POJOs 
for this method.
         *
         * <p>
-        * Use {@link Inherit} to inherit parsers defined on the class.
+        * Parsers are used to convert the body of HTTP requests into POJOs.
+        * <br>Any of the Juneau framework parsers can be used in this setting.
+        * <br>The parser selected is based on the request <c>Content-Type</c> 
header matched against the values returned by the following method
+        * using a best-match algorithm:
+        * <ul class='javatree'>
+        *      <li class='jm'>{@link Parser#getMediaTypes()}
+        * </ul>
         *
         * <p>
-        * Use {@link None} to suppress inheriting parsers defined on the class.
+        * This value overrides parsers specified at the class level using 
{@link Rest#parsers()}.
+        * The {@link org.apache.juneau.parser.ParserGroup.Inherit} class can 
be used to include values from the parent class.
         *
+        * <h5 class='section'>Example:</h5>
         * <p class='bcode w800'>
-        *      <jk>public class</jk> MyResource <jk>extends</jk> RestServlet {
+        *      <jc>// Define a REST resource that can consume JSON and 
HTML.</jc>
+        *      <ja>@Rest</ja>(
+        *              parsers={
+        *                      JsonParser.<jk>class</jk>,
+        *                      HtmlParser.<jk>class</jk>
+        *              }
+        *      )
+        *      <jk>public class</jk> MyResource {
         *
+        *              <jc>// Define a REST method that can also consume 
XML.</jc>
         *              <ja>@RestPost</ja>(
-        *                      path=<js>"/foo"</js>,
-        *                      parsers=MySpecialParser.<jk>class</jk>
+        *                      parsers={
+        *                              ParserGroup.Inherit.<jk>class</jk>, 
XmlParser.<jk>class</jk>
+        *                      }
         *              )
-        *              <jk>public</jk> Object doPostWithSpecialAcceptType() {
-        *                      <jc>// Handle request for special Accept 
type</jc>
+        *              <jk>public void</jk> doPost(MyBean <jv>bean</jv>) {
+        *                      ...
         *              }
         *      }
         * </p>
         *
+        * <p>
+        * The programmatic equivalent to this annotation is:
+        * <p class='bcode w800'>
+        *      RestOpContextBuilder <jv>builder</jv> = 
RestOpContextBuilder.<jsm>create</jsm>(<jv>method</jv>,<jv>restContext</jv>);
+        *      <jv>builder</jv>.getParsers().set(<jv>classes</jv>);
+        * </p>
+        *
         * <ul class='seealso'>
-        *      <li class='jf'>{@link RestContext#REST_parsers}
+        *      <li class='link'>{@doc RestParsers}
         * </ul>
         */
        Class<?>[] parsers() default {};
@@ -645,47 +690,53 @@ public @interface RestPost {
        String rolesDeclared() default "";
 
        /**
-        * The serializers to use to serialize POJOs into response bodies.
+        * Specifies the serializers for marshalling POJOs into response bodies 
for this method.
         *
         * <p>
-        * If no value is specified, the serializers are inherited from the 
class.
-        * <br>Otherwise, this value overrides the serializers defined on the 
class.
+        * Serializer are used to convert POJOs to HTTP response bodies.
+        * <br>Any of the Juneau framework serializers can be used in this 
setting.
+        * <br>The serializer selected is based on the request <c>Accept</c> 
header matched against the values returned by the following method
+        * using a best-match algorithm:
+        * <ul class='javatree'>
+        *      <li class='jm'>{@link Serializer#getMediaTypeRanges()}
+        * </ul>
         *
         * <p>
-        * Use {@link org.apache.juneau.serializer.SerializerGroup.Inherit} to 
inherit serializers defined on the class.
+        * This value overrides serializers specified at the class level using 
{@link Rest#serializers()}.
+        * The {@link org.apache.juneau.serializer.SerializerGroup.Inherit} 
class can be used to include values from the parent class.
         *
         * <h5 class='section'>Example:</h5>
         * <p class='bcode w800'>
+        *      <jc>// Define a REST resource that can produce JSON and 
HTML.</jc>
         *      <ja>@Rest</ja>(
         *              serializers={
-        *                      JsonSerializer.<jk>class</jk>
+        *                      JsonParser.<jk>class</jk>,
+        *                      HtmlParser.<jk>class</jk>
         *              }
         *      )
-        *      <jk>public class</jk> MyResource <jk>extends</jk> RestServlet {
-        *
-        *              <ja>@RestGet</ja>(
-        *                      path=<js>"/foo"</js>,
-        *                      serializers=XmlSerializer.<jk>class</jk>  
<jc>// Override serializers on class.</jc>
-        *              )
-        *              <jk>public</jk> Object doGetOnlyXml() {
-        *                      ...
-        *              }
+        *      <jk>public class</jk> MyResource {
         *
-        *              <ja>@RestGet</ja>(
-        *                      path=<js>"/bar"</js>,
-        *                      
serializers={SerializerGroup.Inherit.<jk>class<jk>, 
XmlSerializer.<jk>class</jk>}  <jc>// Add to serializers on class.</jc>
+        *              <jc>// Define a REST method that can also produce 
XML.</jc>
+        *              <ja>@RestPost</ja>(
+        *                      parsers={
+        *                              SerializerGroup.Inherit.<jk>class</jk>, 
XmlParser.<jk>class</jk>
+        *                      }
         *              )
-        *              <jk>public</jk> Object doGetEither() {
+        *              <jk>public</jk> MyBean doPost() {
         *                      ...
         *              }
         *      }
         * </p>
         *
+        * <p>
+        * The programmatic equivalent to this annotation is:
+        * <p class='bcode w800'>
+        *      RestOpContextBuilder <jv>builder</jv> = 
RestOpContextBuilder.<jsm>create</jsm>(<jv>method</jv>,<jv>restContext</jv>);
+        *      <jv>builder</jv>.getSerializers().set(<jv>classes</jv>);
+        * </p>
+        *
         * <ul class='seealso'>
         *      <li class='link'>{@doc RestSerializers}
-        *      <li class='ja'>{@link Rest#serializers()}
-        *      <li class='jm'>{@link RestContextBuilder#getSerializers()}
-        *      <li class='jm'>{@link RestOpContextBuilder#getSerializers()}
         * </ul>
         */
        Class<? extends Serializer>[] serializers() default {};
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 08e32ed..7efddec 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
@@ -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.*;
@@ -25,7 +23,6 @@ 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.*;
 import org.apache.juneau.rest.*;
 import org.apache.juneau.serializer.*;
@@ -601,10 +598,8 @@ public class RestPostAnnotation {
 
                        b.httpMethod("post");
 
-                       none(a.serializers()).ifPresent(x -> 
b.getSerializers().clear());
                        classes(a.serializers()).ifPresent(x -> 
b.getSerializers().set(x));
-                       b.set(REST_parsers, 
merge(ConverterUtils.toType(b.peek(REST_parsers), Object[].class), 
a.parsers()));
-                       none(a.encoders()).ifPresent(x -> 
b.getEncoders().clear());
+                       classes(a.parsers()).ifPresent(x -> 
b.getParsers().set(x));
                        classes(a.encoders()).ifPresent(x -> 
b.getEncoders().set(x));
                        type(a.contextClass()).ifPresent(x -> 
b.contextClass(x));
                        strings(a.produces()).map(MediaType::of).forEach(x -> 
b.produces(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 6772c9a..5706fe0 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
@@ -25,6 +25,7 @@ import org.apache.juneau.serializer.*;
 import org.apache.juneau.dto.swagger.*;
 import org.apache.juneau.encoders.*;
 import org.apache.juneau.http.header.*;
+import org.apache.juneau.parser.*;
 
 /**
  * Identifies a REST PUT operation Java method on a {@link RestServlet} 
implementation class.
@@ -389,23 +390,46 @@ public @interface RestPut {
        String[] description() default {};
 
        /**
-        * Compression encoders.
+        * Specifies the compression encoders for this method.
         *
         * <p>
-        * Use this annotation when the list of encoders assigned to a method 
differs from the list of encoders assigned at
-        * the servlet level.
+        * Encoders are used to enable various kinds of compression (e.g. 
<js>"gzip"</js>) on requests and responses.
         *
         * <p>
-        * These can be used to enable various kinds of compression (e.g. 
<js>"gzip"</js>) on requests and responses.
+        * This value overrides encoders specified at the class level using 
{@link Rest#encoders()}.
+        * The {@link org.apache.juneau.encoders.EncoderGroup.Inherit} class 
can be used to include values from the parent class.
         *
-        * <ul class='notes'>
-        *      <li>
-        *              Use {@link 
org.apache.juneau.encoders.EncoderGroup.Inherit} to inherit encoders from the 
resource class.
-        * </ul>
+        * <h5 class='section'>Example:</h5>
+        * <p class='bcode w800'>
+        *      <jc>// Define a REST resource that handles GZIP 
compression.</jc>
+        *      <ja>@Rest</ja>(
+        *              encoders={
+        *                      GzipEncoder.<jk>class</jk>
+        *              }
+        *      )
+        *      <jk>public class</jk> MyResource {
+        *
+        *              <jc>// Define a REST method that can also use a custom 
encoder.</jc>
+        *              <ja>@RestPut</ja>(
+        *                      encoders={
+        *                              EncoderGroup.Inherit.<jk>class</jk>, 
MyEncoder.<jk>class</jk>
+        *                      }
+        *              )
+        *              <jk>public void</jk> doPut(MyBean <jv>bean</jv>) {
+        *                      ...
+        *              }
+        *      }
+        * </p>
+        *
+        * <p>
+        * The programmatic equivalent to this annotation is:
+        * <p class='bcode w800'>
+        *      RestOpContextBuilder <jv>builder</jv> = 
RestOpContextBuilder.<jsm>create</jsm>(<jv>method</jv>,<jv>restContext</jv>);
+        *      <jv>builder</jv>.getEncoders().set(<jv>classes</jv>);
+        * </p>
         *
         * <ul class='seealso'>
-        *      <li class='jm'>{@link RestContextBuilder#getEncoders()}
-        *      <li class='jm'>{@link RestOpContextBuilder#getEncoders()}
+        *      <li class='link'>{@doc RestEncoders}
         * </ul>
         */
        Class<? extends Encoder>[] encoders() default {};
@@ -476,33 +500,53 @@ public @interface RestPut {
        String[] on() default {};
 
        /**
-        * Parsers.
-        *
-        * <p>
-        * If no value is specified, the parsers are inherited from the class.
-        * <br>Otherwise, this value overrides the parsers defined on the class.
+        * Specifies the parsers for converting HTTP request bodies into POJOs 
for this method.
         *
         * <p>
-        * Use {@link Inherit} to inherit parsers defined on the class.
+        * Parsers are used to convert the body of HTTP requests into POJOs.
+        * <br>Any of the Juneau framework parsers can be used in this setting.
+        * <br>The parser selected is based on the request <c>Content-Type</c> 
header matched against the values returned by the following method
+        * using a best-match algorithm:
+        * <ul class='javatree'>
+        *      <li class='jm'>{@link Parser#getMediaTypes()}
+        * </ul>
         *
         * <p>
-        * Use {@link None} to suppress inheriting parsers defined on the class.
+        * This value overrides parsers specified at the class level using 
{@link Rest#parsers()}.
+        * The {@link org.apache.juneau.parser.ParserGroup.Inherit} class can 
be used to include values from the parent class.
         *
+        * <h5 class='section'>Example:</h5>
         * <p class='bcode w800'>
-        *      <jk>public class</jk> MyResource <jk>extends</jk> RestServlet {
+        *      <jc>// Define a REST resource that can consume JSON and 
HTML.</jc>
+        *      <ja>@Rest</ja>(
+        *              parsers={
+        *                      JsonParser.<jk>class</jk>,
+        *                      HtmlParser.<jk>class</jk>
+        *              }
+        *      )
+        *      <jk>public class</jk> MyResource {
         *
+        *              <jc>// Define a REST method that can also consume 
XML.</jc>
         *              <ja>@RestPut</ja>(
-        *                      path=<js>"/foo"</js>,
-        *                      parsers=MySpecialParser.<jk>class</jk>
+        *                      parsers={
+        *                              ParserGroup.Inherit.<jk>class</jk>, 
XmlParser.<jk>class</jk>
+        *                      }
         *              )
-        *              <jk>public</jk> Object doPutWithSpecialAcceptType() {
-        *                      <jc>// Handle request for special Accept 
type</jc>
+        *              <jk>public void</jk> doPut(MyBean <jv>bean</jv>) {
+        *                      ...
         *              }
         *      }
         * </p>
         *
+        * <p>
+        * The programmatic equivalent to this annotation is:
+        * <p class='bcode w800'>
+        *      RestOpContextBuilder <jv>builder</jv> = 
RestOpContextBuilder.<jsm>create</jsm>(<jv>method</jv>,<jv>restContext</jv>);
+        *      <jv>builder</jv>.getParsers().set(<jv>classes</jv>);
+        * </p>
+        *
         * <ul class='seealso'>
-        *      <li class='jf'>{@link RestContext#REST_parsers}
+        *      <li class='link'>{@doc RestParsers}
         * </ul>
         */
        Class<?>[] parsers() default {};
@@ -646,47 +690,53 @@ public @interface RestPut {
        String rolesDeclared() default "";
 
        /**
-        * The serializers to use to serialize POJOs into response bodies.
+        * Specifies the serializers for marshalling POJOs into response bodies 
for this method.
         *
         * <p>
-        * If no value is specified, the serializers are inherited from the 
class.
-        * <br>Otherwise, this value overrides the serializers defined on the 
class.
+        * Serializer are used to convert POJOs to HTTP response bodies.
+        * <br>Any of the Juneau framework serializers can be used in this 
setting.
+        * <br>The serializer selected is based on the request <c>Accept</c> 
header matched against the values returned by the following method
+        * using a best-match algorithm:
+        * <ul class='javatree'>
+        *      <li class='jm'>{@link Serializer#getMediaTypeRanges()}
+        * </ul>
         *
         * <p>
-        * Use {@link org.apache.juneau.serializer.SerializerGroup.Inherit} to 
inherit serializers defined on the class.
+        * This value overrides serializers specified at the class level using 
{@link Rest#serializers()}.
+        * The {@link org.apache.juneau.serializer.SerializerGroup.Inherit} 
class can be used to include values from the parent class.
         *
         * <h5 class='section'>Example:</h5>
         * <p class='bcode w800'>
+        *      <jc>// Define a REST resource that can produce JSON and 
HTML.</jc>
         *      <ja>@Rest</ja>(
         *              serializers={
-        *                      JsonSerializer.<jk>class</jk>
+        *                      JsonParser.<jk>class</jk>,
+        *                      HtmlParser.<jk>class</jk>
         *              }
         *      )
-        *      <jk>public class</jk> MyResource <jk>extends</jk> RestServlet {
-        *
-        *              <ja>@RestPut</ja>(
-        *                      path=<js>"/foo"</js>,
-        *                      serializers=XmlSerializer.<jk>class</jk>  
<jc>// Override serializers on class.</jc>
-        *              )
-        *              <jk>public</jk> Object doGetOnlyXml() {
-        *                      ...
-        *              }
+        *      <jk>public class</jk> MyResource {
         *
+        *              <jc>// Define a REST method that can also produce 
XML.</jc>
         *              <ja>@RestPut</ja>(
-        *                      path=<js>"/bar"</js>,
-        *                      
serializers={SerializerGroup.Inherit.<jk>class<jk>, 
XmlSerializer.<jk>class</jk>}  <jc>// Add to serializers on class.</jc>
+        *                      parsers={
+        *                              SerializerGroup.Inherit.<jk>class</jk>, 
XmlParser.<jk>class</jk>
+        *                      }
         *              )
-        *              <jk>public</jk> Object doGetEither() {
+        *              <jk>public</jk> MyBean doPut() {
         *                      ...
         *              }
         *      }
         * </p>
         *
+        * <p>
+        * The programmatic equivalent to this annotation is:
+        * <p class='bcode w800'>
+        *      RestOpContextBuilder <jv>builder</jv> = 
RestOpContextBuilder.<jsm>create</jsm>(<jv>method</jv>,<jv>restContext</jv>);
+        *      <jv>builder</jv>.getSerializers().set(<jv>classes</jv>);
+        * </p>
+        *
         * <ul class='seealso'>
         *      <li class='link'>{@doc RestSerializers}
-        *      <li class='ja'>{@link Rest#serializers()}
-        *      <li class='jm'>{@link RestContextBuilder#getSerializers()}
-        *      <li class='jm'>{@link RestOpContextBuilder#getSerializers()}
         * </ul>
         */
        Class<? extends Serializer>[] serializers() default {};
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 7616b3e..f9f2213 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
@@ -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.*;
@@ -25,7 +23,6 @@ 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.*;
 import org.apache.juneau.rest.*;
 import org.apache.juneau.serializer.*;
@@ -601,10 +598,8 @@ public class RestPutAnnotation {
 
                        b.httpMethod("put");
 
-                       none(a.serializers()).ifPresent(x -> 
b.getSerializers().clear());
                        classes(a.serializers()).ifPresent(x -> 
b.getSerializers().set(x));
-                       b.set(REST_parsers, 
merge(ConverterUtils.toType(b.peek(REST_parsers), Object[].class), 
a.parsers()));
-                       none(a.encoders()).ifPresent(x -> 
b.getEncoders().clear());
+                       classes(a.parsers()).ifPresent(x -> 
b.getParsers().set(x));
                        classes(a.encoders()).ifPresent(x -> 
b.getEncoders().set(x));
                        type(a.contextClass()).ifPresent(x -> 
b.contextClass(x));
                        strings(a.produces()).map(MediaType::of).forEach(x -> 
b.produces(x));
diff --git 
a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/util/RestUtils.java
 
b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/util/RestUtils.java
index 59de93f..d398ddf 100644
--- 
a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/util/RestUtils.java
+++ 
b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/util/RestUtils.java
@@ -23,10 +23,8 @@ import java.util.regex.*;
 import javax.servlet.http.*;
 
 import org.apache.juneau.collections.*;
-import org.apache.juneau.internal.*;
 import org.apache.juneau.json.*;
 import org.apache.juneau.parser.*;
-import org.apache.juneau.rest.*;
 import org.apache.juneau.rest.annotation.*;
 import org.apache.juneau.uon.*;
 
@@ -380,49 +378,6 @@ public final class RestUtils {
        }
 
        /**
-        * Merges the specified parent and child arrays.
-        *
-        * <p>
-        * The general concept is to allow child values to override parent 
values.
-        *
-        * <p>
-        * The rules are:
-        * <ul>
-        *      <li>If the child array is not empty, then the child array is 
returned.
-        *      <li>If the child array is empty, then the parent array is 
returned.
-        *      <li>If the child array contains {@link None}, then an empty 
array is always returned.
-        *      <li>If the child array contains {@link Inherit}, then the 
contents of the parent array are inserted into the position of the {@link 
Inherit} entry.
-        * </ul>
-        *
-        * @param fromParent The parent array.
-        * @param fromChild The child array.
-        * @return A new merged array.
-        */
-       public static Object[] merge(Object[] fromParent, Object[] fromChild) {
-
-               if (fromParent == null)
-                       fromParent = new Object[0];
-
-               if (ArrayUtils.contains(None.class, fromChild))
-                       return new Object[0];
-
-               if (fromChild.length == 0)
-                       return fromParent;
-
-               if (! ArrayUtils.contains(Inherit.class, fromChild))
-                       return fromChild;
-
-               AList<Object> l = AList.create();
-               for (Object o : fromChild) {
-                       if (o == Inherit.class)
-                               l.a(fromParent);
-                       else
-                               l.add(o);
-               }
-               return l.asArrayOf(Object.class);
-       }
-
-       /**
         * If the specified path-info starts with the specified context path, 
trims the context path from the path info.
         *
         * @param contextPath The context path.
diff --git 
a/juneau-utest/src/test/java/org/apache/juneau/parser/ParserGroupTest.java 
b/juneau-utest/src/test/java/org/apache/juneau/parser/ParserGroupTest.java
index b56ef85..525a353 100755
--- a/juneau-utest/src/test/java/org/apache/juneau/parser/ParserGroupTest.java
+++ b/juneau-utest/src/test/java/org/apache/juneau/parser/ParserGroupTest.java
@@ -27,7 +27,7 @@ public class ParserGroupTest {
        @Test
        public void testParserGroupMatching() throws Exception {
 
-               ParserGroup g = ParserGroup.create().append(Parser1.class, 
Parser2.class, Parser3.class).build();
+               ParserGroup g = ParserGroup.create().add(Parser1.class, 
Parser2.class, Parser3.class).build();
                assertObject(g.getParser("text/foo")).isType(Parser1.class);
                assertObject(g.getParser("text/foo_a")).isType(Parser1.class);
                
assertObject(g.getParser("text/foo_a+xxx")).isType(Parser1.class);
@@ -54,18 +54,18 @@ public class ParserGroupTest {
        
//====================================================================================================
        @Test
        public void testInheritence() throws Exception {
-               ParserGroupBuilder gb = null;
+               ParserGroup.Builder gb = null;
                ParserGroup g = null;
 
-               gb = ParserGroup.create().append(P1.class, P2.class);
+               gb = ParserGroup.create().add(P1.class, P2.class);
                g = gb.build();
                
assertObject(g.getSupportedMediaTypes()).asJson().is("['text/1','text/2','text/2a']");
 
-               gb = ParserGroup.create().append(P1.class, 
P2.class).append(P3.class, P4.class);
+               gb = ParserGroup.create().add(P1.class, P2.class).add(P3.class, 
P4.class);
                g = gb.build();
                
assertObject(g.getSupportedMediaTypes()).asJson().is("['text/3','text/4','text/4a','text/1','text/2','text/2a']");
 
-               gb = ParserGroup.create().append(P1.class, 
P2.class).append(P3.class, P4.class).append(P5.class);
+               gb = ParserGroup.create().add(P1.class, P2.class).add(P3.class, 
P4.class).add(P5.class);
                g = gb.build();
                
assertObject(g.getSupportedMediaTypes()).asJson().is("['text/5','text/3','text/4','text/4a','text/1','text/2','text/2a']");
        }
diff --git 
a/juneau-utest/src/test/java/org/apache/juneau/rest/annotation/Restx_Parsers_Test.java
 
b/juneau-utest/src/test/java/org/apache/juneau/rest/annotation/Restx_Parsers_Test.java
index 616c1bf..6fc867d 100644
--- 
a/juneau-utest/src/test/java/org/apache/juneau/rest/annotation/Restx_Parsers_Test.java
+++ 
b/juneau-utest/src/test/java/org/apache/juneau/rest/annotation/Restx_Parsers_Test.java
@@ -153,7 +153,7 @@ public class Restx_Parsers_Test {
        @Rest(parsers={P1.class,P2.class})
        public static class B {}
 
-       @Rest(parsers={P3.class,P4.class,Inherit.class})
+       @Rest(parsers={P3.class,P4.class})
        public static class B1 extends B {}
 
        @Rest
diff --git 
a/juneau-utest/src/test/java/org/apache/juneau/testutils/MockReaderParser.java 
b/juneau-utest/src/test/java/org/apache/juneau/testutils/MockReaderParser.java
index 4c58b3d..b1b87de 100644
--- 
a/juneau-utest/src/test/java/org/apache/juneau/testutils/MockReaderParser.java
+++ 
b/juneau-utest/src/test/java/org/apache/juneau/testutils/MockReaderParser.java
@@ -50,6 +50,14 @@ public class MockReaderParser extends ReaderParser {
        public static class Builder extends ReaderParserBuilder {
                MockReaderParserFunction function;
 
+               public Builder() {
+                       super();
+               }
+
+               public Builder(Builder copyFrom) {
+                       super(copyFrom);
+               }
+
                public Builder function(MockReaderParserFunction function) {
                        this.function = function;
                        return this;
@@ -63,7 +71,7 @@ public class MockReaderParser extends ReaderParser {
 
                @Override
                public Builder copy() {
-                       throw new NoSuchMethodError("Not implemented.");
+                       return new Builder(this);
                }
        }
 

Reply via email to