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 7f54e8124a Add support for setting Session properties via setProperty
7f54e8124a is described below
commit 7f54e8124a526ec5868f088128a2a2dc72b498d6
Author: James Bognar <[email protected]>
AuthorDate: Sat Apr 4 14:06:17 2026 -0400
Add support for setting Session properties via setProperty
---
RELEASE-NOTES.txt | 36 +++
.../apache/juneau/jena/RdfSerializerSession.java | 11 -
.../juneau/jena/RdfStreamSerializerSession.java | 4 -
.../org/apache/juneau/BeanTraverseSession.java | 26 +-
.../apache/juneau/bson/BsonSerializerSession.java | 4 -
.../apache/juneau/cbor/CborSerializerSession.java | 10 -
.../apache/juneau/csv/CsvSerializerSession.java | 59 +++-
.../apache/juneau/html/HtmlSerializerSession.java | 127 +++++++--
.../org/apache/juneau/json/JsonParserSession.java | 31 +-
.../apache/juneau/json/JsonSerializerSession.java | 41 ++-
.../juneau/msgpack/MsgPackSerializerSession.java | 8 +-
.../org/apache/juneau/parser/ParserSession.java | 24 +-
.../juneau/serializer/SerializerSession.java | 168 ++++++++++-
.../juneau/serializer/WriterSerializerSession.java | 50 +++-
.../org/apache/juneau/uon/UonParserSession.java | 37 ++-
.../apache/juneau/uon/UonSerializerSession.java | 78 ++++--
.../urlencoding/UrlEncodingParserSession.java | 31 +-
.../urlencoding/UrlEncodingSerializerSession.java | 31 +-
.../org/apache/juneau/xml/XmlParserSession.java | 52 +++-
.../apache/juneau/xml/XmlSerializerSession.java | 123 ++++++--
.../apache/juneau/yaml/YamlSerializerSession.java | 15 -
.../org/apache/juneau/ContextSession_Test.java | 312 +++++++++++++++++++++
todo/session-options-files.zip | Bin 0 -> 439801 bytes
todo/session-options-plan.md | 288 +++++++++++++++++++
24 files changed, 1400 insertions(+), 166 deletions(-)
diff --git a/RELEASE-NOTES.txt b/RELEASE-NOTES.txt
index e3e2a27df9..fbf28c6e4e 100644
--- a/RELEASE-NOTES.txt
+++ b/RELEASE-NOTES.txt
@@ -110,6 +110,42 @@ Release Notes - Juneau - Version 9.2.1 - YYYY-MM-DD
* New classes: CsvCellParser, CsvCellSerializer, ByteArrayFormat.
* New builder options: byteArrayFormat(), allowNestedStructures(),
nullValue().
+** New Features - Per-Session Property Overrides
+
+ * Session.Builder.property(String, Object) and properties(Map) now
dispatch to typed
+ session-level setter methods, enabling per-request override of
serializer/parser configuration.
+ * Both short names (e.g., "locale") and fully-qualified names (e.g.,
"BeanSession.locale") are
+ accepted as property keys.
+ * New properties exposed as session-level overrides:
+ - ParserSession: trimStrings
+ - BeanTraverseSession: initialDepth
+ - SerializerSession: keepNullProperties, trimStrings, addBeanTypes,
addRootType,
+ sortCollections, sortMaps, trimEmptyCollections, trimEmptyMaps
+ - WriterSerializerSession: maxIndent, quoteChar
+ - CsvSerializerSession: byteArrayFormat, allowNestedStructures,
nullValue
+ - JsonSerializerSession: escapeSolidus
+ - JsonParserSession: validateEnd
+ - UonSerializerSession: encoding, paramFormat (also fixes quoteChar
bypass)
+ - UonParserSession: validateEnd
+ - UrlEncodingSerializerSession: expandedParams
+ - UrlEncodingParserSession: expandedParams
+ - XmlSerializerSession: addNamespaceUrisToRoot, autoDetectNamespaces,
defaultNamespace,
+ enableNamespaces, textNodeDelimiter
+ - XmlParserSession: preserveRootElement, validating
+ - HtmlSerializerSession: addKeyValueTableHeaders,
detectLabelParameters,
+ detectLinksInStrings, labelParameter, uriAnchorText
+ * Bug fixes - several serializer sessions were bypassing the session-level
addBeanTypes field by
+ overriding isAddBeanTypes() to return ctx.isAddBeanTypes() directly.
These overrides now
+ correctly delegate to the session field via super.isAddBeanTypes().
Affected classes:
+ JsonSerializerSession, UonSerializerSession, XmlSerializerSession,
HtmlSerializerSession,
+ MsgPackSerializerSession, YamlSerializerSession, CborSerializerSession,
BsonSerializerSession,
+ RdfSerializerSession, RdfStreamSerializerSession. Similarly,
ParserSession.isTrimStrings()
+ now returns the session-level field instead of delegating to the context.
+ * Example: serializer.createSession().property("locale", "fr-FR").build()
+ is equivalent to
serializer.createSession().locale(Locale.forLanguageTag("fr-FR")).build()
+ * BasicConverter handles type coercion so string values (e.g., "true",
"fr-FR") are
+ automatically converted to the expected target types.
+
** Changes
* Bump junit.version from a mix of 5.13.4 and 6.0.1 to 6.0.3.
diff --git
a/juneau-core/juneau-marshall-rdf/src/main/java/org/apache/juneau/jena/RdfSerializerSession.java
b/juneau-core/juneau-marshall-rdf/src/main/java/org/apache/juneau/jena/RdfSerializerSession.java
index a6fe3cebb3..1fef41dce7 100644
---
a/juneau-core/juneau-marshall-rdf/src/main/java/org/apache/juneau/jena/RdfSerializerSession.java
+++
b/juneau-core/juneau-marshall-rdf/src/main/java/org/apache/juneau/jena/RdfSerializerSession.java
@@ -681,17 +681,6 @@ public class RdfSerializerSession extends
WriterSerializerSession {
return bpm == null ? XmlBeanPropertyMeta.DEFAULT :
ctx.getXmlBeanPropertyMeta(bpm);
}
- /**
- * Add <js>"_type"</js> properties when needed.
- *
- * @see RdfSerializer.Builder#addBeanTypes()
- * @return
- * <jk>true</jk> if <js>"_type"</js> properties will be added to
beans if their type cannot be inferred
- * through reflection.
- */
- @Override
- protected final boolean isAddBeanTypes() { return ctx.isAddBeanTypes();
}
-
/**
* Add XSI data types to non-<c>String</c> literals.
*
diff --git
a/juneau-core/juneau-marshall-rdf/src/main/java/org/apache/juneau/jena/RdfStreamSerializerSession.java
b/juneau-core/juneau-marshall-rdf/src/main/java/org/apache/juneau/jena/RdfStreamSerializerSession.java
index b2ce29d271..b7b7466617 100644
---
a/juneau-core/juneau-marshall-rdf/src/main/java/org/apache/juneau/jena/RdfStreamSerializerSession.java
+++
b/juneau-core/juneau-marshall-rdf/src/main/java/org/apache/juneau/jena/RdfStreamSerializerSession.java
@@ -488,8 +488,4 @@ public class RdfStreamSerializerSession extends
OutputStreamSerializerSession {
RDFDataMgr.write(out.getOutputStream(), model, lang);
}
- @Override
- protected boolean isAddBeanTypes() {
- return ctx.isAddBeanTypes();
- }
}
diff --git
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/BeanTraverseSession.java
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/BeanTraverseSession.java
index 15ee784d42..5d225c549f 100644
---
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/BeanTraverseSession.java
+++
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/BeanTraverseSession.java
@@ -56,6 +56,8 @@ public class BeanTraverseSession extends BeanSession {
// Property name constants
private static final String PROP_indent = "indent";
private static final String PROP_depth = "depth";
+ private static final String PROP_initialDepth = "initialDepth";
+ private static final String PROP_BeanTraverseSession_initialDepth =
"BeanTraverseSession.initialDepth";
// Argument name constants for assertArgNotNull
private static final String ARG_ctx = "ctx";
@@ -117,10 +119,30 @@ public class BeanTraverseSession extends BeanSession {
return this;
}
+ /**
+ * Initial depth.
+ *
+ * @param value The new value for this property.
+ * @return This object.
+ */
+ public Builder initialDepth(int value) {
+ initialDepth = value;
+ return this;
+ }
+
@Override /* Overridden from Builder */
public Builder property(String key, Object value) {
- super.property(key, value);
- return this;
+ if (key == null) {
+ super.property(key, value);
+ return this;
+ }
+ switch (key) {
+ case PROP_initialDepth,
PROP_BeanTraverseSession_initialDepth:
+ return initialDepth(cvt(value,
Integer.class));
+ default:
+ super.property(key, value);
+ return this;
+ }
}
@Override /* Overridden from Builder */
diff --git
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/bson/BsonSerializerSession.java
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/bson/BsonSerializerSession.java
index e31b813cf4..379fbb6589 100644
---
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/bson/BsonSerializerSession.java
+++
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/bson/BsonSerializerSession.java
@@ -310,8 +310,4 @@ public class BsonSerializerSession extends
OutputStreamSerializerSession {
bsonOut.writeDocumentTo(out.getOutputStream());
}
- @Override
- protected boolean isAddBeanTypes() {
- return ctx.isAddBeanTypes();
- }
}
diff --git
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/cbor/CborSerializerSession.java
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/cbor/CborSerializerSession.java
index ffae0910a1..f49545f628 100644
---
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/cbor/CborSerializerSession.java
+++
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/cbor/CborSerializerSession.java
@@ -58,8 +58,6 @@ public class CborSerializerSession extends
OutputStreamSerializerSession {
*/
public static class Builder extends
OutputStreamSerializerSession.Builder {
- private CborSerializer ctx;
-
/**
* Constructor
*
@@ -68,7 +66,6 @@ public class CborSerializerSession extends
OutputStreamSerializerSession {
*/
protected Builder(CborSerializer ctx) {
super(assertArgNotNull(ARG_ctx, ctx));
- this.ctx = ctx;
}
@Override /* Overridden from Builder */
@@ -200,8 +197,6 @@ public class CborSerializerSession extends
OutputStreamSerializerSession {
return os;
}
- private final CborSerializer ctx;
-
/**
* Constructor.
*
@@ -209,7 +204,6 @@ public class CborSerializerSession extends
OutputStreamSerializerSession {
*/
protected CborSerializerSession(Builder builder) {
super(builder);
- ctx = builder.ctx;
}
/*
@@ -380,8 +374,4 @@ public class CborSerializerSession extends
OutputStreamSerializerSession {
serializeAnything(getCborOutputStream(out), o,
getExpectedRootType(o), "root", null);
}
- @Override
- protected boolean isAddBeanTypes() {
- return ctx.isAddBeanTypes();
- }
}
diff --git
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/csv/CsvSerializerSession.java
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/csv/CsvSerializerSession.java
index cdf4948748..d4e83e004b 100644
---
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/csv/CsvSerializerSession.java
+++
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/csv/CsvSerializerSession.java
@@ -56,6 +56,14 @@ import org.apache.juneau.utils.*;
})
public class CsvSerializerSession extends WriterSerializerSession {
+ // Property name constants
+ private static final String PROP_byteArrayFormat = "byteArrayFormat";
+ private static final String PROP_allowNestedStructures =
"allowNestedStructures";
+ private static final String PROP_nullValue = "nullValue";
+ private static final String PROP_CsvSerializerSession_byteArrayFormat =
"CsvSerializerSession.byteArrayFormat";
+ private static final String
PROP_CsvSerializerSession_allowNestedStructures =
"CsvSerializerSession.allowNestedStructures";
+ private static final String PROP_CsvSerializerSession_nullValue =
"CsvSerializerSession.nullValue";
+
// Argument name constants for assertArgNotNull
private static final String ARG_ctx = "ctx";
@@ -88,6 +96,17 @@ public class CsvSerializerSession extends
WriterSerializerSession {
nullValue = ctx.getNullValue();
}
+ /**
+ * Allow nested structures.
+ *
+ * @param value The new value for this property.
+ * @return This object.
+ */
+ public Builder allowNestedStructures(boolean value) {
+ allowNestedStructures = value;
+ return this;
+ }
+
@Override /* Overridden from Builder */
public <T> Builder apply(Class<T> type, Consumer<T> apply) {
super.apply(type, apply);
@@ -99,6 +118,18 @@ public class CsvSerializerSession extends
WriterSerializerSession {
return new CsvSerializerSession(this);
}
+ /**
+ * Byte array format.
+ *
+ * @param value The new value for this property.
+ * @return This object.
+ */
+ public Builder byteArrayFormat(ByteArrayFormat value) {
+ if (nn(value))
+ byteArrayFormat = value;
+ return this;
+ }
+
@Override /* Overridden from Builder */
public Builder debug(Boolean value) {
super.debug(value);
@@ -135,6 +166,17 @@ public class CsvSerializerSession extends
WriterSerializerSession {
return this;
}
+ /**
+ * Null value string.
+ *
+ * @param value The new value for this property. Can be
<jk>null</jk> (resets to default).
+ * @return This object.
+ */
+ public Builder nullValue(String value) {
+ nullValue = value;
+ return this;
+ }
+
@Override /* Overridden from Builder */
public Builder properties(Map<String,Object> value) {
super.properties(value);
@@ -143,8 +185,21 @@ public class CsvSerializerSession extends
WriterSerializerSession {
@Override /* Overridden from Builder */
public Builder property(String key, Object value) {
- super.property(key, value);
- return this;
+ if (key == null) {
+ super.property(key, value);
+ return this;
+ }
+ switch (key) {
+ case PROP_byteArrayFormat,
PROP_CsvSerializerSession_byteArrayFormat:
+ return byteArrayFormat(cvt(value,
ByteArrayFormat.class));
+ case PROP_allowNestedStructures,
PROP_CsvSerializerSession_allowNestedStructures:
+ return allowNestedStructures(cvt(value,
Boolean.class));
+ case PROP_nullValue,
PROP_CsvSerializerSession_nullValue:
+ return nullValue(cvt(value,
String.class));
+ default:
+ super.property(key, value);
+ return this;
+ }
}
@Override /* Overridden from Builder */
diff --git
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/html/HtmlSerializerSession.java
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/html/HtmlSerializerSession.java
index 310011baac..98f7603495 100644
---
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/html/HtmlSerializerSession.java
+++
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/html/HtmlSerializerSession.java
@@ -62,6 +62,18 @@ import org.apache.juneau.xml.annotation.*;
})
public class HtmlSerializerSession extends XmlSerializerSession {
+ // Property name constants
+ private static final String PROP_addKeyValueTableHeaders =
"addKeyValueTableHeaders";
+ private static final String PROP_detectLabelParameters =
"detectLabelParameters";
+ private static final String PROP_detectLinksInStrings =
"detectLinksInStrings";
+ private static final String PROP_labelParameter = "labelParameter";
+ private static final String PROP_uriAnchorText = "uriAnchorText";
+ private static final String
PROP_HtmlSerializerSession_addKeyValueTableHeaders =
"HtmlSerializerSession.addKeyValueTableHeaders";
+ private static final String
PROP_HtmlSerializerSession_detectLabelParameters =
"HtmlSerializerSession.detectLabelParameters";
+ private static final String
PROP_HtmlSerializerSession_detectLinksInStrings =
"HtmlSerializerSession.detectLinksInStrings";
+ private static final String PROP_HtmlSerializerSession_labelParameter =
"HtmlSerializerSession.labelParameter";
+ private static final String PROP_HtmlSerializerSession_uriAnchorText =
"HtmlSerializerSession.uriAnchorText";
+
// Argument name constants for assertArgNotNull
private static final String ARG_ctx = "ctx";
@@ -76,6 +88,11 @@ public class HtmlSerializerSession extends
XmlSerializerSession {
*/
public static class Builder extends XmlSerializerSession.Builder {
+ private boolean addKeyValueTableHeaders;
+ private boolean detectLabelParameters;
+ private boolean detectLinksInStrings;
+ private String labelParameter;
+ private AnchorText uriAnchorText;
private HtmlSerializer ctx;
/**
@@ -87,6 +104,11 @@ public class HtmlSerializerSession extends
XmlSerializerSession {
protected Builder(HtmlSerializer ctx) {
super(assertArgNotNull(ARG_ctx, ctx));
this.ctx = ctx;
+ addKeyValueTableHeaders =
ctx.isAddKeyValueTableHeaders();
+ detectLabelParameters = ctx.isDetectLabelParameters();
+ detectLinksInStrings = ctx.isDetectLinksInStrings();
+ labelParameter = ctx.getLabelParameter();
+ uriAnchorText = ctx.getUriAnchorText();
}
@Override /* Overridden from Builder */
@@ -142,10 +164,79 @@ public class HtmlSerializerSession extends
XmlSerializerSession {
return this;
}
+ /**
+ * Add key/value headers on bean/map tables.
+ *
+ * @param value The new value for this setting.
+ * @return This object.
+ */
+ public Builder addKeyValueTableHeaders(boolean value) {
+ addKeyValueTableHeaders = value;
+ return this;
+ }
+
+ /**
+ * Look for link labels in URIs.
+ *
+ * @param value The new value for this setting.
+ * @return This object.
+ */
+ public Builder detectLabelParameters(boolean value) {
+ detectLabelParameters = value;
+ return this;
+ }
+
+ /**
+ * Look for URLs in Strings.
+ *
+ * @param value The new value for this setting.
+ * @return This object.
+ */
+ public Builder detectLinksInStrings(boolean value) {
+ detectLinksInStrings = value;
+ return this;
+ }
+
+ /**
+ * The label parameter name.
+ *
+ * @param value The new value for this setting.
+ * @return This object.
+ */
+ public Builder labelParameter(String value) {
+ labelParameter = value;
+ return this;
+ }
+
+ /**
+ * The anchor text to use for URL objects.
+ *
+ * @param value The new value for this setting.
+ * @return This object.
+ */
+ public Builder uriAnchorText(AnchorText value) {
+ uriAnchorText = value;
+ return this;
+ }
+
@Override /* Overridden from Builder */
public Builder property(String key, Object value) {
- super.property(key, value);
- return this;
+ if (key == null) { super.property(key, value); return
this; }
+ switch (key) {
+ case PROP_addKeyValueTableHeaders,
PROP_HtmlSerializerSession_addKeyValueTableHeaders:
+ return
addKeyValueTableHeaders(cvt(value, Boolean.class));
+ case PROP_detectLabelParameters,
PROP_HtmlSerializerSession_detectLabelParameters:
+ return detectLabelParameters(cvt(value,
Boolean.class));
+ case PROP_detectLinksInStrings,
PROP_HtmlSerializerSession_detectLinksInStrings:
+ return detectLinksInStrings(cvt(value,
Boolean.class));
+ case PROP_labelParameter,
PROP_HtmlSerializerSession_labelParameter:
+ return labelParameter(cvt(value,
String.class));
+ case PROP_uriAnchorText,
PROP_HtmlSerializerSession_uriAnchorText:
+ return uriAnchorText(cvt(value,
AnchorText.class));
+ default:
+ super.property(key, value);
+ return this;
+ }
}
@Override /* Overridden from Builder */
@@ -215,6 +306,11 @@ public class HtmlSerializerSession extends
XmlSerializerSession {
}
private final HtmlSerializer ctx;
+ private final boolean addKeyValueTableHeaders;
+ private final boolean detectLabelParameters;
+ private final boolean detectLinksInStrings;
+ private final String labelParameter;
+ private final AnchorText uriAnchorText;
private final Pattern urlPattern = Pattern.compile("https?\\:\\/\\/.*");
private final Pattern labelPattern;
@@ -226,7 +322,12 @@ public class HtmlSerializerSession extends
XmlSerializerSession {
protected HtmlSerializerSession(Builder builder) {
super(builder);
ctx = builder.ctx;
- labelPattern = Pattern.compile("[\\?\\&]" +
Pattern.quote(ctx.getLabelParameter()) + "=([^\\&]*)");
+ addKeyValueTableHeaders = builder.addKeyValueTableHeaders;
+ detectLabelParameters = builder.detectLabelParameters;
+ detectLinksInStrings = builder.detectLinksInStrings;
+ labelParameter = builder.labelParameter;
+ uriAnchorText = builder.uriAnchorText;
+ labelPattern = Pattern.compile("[\\?\\&]" +
Pattern.quote(labelParameter) + "=([^\\&]*)");
}
/**
@@ -772,7 +873,7 @@ public class HtmlSerializerSession extends
XmlSerializerSession {
* @return
* The parameter name to look for when resolving link labels.
*/
- protected final String getLabelParameter() { return
ctx.getLabelParameter(); }
+ protected final String getLabelParameter() { return labelParameter; }
/**
* Anchor text source.
@@ -782,18 +883,10 @@ public class HtmlSerializerSession extends
XmlSerializerSession {
* When creating anchor tags (e.g. <code><xt><a</xt>
<xa>href</xa>=<xs>'...'</xs>
* <xt>></xt>text<xt></a></xt></code>) in HTML, this
setting defines what to set the inner text to.
*/
- protected final AnchorText getUriAnchorText() { return
ctx.getUriAnchorText(); }
+ protected final AnchorText getUriAnchorText() { return uriAnchorText; }
- /**
- * Add <js>"_type"</js> properties when needed.
- *
- * @see HtmlSerializer.Builder#addBeanTypesHtml()
- * @return
- * <jk>true</jk> if <js>"_type"</js> properties will be added to
beans if their type cannot be inferred
- * through reflection.
- */
@Override
- protected final boolean isAddBeanTypes() { return ctx.isAddBeanTypes();
}
+ public final boolean isAddBeanTypes() { return super.isAddBeanTypes(); }
/**
* Add key/value headers on bean/map tables.
@@ -802,7 +895,7 @@ public class HtmlSerializerSession extends
XmlSerializerSession {
* @return
* <jk>true</jk> if <bc>key</bc> and <bc>value</bc> column headers
are added to tables.
*/
- protected final boolean isAddKeyValueTableHeaders() { return
ctx.isAddKeyValueTableHeaders(); }
+ protected final boolean isAddKeyValueTableHeaders() { return
addKeyValueTableHeaders; }
/**
* Look for link labels in URIs.
@@ -811,7 +904,7 @@ public class HtmlSerializerSession extends
XmlSerializerSession {
* @return
* <jk>true</jk> if we should ook for URL label parameters (e.g.
<js>"?label=foobar"</js>).
*/
- protected final boolean isDetectLabelParameters() { return
ctx.isDetectLabelParameters(); }
+ protected final boolean isDetectLabelParameters() { return
detectLabelParameters; }
/**
* Look for URLs in {@link String Strings}.
@@ -820,7 +913,7 @@ public class HtmlSerializerSession extends
XmlSerializerSession {
* @return
* <jk>true</jk> if we should automatically convert strings to
URLs if they look like a URL.
*/
- protected final boolean isDetectLinksInStrings() { return
ctx.isDetectLinksInStrings(); }
+ protected final boolean isDetectLinksInStrings() { return
detectLinksInStrings; }
/**
* Serialize the specified object to the specified writer.
diff --git
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/json/JsonParserSession.java
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/json/JsonParserSession.java
index e4e06483b8..7b43efa0af 100644
---
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/json/JsonParserSession.java
+++
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/json/JsonParserSession.java
@@ -58,11 +58,16 @@ import org.apache.juneau.utils.Iso8601Utils;
})
public class JsonParserSession extends ReaderParserSession {
+ // Property name constants
+ private static final String PROP_validateEnd = "validateEnd";
+ private static final String PROP_JsonParserSession_validateEnd =
"JsonParserSession.validateEnd";
+
/**
* Builder class.
*/
public static class Builder extends ReaderParserSession.Builder {
+ private boolean validateEnd;
private JsonParser ctx;
/**
@@ -73,6 +78,7 @@ public class JsonParserSession extends ReaderParserSession {
protected Builder(JsonParser ctx) {
super(ctx);
this.ctx = ctx;
+ validateEnd = ctx.isValidateEnd();
}
@Override /* Overridden from Builder */
@@ -134,10 +140,27 @@ public class JsonParserSession extends
ReaderParserSession {
return this;
}
+ /**
+ * Validate end.
+ *
+ * @param value The new value for this setting.
+ * @return This object.
+ */
+ public Builder validateEnd(boolean value) {
+ validateEnd = value;
+ return this;
+ }
+
@Override /* Overridden from Builder */
public Builder property(String key, Object value) {
- super.property(key, value);
- return this;
+ if (key == null) { super.property(key, value); return
this; }
+ switch (key) {
+ case PROP_validateEnd,
PROP_JsonParserSession_validateEnd:
+ return validateEnd(cvt(value,
Boolean.class));
+ default:
+ super.property(key, value);
+ return this;
+ }
}
@Override /* Overridden from Builder */
@@ -190,6 +213,7 @@ public class JsonParserSession extends ReaderParserSession {
}
private final JsonParser ctx;
+ private final boolean validateEnd;
/**
* Constructor.
@@ -199,6 +223,7 @@ public class JsonParserSession extends ReaderParserSession {
protected JsonParserSession(Builder builder) {
super(builder);
ctx = builder.ctx;
+ validateEnd = builder.validateEnd;
}
@SuppressWarnings({
@@ -905,7 +930,7 @@ public class JsonParserSession extends ReaderParserSession {
* <jk>true</jk> if after parsing a POJO from the input, verifies
that the remaining input in
* the stream consists of only comments or whitespace.
*/
- protected boolean isValidateEnd() { return ctx.isValidateEnd(); }
+ protected boolean isValidateEnd() { return validateEnd; }
/**
* Returns <jk>true</jk> if the specified character is whitespace.
diff --git
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/json/JsonSerializerSession.java
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/json/JsonSerializerSession.java
index c50eda5873..51dcf9bca4 100644
---
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/json/JsonSerializerSession.java
+++
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/json/JsonSerializerSession.java
@@ -51,6 +51,10 @@ import org.apache.juneau.utils.*;
})
public class JsonSerializerSession extends WriterSerializerSession {
+ // Property name constants
+ private static final String PROP_escapeSolidus = "escapeSolidus";
+ private static final String PROP_JsonSerializerSession_escapeSolidus =
"JsonSerializerSession.escapeSolidus";
+
// Argument name constants for assertArgNotNull
private static final String ARG_ctx = "ctx";
@@ -59,6 +63,7 @@ public class JsonSerializerSession extends
WriterSerializerSession {
*/
public static class Builder extends WriterSerializerSession.Builder {
+ private boolean escapeSolidus;
private JsonSerializer ctx;
/**
@@ -70,6 +75,7 @@ public class JsonSerializerSession extends
WriterSerializerSession {
protected Builder(JsonSerializer ctx) {
super(assertArgNotNull(ARG_ctx, ctx));
this.ctx = ctx;
+ escapeSolidus = ctx.isEscapeSolidus();
}
@Override /* Overridden from Builder */
@@ -125,10 +131,27 @@ public class JsonSerializerSession extends
WriterSerializerSession {
return this;
}
+ /**
+ * Prefix solidus characters with escapes.
+ *
+ * @param value The new value for this setting.
+ * @return This object.
+ */
+ public Builder escapeSolidus(boolean value) {
+ escapeSolidus = value;
+ return this;
+ }
+
@Override /* Overridden from Builder */
public Builder property(String key, Object value) {
- super.property(key, value);
- return this;
+ if (key == null) { super.property(key, value); return
this; }
+ switch (key) {
+ case PROP_escapeSolidus,
PROP_JsonSerializerSession_escapeSolidus:
+ return escapeSolidus(cvt(value,
Boolean.class));
+ default:
+ super.property(key, value);
+ return this;
+ }
}
@Override /* Overridden from Builder */
@@ -198,6 +221,7 @@ public class JsonSerializerSession extends
WriterSerializerSession {
}
private final JsonSerializer ctx;
+ private final boolean escapeSolidus;
/**
* Constructor.
@@ -207,6 +231,7 @@ public class JsonSerializerSession extends
WriterSerializerSession {
protected JsonSerializerSession(Builder builder) {
super(builder);
this.ctx = builder.ctx;
+ escapeSolidus = builder.escapeSolidus;
}
protected SerializerWriter serializeBeanMap(JsonWriter out, BeanMap<?>
m, String typeName) throws SerializeException {
@@ -335,16 +360,8 @@ public class JsonSerializerSession extends
WriterSerializerSession {
return w;
}
- /**
- * Add <js>"_type"</js> properties when needed.
- *
- * @see JsonSerializer.Builder#addBeanTypesJson()
- * @return
- * <jk>true</jk> if <js>"_type"</js> properties will be added to
beans if their type cannot be inferred
- * through reflection.
- */
@Override
- protected final boolean isAddBeanTypes() { return ctx.isAddBeanTypes();
}
+ public final boolean isAddBeanTypes() { return super.isAddBeanTypes(); }
/**
* Prefix solidus <js>'/'</js> characters with escapes.
@@ -353,7 +370,7 @@ public class JsonSerializerSession extends
WriterSerializerSession {
* @return
* <jk>true</jk> if solidus (e.g. slash) characters should be
escaped.
*/
- protected final boolean isEscapeSolidus() { return
ctx.isEscapeSolidus(); }
+ protected final boolean isEscapeSolidus() { return escapeSolidus; }
/**
* Workhorse method.
diff --git
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/msgpack/MsgPackSerializerSession.java
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/msgpack/MsgPackSerializerSession.java
index 1aa5dcbb91..b1e680b234 100644
---
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/msgpack/MsgPackSerializerSession.java
+++
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/msgpack/MsgPackSerializerSession.java
@@ -59,8 +59,6 @@ public class MsgPackSerializerSession extends
OutputStreamSerializerSession {
*/
public static class Builder extends
OutputStreamSerializerSession.Builder {
- private MsgPackSerializer ctx;
-
/**
* Constructor
*
@@ -69,7 +67,6 @@ public class MsgPackSerializerSession extends
OutputStreamSerializerSession {
*/
protected Builder(MsgPackSerializer ctx) {
super(assertArgNotNull(ARG_ctx, ctx));
- this.ctx = ctx;
}
@Override /* Overridden from Builder */
@@ -201,8 +198,6 @@ public class MsgPackSerializerSession extends
OutputStreamSerializerSession {
return os;
}
- private final MsgPackSerializer ctx;
-
/**
* Constructor.
*
@@ -210,7 +205,6 @@ public class MsgPackSerializerSession extends
OutputStreamSerializerSession {
*/
protected MsgPackSerializerSession(Builder builder) {
super(builder);
- ctx = builder.ctx;
}
/*
@@ -391,5 +385,5 @@ public class MsgPackSerializerSession extends
OutputStreamSerializerSession {
}
@Override
- protected boolean isAddBeanTypes() { return ctx.isAddBeanTypes(); }
+ public boolean isAddBeanTypes() { return super.isAddBeanTypes(); }
}
\ No newline at end of file
diff --git
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/parser/ParserSession.java
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/parser/ParserSession.java
index d9056bbbba..da76aec9fb 100644
---
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/parser/ParserSession.java
+++
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/parser/ParserSession.java
@@ -62,9 +62,11 @@ public class ParserSession extends BeanSession {
private static final String PROP_listener = "listener";
private static final String PROP_outer = "outer";
private static final String PROP_schema = "schema";
+ private static final String PROP_trimStrings = "trimStrings";
private static final String PROP_ParserSession_javaMethod =
"ParserSession.javaMethod";
private static final String PROP_ParserSession_outer =
"ParserSession.outer";
private static final String PROP_ParserSession_schema =
"ParserSession.schema";
+ private static final String PROP_ParserSession_trimStrings =
"ParserSession.trimStrings";
// Argument name constants for assertArgNotNull
private static final String ARG_ctx = "ctx";
@@ -77,6 +79,7 @@ public class ParserSession extends BeanSession {
private HttpPartSchema schema;
private Method javaMethod;
private Object outer;
+ private boolean trimStrings;
private Parser ctx;
/**
@@ -89,6 +92,7 @@ public class ParserSession extends BeanSession {
super(assertArgNotNull(ARG_ctx, ctx).getBeanContext());
this.ctx = ctx;
mediaTypeDefault(ctx.getPrimaryMediaType());
+ trimStrings = ctx.isTrimStrings();
}
@Override /* Overridden from Builder */
@@ -172,12 +176,25 @@ public class ParserSession extends BeanSession {
return outer(value);
case PROP_schema, PROP_ParserSession_schema:
return schema(cvt(value,
HttpPartSchema.class));
+ case PROP_trimStrings,
PROP_ParserSession_trimStrings:
+ return trimStrings(cvt(value,
Boolean.class));
default:
super.property(key, value);
return this;
}
}
+ /**
+ * Trim parsed strings.
+ *
+ * @param value The new value for this setting.
+ * @return This object.
+ */
+ public Builder trimStrings(boolean value) {
+ trimStrings = value;
+ return this;
+ }
+
/**
* HTTP-part schema.
*
@@ -283,6 +300,7 @@ public class ParserSession extends BeanSession {
private final HttpPartSchema schema;
private final Method javaMethod;
private final Object outer;
+ private final boolean trimStrings;
private final Parser ctx;
private final ParserListener listener;
private final Deque<StringBuilder> sbStack;
@@ -302,6 +320,7 @@ public class ParserSession extends BeanSession {
javaMethod = builder.javaMethod;
outer = builder.outer;
schema = builder.schema;
+ trimStrings = builder.trimStrings;
listener =
BeanCreator.of(ParserListener.class).type(ctx.getListener()).orElse(null);
sbStack = new ArrayDeque<>();
}
@@ -1065,7 +1084,7 @@ public class ParserSession extends BeanSession {
* <jk>true</jk> if string values will be trimmed of whitespace
using {@link String#trim()} before being added to
* the POJO.
*/
- protected final boolean isTrimStrings() { return ctx.isTrimStrings(); }
+ protected final boolean isTrimStrings() { return trimStrings; }
/**
* Unbuffered.
@@ -1126,7 +1145,8 @@ public class ParserSession extends BeanSession {
return super.properties()
.a(PROP_javaMethod, javaMethod)
.a(PROP_listener, listener)
- .a(PROP_outer, outer);
+ .a(PROP_outer, outer)
+ .a(PROP_trimStrings, trimStrings);
}
/**
diff --git
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/serializer/SerializerSession.java
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/serializer/SerializerSession.java
index b37102ce25..a479fbd8da 100644
---
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/serializer/SerializerSession.java
+++
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/serializer/SerializerSession.java
@@ -75,10 +75,26 @@ public class SerializerSession extends BeanTraverseSession {
private static final String PROP_schema = "schema";
private static final String PROP_uriContext = "uriContext";
private static final String PROP_uriResolver = "uriResolver";
+ private static final String PROP_keepNullProperties =
"keepNullProperties";
+ private static final String PROP_trimStrings = "trimStrings";
+ private static final String PROP_addBeanTypes = "addBeanTypes";
+ private static final String PROP_addRootType = "addRootType";
+ private static final String PROP_sortCollections = "sortCollections";
+ private static final String PROP_sortMaps = "sortMaps";
+ private static final String PROP_trimEmptyCollections =
"trimEmptyCollections";
+ private static final String PROP_trimEmptyMaps = "trimEmptyMaps";
private static final String PROP_SerializerSession_javaMethod =
"SerializerSession.javaMethod";
private static final String PROP_SerializerSession_resolver =
"SerializerSession.resolver";
private static final String PROP_SerializerSession_schema =
"SerializerSession.schema";
private static final String PROP_SerializerSession_uriContext =
"SerializerSession.uriContext";
+ private static final String PROP_SerializerSession_keepNullProperties =
"SerializerSession.keepNullProperties";
+ private static final String PROP_SerializerSession_trimStrings =
"SerializerSession.trimStrings";
+ private static final String PROP_SerializerSession_addBeanTypes =
"SerializerSession.addBeanTypes";
+ private static final String PROP_SerializerSession_addRootType =
"SerializerSession.addRootType";
+ private static final String PROP_SerializerSession_sortCollections =
"SerializerSession.sortCollections";
+ private static final String PROP_SerializerSession_sortMaps =
"SerializerSession.sortMaps";
+ private static final String PROP_SerializerSession_trimEmptyCollections
= "SerializerSession.trimEmptyCollections";
+ private static final String PROP_SerializerSession_trimEmptyMaps =
"SerializerSession.trimEmptyMaps";
/**
* Builder class.
@@ -92,6 +108,14 @@ public class SerializerSession extends BeanTraverseSession {
private Serializer ctx;
private UriContext uriContext;
private VarResolverSession resolver;
+ private boolean keepNullProperties;
+ private boolean trimStrings;
+ private boolean addBeanTypes;
+ private boolean addRootType;
+ private boolean sortCollections;
+ private boolean sortMaps;
+ private boolean trimEmptyCollections;
+ private boolean trimEmptyMaps;
/**
* Constructor
@@ -104,6 +128,14 @@ public class SerializerSession extends BeanTraverseSession
{
this.ctx = ctx;
mediaTypeDefault(ctx.getResponseContentType());
uriContext = ctx.getUriContext();
+ keepNullProperties = ctx.isKeepNullProperties();
+ trimStrings = ctx.isTrimStrings();
+ addBeanTypes = ctx.isAddBeanTypes();
+ addRootType = ctx.isAddRootType();
+ sortCollections = ctx.isSortCollections();
+ sortMaps = ctx.isSortMaps();
+ trimEmptyCollections = ctx.isTrimEmptyCollections();
+ trimEmptyMaps = ctx.isTrimEmptyMaps();
}
@Override /* Overridden from Builder */
@@ -176,6 +208,22 @@ public class SerializerSession extends BeanTraverseSession
{
return schema(cvt(value,
HttpPartSchema.class));
case PROP_uriContext,
PROP_SerializerSession_uriContext:
return uriContext(cvt(value,
UriContext.class));
+ case PROP_keepNullProperties,
PROP_SerializerSession_keepNullProperties:
+ return keepNullProperties(cvt(value,
Boolean.class));
+ case PROP_trimStrings,
PROP_SerializerSession_trimStrings:
+ return trimStrings(cvt(value,
Boolean.class));
+ case PROP_addBeanTypes,
PROP_SerializerSession_addBeanTypes:
+ return addBeanTypes(cvt(value,
Boolean.class));
+ case PROP_addRootType,
PROP_SerializerSession_addRootType:
+ return addRootType(cvt(value,
Boolean.class));
+ case PROP_sortCollections,
PROP_SerializerSession_sortCollections:
+ return sortCollections(cvt(value,
Boolean.class));
+ case PROP_sortMaps,
PROP_SerializerSession_sortMaps:
+ return sortMaps(cvt(value,
Boolean.class));
+ case PROP_trimEmptyCollections,
PROP_SerializerSession_trimEmptyCollections:
+ return trimEmptyCollections(cvt(value,
Boolean.class));
+ case PROP_trimEmptyMaps,
PROP_SerializerSession_trimEmptyMaps:
+ return trimEmptyMaps(cvt(value,
Boolean.class));
default:
super.property(key, value);
return this;
@@ -267,6 +315,94 @@ public class SerializerSession extends BeanTraverseSession
{
uriContext = value;
return this;
}
+
+ /**
+ * Keep null bean property values.
+ *
+ * @param value The new value for this property.
+ * @return This object.
+ */
+ public Builder keepNullProperties(boolean value) {
+ keepNullProperties = value;
+ return this;
+ }
+
+ /**
+ * Trim strings.
+ *
+ * @param value The new value for this property.
+ * @return This object.
+ */
+ public Builder trimStrings(boolean value) {
+ trimStrings = value;
+ return this;
+ }
+
+ /**
+ * Add bean types.
+ *
+ * @param value The new value for this property.
+ * @return This object.
+ */
+ public Builder addBeanTypes(boolean value) {
+ addBeanTypes = value;
+ return this;
+ }
+
+ /**
+ * Add root type.
+ *
+ * @param value The new value for this property.
+ * @return This object.
+ */
+ public Builder addRootType(boolean value) {
+ addRootType = value;
+ return this;
+ }
+
+ /**
+ * Sort collections.
+ *
+ * @param value The new value for this property.
+ * @return This object.
+ */
+ public Builder sortCollections(boolean value) {
+ sortCollections = value;
+ return this;
+ }
+
+ /**
+ * Sort maps.
+ *
+ * @param value The new value for this property.
+ * @return This object.
+ */
+ public Builder sortMaps(boolean value) {
+ sortMaps = value;
+ return this;
+ }
+
+ /**
+ * Trim empty collections.
+ *
+ * @param value The new value for this property.
+ * @return This object.
+ */
+ public Builder trimEmptyCollections(boolean value) {
+ trimEmptyCollections = value;
+ return this;
+ }
+
+ /**
+ * Trim empty maps.
+ *
+ * @param value The new value for this property.
+ * @return This object.
+ */
+ public Builder trimEmptyMaps(boolean value) {
+ trimEmptyMaps = value;
+ return this;
+ }
}
/**
@@ -344,6 +480,14 @@ public class SerializerSession extends BeanTraverseSession
{
private final SerializerListener listener;
private final UriResolver uriResolver;
private VarResolverSession vrs;
+ private final boolean keepNullProperties;
+ private final boolean trimStrings;
+ private final boolean addBeanTypes;
+ private final boolean addRootType;
+ private final boolean sortCollections;
+ private final boolean sortMaps;
+ private final boolean trimEmptyCollections;
+ private final boolean trimEmptyMaps;
/**
* Constructor.
@@ -359,6 +503,14 @@ public class SerializerSession extends BeanTraverseSession
{
uriResolver = UriResolver.of(ctx.getUriResolution(),
ctx.getUriRelativity(), uriContext);
vrs = builder.resolver;
listener =
BeanCreator.of(SerializerListener.class).type(ctx.getListener()).orElse(null);
+ keepNullProperties = builder.keepNullProperties;
+ trimStrings = builder.trimStrings;
+ addBeanTypes = builder.addBeanTypes;
+ addRootType = builder.addRootType;
+ sortCollections = builder.sortCollections;
+ sortMaps = builder.sortMaps;
+ trimEmptyCollections = builder.trimEmptyCollections;
+ trimEmptyMaps = builder.trimEmptyMaps;
}
/**
@@ -973,7 +1125,7 @@ public class SerializerSession extends BeanTraverseSession
{
* <jk>true</jk> if <js>"_type"</js> properties added to beans if
their type cannot be inferred
* through reflection.
*/
- protected boolean isAddBeanTypes() { return ctx.isAddBeanTypes(); }
+ protected boolean isAddBeanTypes() { return addBeanTypes; }
/**
* Add type attribute to root nodes.
@@ -982,7 +1134,7 @@ public class SerializerSession extends BeanTraverseSession
{
* @return
* <jk>true</jk> if type property should be added to root node.
*/
- protected final boolean isAddRootType() { return ctx.isAddRootType(); }
+ protected final boolean isAddRootType() { return addRootType; }
/**
* Don't trim null bean property values.
@@ -991,7 +1143,7 @@ public class SerializerSession extends BeanTraverseSession
{
* @return
* <jk>true</jk> if null bean values are serialized to the output.
*/
- protected final boolean isKeepNullProperties() { return
ctx.isKeepNullProperties(); }
+ protected final boolean isKeepNullProperties() { return
keepNullProperties; }
/**
* Sort arrays and collections alphabetically.
@@ -1000,7 +1152,7 @@ public class SerializerSession extends
BeanTraverseSession {
* @return
* <jk>true</jk> if arrays and collections are copied and sorted
before serialization.
*/
- protected final boolean isSortCollections() { return
ctx.isSortCollections(); }
+ protected final boolean isSortCollections() { return sortCollections; }
/**
* Sort maps alphabetically.
@@ -1009,7 +1161,7 @@ public class SerializerSession extends
BeanTraverseSession {
* @return
* <jk>true</jk> if maps are copied and sorted before
serialization.
*/
- protected final boolean isSortMaps() { return ctx.isSortMaps(); }
+ protected final boolean isSortMaps() { return sortMaps; }
/**
* Trim empty lists and arrays.
@@ -1018,7 +1170,7 @@ public class SerializerSession extends
BeanTraverseSession {
* @return
* <jk>true</jk> if empty lists and arrays are not serialized to
the output.
*/
- protected final boolean isTrimEmptyCollections() { return
ctx.isTrimEmptyCollections(); }
+ protected final boolean isTrimEmptyCollections() { return
trimEmptyCollections; }
/**
* Trim empty maps.
@@ -1027,7 +1179,7 @@ public class SerializerSession extends
BeanTraverseSession {
* @return
* <jk>true</jk> if empty map values are not serialized to the
output.
*/
- protected final boolean isTrimEmptyMaps() { return
ctx.isTrimEmptyMaps(); }
+ protected final boolean isTrimEmptyMaps() { return trimEmptyMaps; }
/**
* Trim strings.
@@ -1036,7 +1188,7 @@ public class SerializerSession extends
BeanTraverseSession {
* @return
* <jk>true</jk> if string values will be trimmed of whitespace
using {@link String#trim()} before being serialized.
*/
- protected boolean isTrimStrings() { return ctx.isTrimStrings(); }
+ protected boolean isTrimStrings() { return trimStrings; }
/**
* Specialized warning when an exception is thrown while executing a
bean getter.
diff --git
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/serializer/WriterSerializerSession.java
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/serializer/WriterSerializerSession.java
index 4c44251c62..d653401534 100644
---
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/serializer/WriterSerializerSession.java
+++
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/serializer/WriterSerializerSession.java
@@ -59,9 +59,13 @@ public class WriterSerializerSession extends
SerializerSession {
private static final String PROP_fileCharset = "fileCharset";
private static final String PROP_streamCharset = "streamCharset";
private static final String PROP_useWhitespace = "useWhitespace";
+ private static final String PROP_maxIndent = "maxIndent";
+ private static final String PROP_quoteChar = "quoteChar";
private static final String PROP_WriterSerializerSession_fileCharset =
"WriterSerializerSession.fileCharset";
private static final String PROP_WriterSerializerSession_streamCharset
= "WriterSerializerSession.streamCharset";
private static final String PROP_WriterSerializerSession_useWhitespace
= "WriterSerializerSession.useWhitespace";
+ private static final String PROP_WriterSerializerSession_maxIndent =
"WriterSerializerSession.maxIndent";
+ private static final String PROP_WriterSerializerSession_quoteChar =
"WriterSerializerSession.quoteChar";
// Argument name constants for assertArgNotNull
private static final String ARG_ctx = "ctx";
@@ -74,7 +78,8 @@ public class WriterSerializerSession extends
SerializerSession {
private boolean useWhitespace;
private Charset fileCharset;
private Charset streamCharset;
- private WriterSerializer ctx;
+ private int maxIndent;
+ private char quoteChar;
/**
* Constructor
@@ -84,10 +89,11 @@ public class WriterSerializerSession extends
SerializerSession {
*/
protected Builder(WriterSerializer ctx) {
super(assertArgNotNull(ARG_ctx, ctx));
- this.ctx = ctx;
fileCharset = ctx.getFileCharset();
streamCharset = ctx.getStreamCharset();
useWhitespace = ctx.useWhitespace;
+ maxIndent = ctx.getMaxIndent();
+ quoteChar = ctx.getQuoteChar();
}
@Override /* Overridden from Builder */
@@ -160,6 +166,17 @@ public class WriterSerializerSession extends
SerializerSession {
return this;
}
+ /**
+ * Maximum indentation.
+ *
+ * @param value The new value for this property.
+ * @return This object.
+ */
+ public Builder maxIndent(int value) {
+ maxIndent = value;
+ return this;
+ }
+
@Override /* Overridden from Builder */
public Builder property(String key, Object value) {
if (key == null) {
@@ -173,12 +190,27 @@ public class WriterSerializerSession extends
SerializerSession {
return streamCharset(cvt(value,
Charset.class));
case PROP_useWhitespace,
PROP_WriterSerializerSession_useWhitespace:
return useWhitespace(cvt(value,
Boolean.class));
+ case PROP_maxIndent,
PROP_WriterSerializerSession_maxIndent:
+ return maxIndent(cvt(value,
Integer.class));
+ case PROP_quoteChar,
PROP_WriterSerializerSession_quoteChar:
+ return quoteChar(cvt(value,
Character.class));
default:
super.property(key, value);
return this;
}
}
+ /**
+ * Quote character.
+ *
+ * @param value The new value for this property.
+ * @return This object.
+ */
+ public Builder quoteChar(char value) {
+ quoteChar = value;
+ return this;
+ }
+
@Override /* Overridden from Builder */
public Builder resolver(VarResolverSession value) {
super.resolver(value);
@@ -273,10 +305,11 @@ public class WriterSerializerSession extends
SerializerSession {
return new Builder(assertArgNotNull(ARG_ctx, ctx));
}
- private final WriterSerializer ctx;
private final boolean useWhitespace;
private final Charset fileCharset;
private final Charset streamCharset;
+ private final int maxIndent;
+ private final char quoteChar;
/**
* Constructor.
@@ -285,10 +318,11 @@ public class WriterSerializerSession extends
SerializerSession {
*/
protected WriterSerializerSession(Builder builder) {
super(builder);
- ctx = builder.ctx;
fileCharset = builder.fileCharset;
streamCharset = builder.streamCharset;
useWhitespace = builder.useWhitespace;
+ maxIndent = builder.maxIndent;
+ quoteChar = builder.quoteChar;
}
/**
@@ -343,7 +377,7 @@ public class WriterSerializerSession extends
SerializerSession {
* @return
* The maximum indentation level in the serialized document.
*/
- protected final int getMaxIndent() { return ctx.getMaxIndent(); }
+ protected final int getMaxIndent() { return maxIndent; }
/**
* Quote character.
@@ -352,7 +386,7 @@ public class WriterSerializerSession extends
SerializerSession {
* @return
* The character used for quoting attributes and values.
*/
- protected char getQuoteChar() { return ctx.getQuoteChar(); }
+ protected char getQuoteChar() { return quoteChar; }
/**
* Use whitespace.
@@ -368,6 +402,8 @@ public class WriterSerializerSession extends
SerializerSession {
return super.properties()
.a(PROP_fileCharset, fileCharset)
.a(PROP_streamCharset, streamCharset)
- .a(PROP_useWhitespace, useWhitespace);
+ .a(PROP_useWhitespace, useWhitespace)
+ .a(PROP_maxIndent, maxIndent)
+ .a(PROP_quoteChar, quoteChar);
}
}
\ No newline at end of file
diff --git
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/uon/UonParserSession.java
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/uon/UonParserSession.java
index 39c986642c..a00fb876bb 100644
---
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/uon/UonParserSession.java
+++
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/uon/UonParserSession.java
@@ -61,6 +61,8 @@ public class UonParserSession extends ReaderParserSession
implements HttpPartPar
// Property name constants
private static final String PROP_decoding = "decoding";
+ private static final String PROP_validateEnd = "validateEnd";
+ private static final String PROP_UonParserSession_validateEnd =
"UonParserSession.validateEnd";
/**
* Builder class.
@@ -68,7 +70,7 @@ public class UonParserSession extends ReaderParserSession
implements HttpPartPar
public static class Builder extends ReaderParserSession.Builder {
private boolean decoding;
- private UonParser ctx;
+ private boolean validateEnd;
/**
* Constructor
@@ -77,8 +79,8 @@ public class UonParserSession extends ReaderParserSession
implements HttpPartPar
*/
protected Builder(UonParser ctx) {
super(ctx);
- this.ctx = ctx;
decoding = ctx.decoding;
+ validateEnd = ctx.isValidateEnd();
}
@Override /* Overridden from Builder */
@@ -153,7 +155,26 @@ public class UonParserSession extends ReaderParserSession
implements HttpPartPar
@Override /* Overridden from Builder */
public Builder property(String key, Object value) {
- super.property(key, value);
+ if (key == null) { super.property(key, value); return
this; }
+ switch (key) {
+ case PROP_decoding:
+ return decoding(cvt(value,
Boolean.class));
+ case PROP_validateEnd,
PROP_UonParserSession_validateEnd:
+ return validateEnd(cvt(value,
Boolean.class));
+ default:
+ super.property(key, value);
+ return this;
+ }
+ }
+
+ /**
+ * Validate end.
+ *
+ * @param value The new value for this setting.
+ * @return This object.
+ */
+ public Builder validateEnd(boolean value) {
+ validateEnd = value;
return this;
}
@@ -236,9 +257,8 @@ public class UonParserSession extends ReaderParserSession
implements HttpPartPar
}
}
- private final UonParser ctx;
-
private final boolean decoding;
+ private final boolean validateEnd;
/**
* Constructor.
@@ -247,8 +267,8 @@ public class UonParserSession extends ReaderParserSession
implements HttpPartPar
*/
protected UonParserSession(Builder builder) {
super(builder);
- ctx = builder.ctx;
decoding = builder.decoding;
+ validateEnd = builder.validateEnd;
}
/**
@@ -870,7 +890,7 @@ public class UonParserSession extends ReaderParserSession
implements HttpPartPar
* <jk>true</jk> if after parsing a POJO from the input, verifies
that the remaining input in
* the stream consists of only comments or whitespace.
*/
- protected final boolean isValidateEnd() { return ctx.isValidateEnd(); }
+ protected final boolean isValidateEnd() { return validateEnd; }
/**
* Convenience method for parsing an attribute from the specified
parser.
@@ -992,6 +1012,7 @@ public class UonParserSession extends ReaderParserSession
implements HttpPartPar
@Override /* Overridden from ReaderParserSession */
protected FluentMap<String,Object> properties() {
return super.properties()
- .a(PROP_decoding, decoding);
+ .a(PROP_decoding, decoding)
+ .a(PROP_validateEnd, validateEnd);
}
}
\ No newline at end of file
diff --git
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/uon/UonSerializerSession.java
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/uon/UonSerializerSession.java
index d8d6b879e3..89a3df235d 100644
---
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/uon/UonSerializerSession.java
+++
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/uon/UonSerializerSession.java
@@ -54,6 +54,12 @@ import org.apache.juneau.utils.*;
})
public class UonSerializerSession extends WriterSerializerSession implements
HttpPartSerializerSession {
+ // Property name constants
+ private static final String PROP_encoding = "encoding";
+ private static final String PROP_paramFormat = "paramFormat";
+ private static final String PROP_UonSerializerSession_encoding =
"UonSerializerSession.encoding";
+ private static final String PROP_UonSerializerSession_paramFormat =
"UonSerializerSession.paramFormat";
+
// Argument name constants for assertArgNotNull
private static final String ARG_ctx = "ctx";
@@ -62,7 +68,8 @@ public class UonSerializerSession extends
WriterSerializerSession implements Htt
*/
public static class Builder extends WriterSerializerSession.Builder {
- private UonSerializer ctx;
+ private boolean encoding;
+ private ParamFormat paramFormat;
/**
* Constructor
@@ -72,7 +79,8 @@ public class UonSerializerSession extends
WriterSerializerSession implements Htt
*/
protected Builder(UonSerializer ctx) {
super(assertArgNotNull(ARG_ctx, ctx));
- this.ctx = ctx;
+ encoding = ctx.isEncoding();
+ paramFormat = ctx.getParamFormat();
}
@Override /* Overridden from Builder */
@@ -128,10 +136,40 @@ public class UonSerializerSession extends
WriterSerializerSession implements Htt
return this;
}
+ /**
+ * Encode non-valid URI characters.
+ *
+ * @param value The new value for this setting.
+ * @return This object.
+ */
+ public Builder encoding(boolean value) {
+ encoding = value;
+ return this;
+ }
+
+ /**
+ * Format to use for query/form-data/header values.
+ *
+ * @param value The new value for this setting.
+ * @return This object.
+ */
+ public Builder paramFormat(ParamFormat value) {
+ paramFormat = value;
+ return this;
+ }
+
@Override /* Overridden from Builder */
public Builder property(String key, Object value) {
- super.property(key, value);
- return this;
+ if (key == null) { super.property(key, value); return
this; }
+ switch (key) {
+ case PROP_encoding,
PROP_UonSerializerSession_encoding:
+ return encoding(cvt(value,
Boolean.class));
+ case PROP_paramFormat,
PROP_UonSerializerSession_paramFormat:
+ return paramFormat(cvt(value,
ParamFormat.class));
+ default:
+ super.property(key, value);
+ return this;
+ }
}
@Override /* Overridden from Builder */
@@ -200,7 +238,8 @@ public class UonSerializerSession extends
WriterSerializerSession implements Htt
return new Builder(assertArgNotNull(ARG_ctx, ctx));
}
- private final UonSerializer ctx;
+ private final boolean encoding;
+ private final ParamFormat paramFormat;
private final boolean plainTextParams;
/**
@@ -210,8 +249,9 @@ public class UonSerializerSession extends
WriterSerializerSession implements Htt
*/
public UonSerializerSession(Builder builder) {
super(builder);
- ctx = builder.ctx;
- plainTextParams = ctx.getParamFormat() == ParamFormat.PLAINTEXT;
+ encoding = builder.encoding;
+ paramFormat = builder.paramFormat;
+ plainTextParams = paramFormat == ParamFormat.PLAINTEXT;
}
@Override /* Overridden from HttpPartSerializer */
@@ -365,17 +405,7 @@ public class UonSerializerSession extends
WriterSerializerSession implements Htt
* @return
* Specifies the format to use for URL GET parameter keys and
values.
*/
- protected final ParamFormat getParamFormat() { return
ctx.getParamFormat(); }
-
- /**
- * Quote character.
- *
- * @see UonSerializer.Builder#quoteCharUon(char)
- * @return
- * The character used for quoting attributes and values.
- */
- @Override
- protected final char getQuoteChar() { return ctx.getQuoteChar(); }
+ protected final ParamFormat getParamFormat() { return paramFormat; }
/**
* Converts the specified output target object to an {@link UonWriter}.
@@ -393,16 +423,8 @@ public class UonSerializerSession extends
WriterSerializerSession implements Htt
return w;
}
- /**
- * Add <js>"_type"</js> properties when needed.
- *
- * @see UonSerializer.Builder#addBeanTypesUon()
- * @return
- * <jk>true</jk> if <js>"_type"</js> properties will be added to
beans if their type cannot be inferred
- * through reflection.
- */
@Override
- protected final boolean isAddBeanTypes() { return ctx.isAddBeanTypes();
}
+ public final boolean isAddBeanTypes() { return super.isAddBeanTypes(); }
/**
* Encode non-valid URI characters.
@@ -411,7 +433,7 @@ public class UonSerializerSession extends
WriterSerializerSession implements Htt
* @return
* <jk>true</jk> if non-valid URI characters should be encoded
with <js>"%xx"</js> constructs.
*/
- protected final boolean isEncoding() { return ctx.isEncoding(); }
+ protected final boolean isEncoding() { return encoding; }
/**
* Workhorse method.
diff --git
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/urlencoding/UrlEncodingParserSession.java
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/urlencoding/UrlEncodingParserSession.java
index 231532f529..972fef9485 100644
---
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/urlencoding/UrlEncodingParserSession.java
+++
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/urlencoding/UrlEncodingParserSession.java
@@ -56,11 +56,16 @@ public class UrlEncodingParserSession extends
UonParserSession {
private static final String CONST_value = "_value";
+ // Property name constants
+ private static final String PROP_expandedParams = "expandedParams";
+ private static final String
PROP_UrlEncodingParserSession_expandedParams =
"UrlEncodingParserSession.expandedParams";
+
/**
* Builder class.
*/
public static class Builder extends UonParserSession.Builder {
+ private boolean expandedParams;
private UrlEncodingParser ctx;
/**
@@ -71,6 +76,7 @@ public class UrlEncodingParserSession extends
UonParserSession {
protected Builder(UrlEncodingParser ctx) {
super(ctx);
this.ctx = ctx;
+ expandedParams = ctx.isExpandedParams();
}
@Override /* Overridden from Builder */
@@ -138,10 +144,27 @@ public class UrlEncodingParserSession extends
UonParserSession {
return this;
}
+ /**
+ * Serialize bean property collections/arrays as separate
key/value pairs.
+ *
+ * @param value The new value for this setting.
+ * @return This object.
+ */
+ public Builder expandedParams(boolean value) {
+ expandedParams = value;
+ return this;
+ }
+
@Override /* Overridden from Builder */
public Builder property(String key, Object value) {
- super.property(key, value);
- return this;
+ if (key == null) { super.property(key, value); return
this; }
+ switch (key) {
+ case PROP_expandedParams,
PROP_UrlEncodingParserSession_expandedParams:
+ return expandedParams(cvt(value,
Boolean.class));
+ default:
+ super.property(key, value);
+ return this;
+ }
}
@Override /* Overridden from Builder */
@@ -192,6 +215,7 @@ public class UrlEncodingParserSession extends
UonParserSession {
}
private final UrlEncodingParser ctx;
+ private final boolean expandedParams;
/**
* Constructor.
@@ -201,6 +225,7 @@ public class UrlEncodingParserSession extends
UonParserSession {
public UrlEncodingParserSession(Builder builder) {
super(builder);
ctx = builder.ctx;
+ expandedParams = builder.expandedParams;
}
/**
@@ -572,5 +597,5 @@ public class UrlEncodingParserSession extends
UonParserSession {
* <jk>false</jk> if serializing the array <c>[1,2,3]</c> results in
<c>?key=$a(1,2,3)</c>.
* <br><jk>true</jk> if serializing the same array results in
<c>?key=1&key=2&key=3</c>.
*/
- protected final boolean isExpandedParams() { return
ctx.isExpandedParams(); }
+ protected final boolean isExpandedParams() { return expandedParams; }
}
\ No newline at end of file
diff --git
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/urlencoding/UrlEncodingSerializerSession.java
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/urlencoding/UrlEncodingSerializerSession.java
index fd89a59fec..fe7b9c37b1 100644
---
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/urlencoding/UrlEncodingSerializerSession.java
+++
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/urlencoding/UrlEncodingSerializerSession.java
@@ -51,11 +51,16 @@ import org.apache.juneau.uon.*;
})
public class UrlEncodingSerializerSession extends UonSerializerSession {
+ // Property name constants
+ private static final String PROP_expandedParams = "expandedParams";
+ private static final String
PROP_UrlEncodingSerializerSession_expandedParams =
"UrlEncodingSerializerSession.expandedParams";
+
/**
* Builder class.
*/
public static class Builder extends UonSerializerSession.Builder {
+ private boolean expandedParams;
private UrlEncodingSerializer ctx;
/**
@@ -66,6 +71,7 @@ public class UrlEncodingSerializerSession extends
UonSerializerSession {
protected Builder(UrlEncodingSerializer ctx) {
super(ctx);
this.ctx = ctx;
+ expandedParams = ctx.isExpandedParams();
}
@Override /* Overridden from Builder */
@@ -121,10 +127,27 @@ public class UrlEncodingSerializerSession extends
UonSerializerSession {
return this;
}
+ /**
+ * Serialize bean property collections/arrays as separate
key/value pairs.
+ *
+ * @param value The new value for this setting.
+ * @return This object.
+ */
+ public Builder expandedParams(boolean value) {
+ expandedParams = value;
+ return this;
+ }
+
@Override /* Overridden from Builder */
public Builder property(String key, Object value) {
- super.property(key, value);
- return this;
+ if (key == null) { super.property(key, value); return
this; }
+ switch (key) {
+ case PROP_expandedParams,
PROP_UrlEncodingSerializerSession_expandedParams:
+ return expandedParams(cvt(value,
Boolean.class));
+ default:
+ super.property(key, value);
+ return this;
+ }
}
@Override /* Overridden from Builder */
@@ -213,6 +236,7 @@ public class UrlEncodingSerializerSession extends
UonSerializerSession {
}
private final UrlEncodingSerializer ctx;
+ private final boolean expandedParams;
/**
* Constructor.
@@ -222,6 +246,7 @@ public class UrlEncodingSerializerSession extends
UonSerializerSession {
protected UrlEncodingSerializerSession(Builder builder) {
super(builder);
ctx = builder.ctx;
+ expandedParams = builder.expandedParams;
}
/*
@@ -441,5 +466,5 @@ public class UrlEncodingSerializerSession extends
UonSerializerSession {
* <jk>false</jk> if serializing the array <c>[1,2,3]</c> results
in <c>?key=$a(1,2,3)</c>.
* <br><jk>true</jk> if serializing the same array results in
<c>?key=1&key=2&key=3</c>.
*/
- protected final boolean isExpandedParams() { return
ctx.isExpandedParams(); }
+ protected final boolean isExpandedParams() { return expandedParams; }
}
\ No newline at end of file
diff --git
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/xml/XmlParserSession.java
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/xml/XmlParserSession.java
index 25d1f0ada0..d9f583e21a 100644
---
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/xml/XmlParserSession.java
+++
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/xml/XmlParserSession.java
@@ -58,11 +58,19 @@ import org.apache.juneau.utils.Iso8601Utils;
})
public class XmlParserSession extends ReaderParserSession {
+ // Property name constants
+ private static final String PROP_preserveRootElement =
"preserveRootElement";
+ private static final String PROP_validating = "validating";
+ private static final String PROP_XmlParserSession_preserveRootElement =
"XmlParserSession.preserveRootElement";
+ private static final String PROP_XmlParserSession_validating =
"XmlParserSession.validating";
+
/**
* Builder class.
*/
public static class Builder extends ReaderParserSession.Builder {
+ private boolean preserveRootElement;
+ private boolean validating;
private XmlParser ctx;
/**
@@ -73,6 +81,8 @@ public class XmlParserSession extends ReaderParserSession {
protected Builder(XmlParser ctx) {
super(ctx);
this.ctx = ctx;
+ preserveRootElement = ctx.isPreserveRootElement();
+ validating = ctx.isValidating();
}
@Override /* Overridden from Builder */
@@ -134,10 +144,40 @@ public class XmlParserSession extends ReaderParserSession
{
return this;
}
+ /**
+ * Preserve root element during XML parsing.
+ *
+ * @param value The new value for this setting.
+ * @return This object.
+ */
+ public Builder preserveRootElement(boolean value) {
+ preserveRootElement = value;
+ return this;
+ }
+
+ /**
+ * Validate XML during parsing.
+ *
+ * @param value The new value for this setting.
+ * @return This object.
+ */
+ public Builder validating(boolean value) {
+ validating = value;
+ return this;
+ }
+
@Override /* Overridden from Builder */
public Builder property(String key, Object value) {
- super.property(key, value);
- return this;
+ if (key == null) { super.property(key, value); return
this; }
+ switch (key) {
+ case PROP_preserveRootElement,
PROP_XmlParserSession_preserveRootElement:
+ return preserveRootElement(cvt(value,
Boolean.class));
+ case PROP_validating,
PROP_XmlParserSession_validating:
+ return validating(cvt(value,
Boolean.class));
+ default:
+ super.property(key, value);
+ return this;
+ }
}
@Override /* Overridden from Builder */
@@ -217,6 +257,8 @@ public class XmlParserSession extends ReaderParserSession {
}
private final XmlParser ctx;
+ private final boolean preserveRootElement;
+ private final boolean validating;
private final StringBuilder rsb = new StringBuilder(); // Reusable
string builder used in this class.
@@ -228,6 +270,8 @@ public class XmlParserSession extends ReaderParserSession {
protected XmlParserSession(Builder builder) {
super(builder);
ctx = builder.ctx;
+ preserveRootElement = builder.preserveRootElement;
+ validating = builder.validating;
}
/*
@@ -744,7 +788,7 @@ public class XmlParserSession extends ReaderParserSession {
* <jk>true</jk> if when parsing into a generic {@link JsonMap},
the map will contain a single entry whose key
* is the root element name.
*/
- protected final boolean isPreserveRootElement() { return
ctx.isPreserveRootElement(); }
+ protected final boolean isPreserveRootElement() { return
preserveRootElement; }
/**
* Enable validation.
@@ -753,7 +797,7 @@ public class XmlParserSession extends ReaderParserSession {
* @return
* <jk>true</jk> if XML document will be validated.
*/
- protected final boolean isValidating() { return ctx.isValidating(); }
+ protected final boolean isValidating() { return validating; }
/**
* Returns <jk>true</jk> if the current element is a whitespace element.
diff --git
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/xml/XmlSerializerSession.java
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/xml/XmlSerializerSession.java
index aefab5e43a..d6c5894dec 100644
---
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/xml/XmlSerializerSession.java
+++
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/xml/XmlSerializerSession.java
@@ -57,6 +57,18 @@ import org.apache.juneau.xml.annotation.*;
})
public class XmlSerializerSession extends WriterSerializerSession {
+ // Property name constants
+ private static final String PROP_addNamespaceUrisToRoot =
"addNamespaceUrisToRoot";
+ private static final String PROP_autoDetectNamespaces =
"autoDetectNamespaces";
+ private static final String PROP_defaultNamespace = "defaultNamespace";
+ private static final String PROP_enableNamespaces = "enableNamespaces";
+ private static final String PROP_textNodeDelimiter =
"textNodeDelimiter";
+ private static final String
PROP_XmlSerializerSession_addNamespaceUrisToRoot =
"XmlSerializerSession.addNamespaceUrisToRoot";
+ private static final String
PROP_XmlSerializerSession_autoDetectNamespaces =
"XmlSerializerSession.autoDetectNamespaces";
+ private static final String PROP_XmlSerializerSession_defaultNamespace
= "XmlSerializerSession.defaultNamespace";
+ private static final String PROP_XmlSerializerSession_enableNamespaces
= "XmlSerializerSession.enableNamespaces";
+ private static final String PROP_XmlSerializerSession_textNodeDelimiter
= "XmlSerializerSession.textNodeDelimiter";
+
// Argument name constants for assertArgNotNull
private static final String ARG_ctx = "ctx";
@@ -65,6 +77,11 @@ public class XmlSerializerSession extends
WriterSerializerSession {
*/
public static class Builder extends WriterSerializerSession.Builder {
+ private boolean addNamespaceUrisToRoot;
+ private boolean autoDetectNamespaces;
+ private String defaultNamespace;
+ private boolean enableNamespaces;
+ private String textNodeDelimiter;
private XmlSerializer ctx;
/**
@@ -76,6 +93,11 @@ public class XmlSerializerSession extends
WriterSerializerSession {
protected Builder(XmlSerializer ctx) {
super(assertArgNotNull(ARG_ctx, ctx));
this.ctx = ctx;
+ addNamespaceUrisToRoot = ctx.isAddNamespaceUrlsToRoot();
+ autoDetectNamespaces = ctx.isAutoDetectNamespaces();
+ defaultNamespace = ctx.getDefaultNamespace() == null ?
null : ctx.getDefaultNamespace().toString();
+ enableNamespaces = ctx.isEnableNamespaces();
+ textNodeDelimiter = ctx.getTextNodeDelimiter();
}
@Override /* Overridden from Builder */
@@ -131,10 +153,79 @@ public class XmlSerializerSession extends
WriterSerializerSession {
return this;
}
+ /**
+ * Add namespace URLs to the root element.
+ *
+ * @param value The new value for this setting.
+ * @return This object.
+ */
+ public Builder addNamespaceUrisToRoot(boolean value) {
+ addNamespaceUrisToRoot = value;
+ return this;
+ }
+
+ /**
+ * Auto-detect namespace usage.
+ *
+ * @param value The new value for this setting.
+ * @return This object.
+ */
+ public Builder autoDetectNamespaces(boolean value) {
+ autoDetectNamespaces = value;
+ return this;
+ }
+
+ /**
+ * Default namespace.
+ *
+ * @param value The new value for this setting.
+ * @return This object.
+ */
+ public Builder defaultNamespace(String value) {
+ defaultNamespace = value;
+ return this;
+ }
+
+ /**
+ * Enable support for XML namespaces.
+ *
+ * @param value The new value for this setting.
+ * @return This object.
+ */
+ public Builder enableNamespaces(boolean value) {
+ enableNamespaces = value;
+ return this;
+ }
+
+ /**
+ * Text node delimiter.
+ *
+ * @param value The new value for this setting.
+ * @return This object.
+ */
+ public Builder textNodeDelimiter(String value) {
+ textNodeDelimiter = value == null ? "" : value;
+ return this;
+ }
+
@Override /* Overridden from Builder */
public Builder property(String key, Object value) {
- super.property(key, value);
- return this;
+ if (key == null) { super.property(key, value); return
this; }
+ switch (key) {
+ case PROP_addNamespaceUrisToRoot,
PROP_XmlSerializerSession_addNamespaceUrisToRoot:
+ return
addNamespaceUrisToRoot(cvt(value, Boolean.class));
+ case PROP_autoDetectNamespaces,
PROP_XmlSerializerSession_autoDetectNamespaces:
+ return autoDetectNamespaces(cvt(value,
Boolean.class));
+ case PROP_defaultNamespace,
PROP_XmlSerializerSession_defaultNamespace:
+ return defaultNamespace(cvt(value,
String.class));
+ case PROP_enableNamespaces,
PROP_XmlSerializerSession_enableNamespaces:
+ return enableNamespaces(cvt(value,
Boolean.class));
+ case PROP_textNodeDelimiter,
PROP_XmlSerializerSession_textNodeDelimiter:
+ return textNodeDelimiter(cvt(value,
String.class));
+ default:
+ super.property(key, value);
+ return this;
+ }
}
@Override /* Overridden from Builder */
@@ -245,6 +336,9 @@ public class XmlSerializerSession extends
WriterSerializerSession {
}
private final String textNodeDelimiter;
+ private final boolean addNamespaceUrisToRoot;
+ private final boolean autoDetectNamespaces;
+ private final boolean enableNamespaces;
private final XmlSerializer ctx;
private Namespace defaultNamespace;
private List<Namespace> namespaces = new ArrayList<>();
@@ -257,10 +351,15 @@ public class XmlSerializerSession extends
WriterSerializerSession {
protected XmlSerializerSession(Builder builder) {
super(builder);
ctx = builder.ctx;
- defaultNamespace =
findDefaultNamespace(ctx.getDefaultNamespace());
+ addNamespaceUrisToRoot = builder.addNamespaceUrisToRoot;
+ autoDetectNamespaces = builder.autoDetectNamespaces;
+ enableNamespaces = builder.enableNamespaces;
+ textNodeDelimiter = builder.textNodeDelimiter;
+ defaultNamespace = findDefaultNamespace(
+ builder.defaultNamespace != null ?
Namespace.create(builder.defaultNamespace) : ctx.getDefaultNamespace()
+ );
var ctxNamespaces = ctx.getNamespaces();
namespaces = ctxNamespaces == null ? new ArrayList<>() : new
ArrayList<>(ctxNamespaces);
- textNodeDelimiter = ctx.getTextNodeDelimiter();
}
/**
@@ -726,16 +825,8 @@ public class XmlSerializerSession extends
WriterSerializerSession {
*/
protected final List<Namespace> getNamespaces() { return namespaces ==
null ? l() : namespaces; }
- /**
- * Add <js>"_type"</js> properties when needed.
- *
- * @see XmlSerializer.Builder#addBeanTypesXml()
- * @return
- * <jk>true</jk> if<js>"_type"</js> properties will be added to
beans if their type cannot be inferred
- * through reflection.
- */
@Override
- protected boolean isAddBeanTypes() { return ctx.isAddBeanTypes(); }
+ public boolean isAddBeanTypes() { return super.isAddBeanTypes(); }
/**
* Add JSON type tags.
@@ -753,7 +844,7 @@ public class XmlSerializerSession extends
WriterSerializerSession {
* @return
* <jk>true</jk> if {@code xmlns:x} attributes are added to the
root element for the default and all mapped namespaces.
*/
- protected final boolean isAddNamespaceUrisToRoot() { return
ctx.isAddNamespaceUrlsToRoot(); }
+ protected final boolean isAddNamespaceUrisToRoot() { return
addNamespaceUrisToRoot; }
/**
* Auto-detect namespace usage.
@@ -762,7 +853,7 @@ public class XmlSerializerSession extends
WriterSerializerSession {
* @return
* <jk>true</jk> if namespace usage is detected before
serialization.
*/
- protected final boolean isAutoDetectNamespaces() { return
ctx.isAutoDetectNamespaces(); }
+ protected final boolean isAutoDetectNamespaces() { return
autoDetectNamespaces; }
/**
* Enable support for XML namespaces.
@@ -771,7 +862,7 @@ public class XmlSerializerSession extends
WriterSerializerSession {
* @return
* <jk>false</jk> if XML output will not contain any namespaces
regardless of any other settings.
*/
- protected final boolean isEnableNamespaces() { return
ctx.isEnableNamespaces(); }
+ protected final boolean isEnableNamespaces() { return enableNamespaces;
}
/**
* Returns <jk>true</jk> if we're serializing HTML.
diff --git
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/yaml/YamlSerializerSession.java
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/yaml/YamlSerializerSession.java
index bd9ea06ae7..ab141aa620 100644
---
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/yaml/YamlSerializerSession.java
+++
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/yaml/YamlSerializerSession.java
@@ -58,8 +58,6 @@ public class YamlSerializerSession extends
WriterSerializerSession {
*/
public static class Builder extends WriterSerializerSession.Builder {
- private YamlSerializer ctx;
-
/**
* Constructor
*
@@ -68,7 +66,6 @@ public class YamlSerializerSession extends
WriterSerializerSession {
*/
protected Builder(YamlSerializer ctx) {
super(assertArgNotNull(ARG_ctx, ctx));
- this.ctx = ctx;
}
@Override /* Overridden from Builder */
@@ -196,8 +193,6 @@ public class YamlSerializerSession extends
WriterSerializerSession {
return new Builder(assertArgNotNull(ARG_ctx, ctx));
}
- private final YamlSerializer ctx;
-
/**
* Constructor.
*
@@ -205,7 +200,6 @@ public class YamlSerializerSession extends
WriterSerializerSession {
*/
protected YamlSerializerSession(Builder builder) {
super(builder);
- this.ctx = builder.ctx;
}
@Override /* Overridden from SerializerSession */
@@ -441,13 +435,4 @@ public class YamlSerializerSession extends
WriterSerializerSession {
return out;
}
- /**
- * Add <js>"_type"</js> properties when needed.
- *
- * @return
- * <jk>true</jk> if <js>"_type"</js> properties will be added to
beans if their type cannot be inferred
- * through reflection.
- */
- @Override
- protected final boolean isAddBeanTypes() { return ctx.isAddBeanTypes();
}
}
diff --git
a/juneau-utest/src/test/java/org/apache/juneau/ContextSession_Test.java
b/juneau-utest/src/test/java/org/apache/juneau/ContextSession_Test.java
index d6dfeb45c5..71c4cf0d0c 100644
--- a/juneau-utest/src/test/java/org/apache/juneau/ContextSession_Test.java
+++ b/juneau-utest/src/test/java/org/apache/juneau/ContextSession_Test.java
@@ -22,9 +22,15 @@ import java.nio.charset.*;
import java.util.*;
import org.apache.juneau.collections.*;
+import org.apache.juneau.csv.*;
+import org.apache.juneau.html.*;
import org.apache.juneau.json.*;
+import org.apache.juneau.json5.*;
import org.apache.juneau.parser.*;
import org.apache.juneau.serializer.*;
+import org.apache.juneau.uon.*;
+import org.apache.juneau.urlencoding.*;
+import org.apache.juneau.xml.*;
import org.junit.jupiter.api.*;
class ContextSession_Test extends TestBase {
@@ -140,6 +146,21 @@ class ContextSession_Test extends TestBase {
@Nested class E_propertyDispatch extends TestBase {
+ public static class BeanWithNullField {
+ public String a = null;
+ public int b = 1;
+ }
+
+ public static class BeanWithEmptyCollection {
+ public String[] a = new String[0];
+ public int b = 1;
+ }
+
+ public static class BeanWithEmptyMap {
+ public Map<String,Object> a = new LinkedHashMap<>();
+ public int b = 1;
+ }
+
// -- ContextSession: debug --
@Test void e01_debug_shortForm() {
@@ -296,6 +317,297 @@ class ContextSession_Test extends TestBase {
.build();
assertEquals(Locale.forLanguageTag("ja-JP"),
session.getLocale());
}
+
+ // -- BeanTraverseSession: initialDepth --
+
+ @Test void e20_beanTraverse_initialDepth_shortForm() {
+ var session = (BeanTraverseSession)
JsonSerializer.DEFAULT.createSession()
+ .property("initialDepth", 3)
+ .build();
+ assertEquals(3, session.indent);
+ }
+
+ @Test void e21_beanTraverse_initialDepth_qualifiedForm() {
+ var session = (BeanTraverseSession)
JsonSerializer.DEFAULT.createSession()
+ .property("BeanTraverseSession.initialDepth",
"5")
+ .build();
+ assertEquals(5, session.indent);
+ }
+
+ // -- SerializerSession: trimStrings --
+
+ @Test void e22_serializer_trimStrings_shortForm() throws
Exception {
+ var session = (WriterSerializerSession)
JsonSerializer.DEFAULT.createSession()
+ .property("trimStrings", true)
+ .build();
+ assertEquals("\"hello\"", session.serialize(" hello
"));
+ }
+
+ @Test void e23_serializer_trimStrings_qualifiedForm() throws
Exception {
+ var session = (WriterSerializerSession)
JsonSerializer.DEFAULT.createSession()
+ .property("SerializerSession.trimStrings",
"true")
+ .build();
+ assertEquals("\"hello\"", session.serialize(" hello
"));
+ }
+
+ // -- SerializerSession: keepNullProperties --
+
+ @Test void e24_serializer_keepNullProperties_true() throws
Exception {
+ var session = (WriterSerializerSession)
JsonSerializer.DEFAULT.createSession()
+ .property("keepNullProperties", true)
+ .build();
+ var result = session.serialize(new BeanWithNullField());
+ assertTrue(result.contains("\"a\""));
+ }
+
+ @Test void e25_serializer_keepNullProperties_false() throws
Exception {
+ var session = (WriterSerializerSession)
JsonSerializer.DEFAULT.createSession()
+
.property("SerializerSession.keepNullProperties", "false")
+ .build();
+ var result = session.serialize(new BeanWithNullField());
+ assertFalse(result.contains("\"a\""));
+ }
+
+ // -- SerializerSession: sortCollections --
+
+ @Test void e26_serializer_sortCollections() throws Exception {
+ var session = (WriterSerializerSession)
JsonSerializer.DEFAULT.createSession()
+ .property("sortCollections", true)
+ .build();
+ var result = session.serialize(new String[]{"c", "a",
"b"});
+ assertEquals("[\"a\",\"b\",\"c\"]", result);
+ }
+
+ // -- SerializerSession: sortMaps --
+
+ @Test void e27_serializer_sortMaps() throws Exception {
+ var session = (WriterSerializerSession)
JsonSerializer.DEFAULT.createSession()
+ .property("SerializerSession.sortMaps", "true")
+ .build();
+ var m = new LinkedHashMap<String,Integer>();
+ m.put("c", 3);
+ m.put("a", 1);
+ m.put("b", 2);
+ var result = session.serialize(m);
+ assertEquals("{\"a\":1,\"b\":2,\"c\":3}", result);
+ }
+
+ // -- SerializerSession: trimEmptyCollections --
+
+ @Test void e28_serializer_trimEmptyCollections() throws
Exception {
+ var session = (WriterSerializerSession)
JsonSerializer.DEFAULT.createSession()
+ .property("trimEmptyCollections", true)
+ .build();
+ var result = session.serialize(new
BeanWithEmptyCollection());
+ assertFalse(result.contains("\"a\""));
+ assertTrue(result.contains("\"b\""));
+ }
+
+ // -- SerializerSession: trimEmptyMaps --
+
+ @Test void e29_serializer_trimEmptyMaps() throws Exception {
+ var session = (WriterSerializerSession)
JsonSerializer.DEFAULT.createSession()
+ .property("trimEmptyMaps", true)
+ .build();
+ var result = session.serialize(new BeanWithEmptyMap());
+ assertFalse(result.contains("\"a\""));
+ assertTrue(result.contains("\"b\""));
+ }
+
+ // -- WriterSerializerSession: maxIndent --
+
+ @Test void e30_writerSerializer_maxIndent_shortForm() throws
Exception {
+ var ctx =
JsonSerializer.create().useWhitespace().build();
+ var noLimitSession = (WriterSerializerSession)
ctx.createSession().build();
+ var limitedSession = (WriterSerializerSession)
ctx.createSession()
+ .property("maxIndent", 0)
+ .build();
+ // With maxIndent=0, output should have no leading
spaces on values
+ var unlimited =
noLimitSession.serialize(JsonMap.of("a", 1));
+ var limited = limitedSession.serialize(JsonMap.of("a",
1));
+ assertTrue(unlimited.contains("\t"));
+ assertFalse(limited.contains("\t"));
+ }
+
+ @Test void e31_writerSerializer_maxIndent_qualifiedForm()
throws Exception {
+ var ctx =
JsonSerializer.create().useWhitespace().build();
+ var session = (WriterSerializerSession)
ctx.createSession()
+ .property("WriterSerializerSession.maxIndent",
"0")
+ .build();
+ var result = session.serialize(JsonMap.of("a", 1));
+ assertFalse(result.contains("\t"));
+ }
+
+ // -- WriterSerializerSession: quoteChar --
+
+ @Test void e32_writerSerializer_quoteChar_shortForm() throws
Exception {
+ var session = (WriterSerializerSession)
Json5Serializer.DEFAULT.createSession()
+ .property("quoteChar", '"')
+ .build();
+ var result = session.serialize("hello");
+ assertEquals("\"hello\"", result);
+ }
+
+ @Test void e33_writerSerializer_quoteChar_qualifiedForm()
throws Exception {
+ var session = (WriterSerializerSession)
Json5Serializer.DEFAULT.createSession()
+ .property("WriterSerializerSession.quoteChar",
"\"")
+ .build();
+ var result = session.serialize("hello");
+ assertEquals("\"hello\"", result);
+ }
+
+ // -- CsvSerializerSession: nullValue --
+
+ @Test void e34_csv_nullValue_shortForm() throws Exception {
+ var session = CsvSerializer.DEFAULT.createSession()
+ .property("nullValue", "N/A")
+ .build();
+ var result = session.serialize(JsonMap.of("a", null));
+ assertTrue(result.contains("N/A"));
+ }
+
+ @Test void e35_csv_nullValue_qualifiedForm() throws Exception {
+ var session = CsvSerializer.DEFAULT.createSession()
+ .property("CsvSerializerSession.nullValue",
"EMPTY")
+ .build();
+ var result = session.serialize(JsonMap.of("a", null));
+ assertTrue(result.contains("EMPTY"));
+ }
+
+ // -- CsvSerializerSession: byteArrayFormat --
+
+ @Test void e36_csv_byteArrayFormat_shortForm() throws Exception
{
+ var session = CsvSerializer.DEFAULT.createSession()
+ .property("byteArrayFormat",
ByteArrayFormat.SEMICOLON_DELIMITED)
+ .build();
+ var result = session.serialize(new byte[]{1, 2, 3});
+ assertTrue(result.contains("1;2;3"));
+ }
+
+ // -- ParserSession: trimStrings --
+
+ @Test void e37_parser_trimStrings_shortForm() throws Exception {
+ var session = JsonParser.DEFAULT.createSession()
+ .property("trimStrings", true)
+ .build();
+ var result = session.parse("\" hello \"", String.class);
+ assertEquals("hello", result);
+ }
+
+ @Test void e38_parser_trimStrings_qualifiedForm() throws
Exception {
+ var session = JsonParser.DEFAULT.createSession()
+ .property("ParserSession.trimStrings", "true")
+ .build();
+ var result = session.parse("\" hello \"", String.class);
+ assertEquals("hello", result);
+ }
+
+ // -- JsonSerializerSession: escapeSolidus --
+
+ @Test void e39_json_escapeSolidus_shortForm() throws Exception {
+ var session = (WriterSerializerSession)
JsonSerializer.DEFAULT.createSession()
+ .property("escapeSolidus", true)
+ .build();
+ var result = session.serialize("http://example.com");
+ assertTrue(result.contains("\\/"));
+ }
+
+ @Test void e40_json_escapeSolidus_qualifiedForm() throws
Exception {
+ var session = (WriterSerializerSession)
JsonSerializer.DEFAULT.createSession()
+
.property("JsonSerializerSession.escapeSolidus", "true")
+ .build();
+ var result = session.serialize("http://example.com");
+ assertTrue(result.contains("\\/"));
+ }
+
+ // -- JsonParserSession: validateEnd --
+
+ @Test void e41_json_validateEnd_shortForm() throws Exception {
+ var session = JsonParser.DEFAULT.createSession()
+ .property("validateEnd", true)
+ .build();
+ // With validateEnd=true, trailing content should throw
an error
+ assertThrows(Exception.class, () ->
session.parse("{\"a\":1}extra", JsonMap.class));
+ }
+
+ // -- UonParserSession: validateEnd --
+
+ @Test void e42_uon_validateEnd_shortForm() throws Exception {
+ var session = UonParser.DEFAULT.createSession()
+ .property("validateEnd", true)
+ .build();
+ assertThrows(Exception.class, () ->
session.parse("(a=1)extra", JsonMap.class));
+ }
+
+ // -- UonSerializerSession: encoding --
+
+ @Test void e43_uon_encoding_shortForm() throws Exception {
+ var session = (WriterSerializerSession)
UonSerializer.DEFAULT.createSession()
+ .property("encoding", true)
+ .build();
+ var result = session.serialize("hello world");
+ assertTrue(result.contains("%20") ||
result.contains("+"));
+ }
+
+ // -- UonSerializerSession: paramFormat --
+
+ @Test void e44_uon_paramFormat_shortForm() throws Exception {
+ var session = (WriterSerializerSession)
UonSerializer.DEFAULT.createSession()
+ .property("paramFormat", ParamFormat.PLAINTEXT)
+ .build();
+ var result = session.serialize("hello");
+ assertEquals("hello", result);
+ }
+
+ // -- UrlEncodingSerializerSession: expandedParams --
+
+ @Test void e45_urlEncoding_expandedParams_shortForm() throws
Exception {
+ var session = (WriterSerializerSession)
UrlEncodingSerializer.DEFAULT.createSession()
+ .property("expandedParams", true)
+ .build();
+ var result = session.serialize(JsonMap.of("a", new
int[]{1, 2, 3}));
+ assertTrue(result.contains("a=1") &&
result.contains("a=2") && result.contains("a=3"));
+ }
+
+ // -- XmlSerializerSession: enableNamespaces --
+
+ @Test void e46_xml_enableNamespaces_shortForm() throws
Exception {
+ var session = (WriterSerializerSession)
XmlSerializer.DEFAULT.createSession()
+ .property("enableNamespaces", false)
+ .build();
+ var result = session.serialize(JsonMap.of("a", 1));
+ assertFalse(result.contains("xmlns"));
+ }
+
+ // -- XmlParserSession: preserveRootElement --
+
+ @Test void e47_xml_preserveRootElement_shortForm() throws
Exception {
+ var session = XmlParser.DEFAULT.createSession()
+ .property("preserveRootElement", true)
+ .build();
+ var result = session.parse("<root><a>1</a></root>",
JsonMap.class);
+ assertTrue(result.containsKey("root"));
+ }
+
+ // -- HtmlSerializerSession: detectLinksInStrings --
+
+ @Test void e48_html_detectLinksInStrings_shortForm() throws
Exception {
+ var session = (WriterSerializerSession)
HtmlSerializer.DEFAULT.createSession()
+ .property("detectLinksInStrings", false)
+ .build();
+ var result = session.serialize("http://example.com");
+ assertFalse(result.contains("<a "));
+ }
+
+ // -- HtmlSerializerSession: labelParameter --
+
+ @Test void e49_html_labelParameter_shortForm() throws Exception
{
+ var session = (WriterSerializerSession)
HtmlSerializer.DEFAULT.createSession()
+ .property("labelParameter", "customlabel")
+ .build();
+ var result =
session.serialize("http://example.com?customlabel=MyLink");
+ assertTrue(result.contains("MyLink"));
+ }
}
}
diff --git a/todo/session-options-files.zip b/todo/session-options-files.zip
new file mode 100644
index 0000000000..20fc5685f3
Binary files /dev/null and b/todo/session-options-files.zip differ
diff --git a/todo/session-options-plan.md b/todo/session-options-plan.md
new file mode 100644
index 0000000000..6ecc6d98f1
--- /dev/null
+++ b/todo/session-options-plan.md
@@ -0,0 +1,288 @@
+# Session Options & Allowlists Refactoring Plan
+
+This document describes all changes made to implement serializer/parser
session options, allowlists, `noInherit`, and the separation of request
attributes from session properties.
+
+---
+
+## Overview
+
+The changes fall into these major categories:
+
+1. **New constants classes** for shared wire names and server-side settings
+2. **New annotation properties** (`allowedSerializerOptions`,
`allowedParserOptions`, `noInherit`) on `@Rest` and all `@RestOp`-group
annotations
+3. **Session option allowlists** computed via memoized fields on `RestContext`
and `RestOpContext`, with inheritance and negation support
+4. **Separation of request attributes from session properties** —
`defaultRequestAttributes` no longer auto-merged into session properties
+5. **Programmatic session property setters** on `RestRequest`
+6. **REST client wire helpers** for passing session options via headers/query
params
+7. **Swagger documentation** for session option parameters
+8. **Test updates** to accommodate the new behavior
+9. **Release notes** documenting the changes
+
+---
+
+## 1. New Files (Added)
+
+###
`juneau-rest/juneau-rest-common/src/main/java/org/apache/juneau/rest/RestSharedConstants.java`
+Central home for static literals shared across REST modules (server, client,
mock). Contains:
+- `HEADER_JuneauSerializerOptions` = `"X-Juneau-Serializer-Options"`
+- `HEADER_JuneauParserOptions` = `"X-Juneau-Parser-Options"`
+- `QUERY_juneauSerializerOptions` = `"juneauSerializerOptions"`
+- `QUERY_juneauParserOptions` = `"juneauParserOptions"`
+
+###
`juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestServerConstants.java`
+Server-side static literals:
+- `PROPERTY_allowedSerializerOptions` = `"allowedSerializerOptions"`
+- `PROPERTY_allowedParserOptions` = `"allowedParserOptions"`
+- `PROPERTY_noInherit` = `"noInherit"`
+- Various `SETTING_sessionOptions_*` fields
+- Various `PROP_*` fields for properties output
+
+### `juneau-utest/src/test/java/org/apache/juneau/rest/NoInherit_Test.java`
+Tests for `noInherit` behavior:
+- `a01_classNoInherit_skipsParentSerializerAllowlist` — class-level
`noInherit` blocks parent context
+- `a02_withoutNoInherit_mergesParentSerializerAllowlist` — no `noInherit`
merges parent+child
+- `a03_methodNoInherit_stillInheritsParentMethodSerializerAllowlist` — method
`noInherit` does NOT block parent method annotations (only blocks context)
+- `a04_aggregatedNoInherit_includesBothParentAndChild` — aggregated
`noInherit` for unrelated props doesn't block `allowedSerializerOptions`
+- `a05_methodNoInherit_blocksClassLevelButNotParentMethod` — method
`noInherit="allowedSerializerOptions"` blocks class-level keys but still
inherits parent method keys
+
+### `juneau-utest/src/test/java/org/apache/juneau/rest/RestOpContext_Test.java`
+Tests for `RestOpContext` allowlist computation, `noInherit` aggregation, and
annotation discovery.
+
+###
`juneau-utest/src/test/java/org/apache/juneau/rest/RestRequest_SessionProperties_Test.java`
+Tests for `RestRequest.setSerializerSessionProperty()`,
`setParserSessionProperty()`, `setSerializerSessionProperties()`,
`setParserSessionProperties()`.
+
+---
+
+## 2. Annotation Changes
+
+### New properties on `@Rest` (`Rest.java`, `RestAnnotation.java`):
+- `String[] allowedSerializerOptions() default {};` — CDL of allowed
serializer session option keys
+- `String[] allowedParserOptions() default {};` — CDL of allowed parser
session option keys
+- `String[] noInherit() default {};` — CDL of property names to NOT inherit
from parent class hierarchy
+
+### New properties on all `@RestOp`-group annotations:
+Same three properties (`allowedSerializerOptions`, `allowedParserOptions`,
`noInherit`) added to:
+- `RestOp.java` / `RestOpAnnotation.java`
+- `RestGet.java` / `RestGetAnnotation.java`
+- `RestPost.java` / `RestPostAnnotation.java`
+- `RestPut.java` / `RestPutAnnotation.java`
+- `RestPatch.java` / `RestPatchAnnotation.java`
+- `RestDelete.java` / `RestDeleteAnnotation.java`
+- `RestOptions.java` / `RestOptionsAnnotation.java`
+
+Each `*Annotation.java` file also has updated `Builder` with fields, getters,
setters, and `hashKey()` updates.
+
+Full Javadocs duplicated on each annotation (not cross-referenced to
`@RestOp`).
+
+---
+
+## 3. Core Library Changes
+
+###
`juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/utils/StringUtils.java`
+- Added `public static final String[] EMPTY_STRING_ARRAY = new String[0];`
+
+###
`juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/utils/CollectionUtils.java`
+- Added `removeNegations(List<String>)` — removes entries paired with `-entry`
tokens
+- Added `treeSet(Comparator, Collection)` — creates TreeSet with comparator
from collection
+- Added `rstream(List)` — reverse stream of a list
+
+###
`juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/reflect/AnnotationInfo.java`
+- Added `getStringArray(String name)` — returns `Optional<String[]>` for
annotation attribute
+- Added `getAnnotatable()` — returns the `Annotatable` where the annotation
was found
+
+###
`juneau-core/juneau-marshall/src/main/java/org/apache/juneau/ContextSession.java`
+- Added `getSessionProperties()` method returning the session property map
+
+###
`juneau-core/juneau-marshall/src/main/java/org/apache/juneau/BeanSession.java`
+- Minor changes for session property support
+
+###
`juneau-core/juneau-marshall/src/main/java/org/apache/juneau/serializer/OutputStreamSerializerSession.java`
+- Minor changes for session property support
+
+###
`juneau-core/juneau-marshall/src/main/java/org/apache/juneau/json/JsonSerializerSession.java`
+- Minor changes
+
+###
`juneau-core/juneau-marshall/src/main/java/org/apache/juneau/bson/BsonParserSession.java`
+- Minor changes
+
+###
`juneau-core/juneau-marshall/src/main/java/org/apache/juneau/objecttools/ObjectRest.java`
+- Minor changes
+
+---
+
+## 4. RestContext Changes
+
+###
`juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestContext.java`
+
+Major additions:
+- **`allowedSerializerOptionsKeys`** memoizer — computes allowed serializer
session option keys from `@Rest` annotations:
+ 1. Inherits from parent context (router hierarchy) unless `noInherit` blocks
it
+ 2. Pre-pass walks nearest-first to find `noInherit` cut-off point
+ 3. Collects tokens in parent-to-child order (reversed) via `rstream()` so
child negation tokens (`-key`) override parent additions
+ 4. Calls `removeNegations()` for deferred negation resolution
+- **`allowedParserOptionsKeys`** memoizer — same pattern for parser options
+- **`getRestAnnotationsForProperty(String name)`** helper — finds cut-off via
`noInherit`, returns reversed stream
+- **`noInherit`** memoizer — aggregates `noInherit` tokens from nearest `@Rest`
+- **`isInherited(String property)`** — checks if a property is blocked by
`noInherit` (for parent context inheritance)
+- **`getRestAnnotations()`** — returns all `@Rest` annotations on the class
hierarchy
+- **`getRestAnnotation()`** — returns the nearest (first) `@Rest` annotation
+- **`resolveCdl(String...)`** — resolves comma-delimited annotation values
with SVL variable resolution
+- **`reset()`** — clears memoized allowlists and cascades to op contexts
+- Removed `EMPTY_STRING_ARRAY` local constant (now in `StringUtils`)
+- Added `import static` for `StringUtils.EMPTY_STRING_ARRAY`
+
+---
+
+## 5. RestOpContext Changes
+
+###
`juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestOpContext.java`
+
+Major additions:
+- **`allowedSerializerOptionsKeys`** memoizer:
+ 1. Adds context-level keys from
`RestContext.getAllowedSerializerOptionsKeys()` if not blocked by aggregated
`noInherit`
+ 2. Always inherits method-level keys from the full method override chain
(child + parent methods) — `noInherit` does NOT cut off method-chain climbing
+- **`allowedParserOptionsKeys`** memoizer — same pattern
+- **`noInherit`** memoizer — aggregates `noInherit` tokens from ALL
`@RestOp`-group annotations on the method override chain
+- **`isInherited(String property)`** — checks aggregated `noInherit` for
context-level inheritance
+- **`getRestOpAnnotations()`** — returns all `@RestOp`-group annotations
(including `@RestGet`, etc.) on the method and parent methods, child-to-parent
order, using `AnnotationInfo.isInGroup(RestOp.class)`
+- **`resolveCdl(String...)`** — resolves comma-delimited annotation values
+- **`reset()`** — clears memoized allowlists
+- Removed `EMPTY_STRING_ARRAY` local constant (now in `StringUtils`)
+
+### Inheritance semantics (two types):
+1. **Context inheritance** (from `RestContext`) — controlled by `noInherit`.
When `noInherit="allowedSerializerOptions"`, blocks values from the `@Rest`
class annotation
+2. **Method annotation inheritance** (from parent method `@RestOp`
annotations) — ALWAYS inherited, regardless of `noInherit`
+
+---
+
+## 6. RestRequest Changes
+
+###
`juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestRequest.java`
+
+Major additions:
+- **`setSerializerSessionProperty(String name, Object value)`** — sets a
single serializer session property
+- **`setParserSessionProperty(String name, Object value)`** — sets a single
parser session property
+- **`setSerializerSessionProperties(Map<String,Object> values)`** — sets bulk
serializer session properties
+- **`setParserSessionProperties(Map<String,Object> values)`** — sets bulk
parser session properties
+- **`getSerializerSessionPropertyMap()`** — computes effective serializer
session properties by merging:
+ 1. Query parameter `juneauSerializerOptions` (UON format)
+ 2. Header `X-Juneau-Serializer-Options` (JSON5 format)
+ 3. Programmatic `serializerSessionProperties` set via setters
+ - Validates all keys against the allowlist; throws `BadRequest` for
disallowed keys
+- **`getParserSessionPropertyMap()`** — same for parser options
+- **`isPlainText()`** — checks for `plainText: true` header
+- **Private helpers**: `merge(Map...)`, `badRequest(...)`, `parseUonMap(...)`,
`parseJsonMap(...)` — all static
+- **Removed**: Request attributes (`getAttributes().asMap()`) are no longer
merged into session property maps
+
+---
+
+## 7. REST Client Changes
+
+###
`juneau-rest/juneau-rest-client/src/main/java/org/apache/juneau/rest/client/RestClient.java`
+- Added default session option header/query parameter methods on
`RestClient.Builder`
+- Uses `RestSharedConstants` wire names
+
+###
`juneau-rest/juneau-rest-client/src/main/java/org/apache/juneau/rest/client/RestRequest.java`
+- Added per-request session option header/query parameter methods
+- Uses `RestSharedConstants` wire names
+
+###
`juneau-rest/juneau-rest-mock/src/main/java/org/apache/juneau/rest/mock/MockRestClient.java`
+- Overrides session option methods for fluent typing
+
+###
`juneau-rest/juneau-rest-mock/src/main/java/org/apache/juneau/rest/mock/MockRestRequest.java`
+- Overrides session option methods for fluent typing
+
+---
+
+## 8. Serialized POJO Processor Changes
+
+###
`juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/processor/SerializedPojoProcessor.java`
+- Now calls `req.getSerializerSessionPropertyMap()` to get session properties
and passes them to serializer via `.properties()`
+
+###
`juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/httppart/RequestContent.java`
+- Now calls `req.getParserSessionPropertyMap()` to get parser session
properties
+
+---
+
+## 9. Swagger Changes
+
+###
`juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/swagger/BasicSwaggerProviderSession.java`
+- Generated Swagger now includes optional documentation parameters for session
options:
+ - Headers: `X-Juneau-Serializer-Options`, `X-Juneau-Parser-Options`
+ - Query params: `juneauSerializerOptions`, `juneauParserOptions`
+
+---
+
+## 10. Config Changes
+
+###
`juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/config/BasicUniversalConfig.java`
+- Added `allowedSerializerOptions="binaryFormat"` and
`allowedParserOptions="binaryFormat"` to `@Rest`
+
+###
`juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/config/DefaultConfig.java`
+- Minor changes to allowed header params
+
+---
+
+## 11. Test Updates
+
+### Tests updated to use new programmatic API (separated attributes from
session properties):
+
+**`Nls_Test.java`**:
+- Removed `defaultRequestAttributes` for session properties from
`@Rest`/`@RestGet`
+- Methods now accept `RestRequest req` and call
`req.setSerializerSessionProperty("TestProperty", req.getMessage("key1"))`
explicitly
+- Removed fully-qualified `org.apache.juneau.rest.RestRequest` references
+
+**`Rest_DefaultRequestAttributes_Test.java`**:
+- Test A (parser): Added `req.setParserSessionProperties(attrs.asMap())` in
`@RestPreCall` and in REST method `b()`
+- Test B (serializer): Added
`req.setSerializerSessionProperties(attrs.asMap())` in `@RestPostCall` and in
REST method `b()`
+
+**`Rest_RVars_Test.java`**:
+- Added `RestRequest req` parameter to method `a()`
+- Added `req.setSerializerSessionProperties(req.getAttributes().asMap())` to
bridge attributes to session properties
+
+**`RestClient_Headers_Test.java`**:
+- Added `allowedSerializerOptions="simple"` and
`allowedParserOptions="addBeanTypes"` to `@RestGet` annotation on `headers()`
method in class `A`
+
+**`ContentComboTestBase.java`**:
+- MsgPack client: added `queryData("juneauSerializerOptions",
"(binaryFormat=BASE64)")` to send session options
+
+### Annotation test updates:
+- `RestAnnotation_Test.java` — tests for new `allowedSerializerOptions`,
`allowedParserOptions`, `noInherit` properties
+- `RestOpAnnotation_Test.java` — same
+- `RestGetAnnotation_Test.java` — same
+- `RestPostAnnotation_Test.java` — same
+- `RestPutAnnotation_Test.java` — same
+- `RestDeleteAnnotation_Test.java` — same
+
+### Other test updates:
+- `CollectionUtils_Test.java` — tests for `removeNegations()`,
`treeSet(Comparator, Collection)`, `rstream()`
+- `AnnotationInfo_Test.java` — tests for `getStringArray()`, `getAnnotatable()`
+- `RestClient_Query_Test.java` — tests for session option query parameters
+
+---
+
+## 12. Release Notes
+
+### `/docs/pages/release-notes/9.2.1.md` (docs repo, untracked)
+Added sections:
+- **Request Attributes and Session Properties Separation** — breaking change,
new API, migration guidance with code examples
+- **`noInherit` Inheritance Semantics** — clarified class-level vs
method-level inheritance, with code example showing `noInherit` blocks
class-level but not parent method-level keys
+
+---
+
+## Key Design Decisions
+
+### `noInherit` semantics:
+1. **On `@Rest`**: Controls two things:
+ - Blocks inheritance from parent context (router hierarchy)
+ - Stops climbing the class hierarchy annotations (the for-loop breaks)
+2. **On `@RestOp`-group annotations**: Only blocks inheritance from
`RestContext` (class-level); does NOT cut off method override chain climbing —
parent method annotations are always inherited
+
+### Annotation hierarchy walking in `RestContext`:
+- Pre-pass walks nearest-first to find `noInherit` cut-off
+- Collection pass walks parent-to-child (reversed via `rstream()`) so child
negation tokens override parent values
+- `removeNegations()` does deferred resolution at the end
+
+### Annotation hierarchy walking in `RestOpContext`:
+- Always iterates ALL method annotations (no cut-off for method chain)
+- `isInherited()` only controls whether to include `RestContext`-level keys