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<{@link
org.apache.juneau.parser.Parser}|Class<{@link
org.apache.juneau.parser.Parser}>></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: </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: </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: </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: </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);
}
}