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 f718a4621a refactor: reorder serializer/parser dispatch chains +
ClassMeta polish (TODO-56)
f718a4621a is described below
commit f718a4621acb5bcfde6d614ba68460e09ce99f99
Author: James Bognar <[email protected]>
AuthorDate: Fri May 22 12:18:23 2026 -0400
refactor: reorder serializer/parser dispatch chains + ClassMeta polish
(TODO-56)
---
.../org/apache/juneau/jena/RdfParserSession.java | 62 ++++++++--------
.../apache/juneau/jena/RdfSerializerSession.java | 38 +++++-----
.../apache/juneau/jena/RdfStreamParserSession.java | 77 ++++++++++----------
.../juneau/jena/RdfStreamSerializerSession.java | 40 ++++++-----
.../src/main/java/org/apache/juneau/ClassMeta.java | 11 ++-
.../apache/juneau/bson/BsonSerializerSession.java | 70 +++++++++---------
.../org/apache/juneau/cbor/CborParserSession.java | 54 +++++++-------
.../apache/juneau/cbor/CborSerializerSession.java | 32 ++++-----
.../juneau/hjson/HjsonSerializerSession.java | 26 +++----
.../juneau/hocon/HoconSerializerSession.java | 27 +++----
.../org/apache/juneau/html/HtmlParserSession.java | 8 +--
.../apache/juneau/html/HtmlSerializerSession.java | 82 ++++++++++-----------
.../apache/juneau/ini/IniSerializerSession.java | 12 ++--
.../org/apache/juneau/json/JsonParserSession.java | 52 +++++++-------
.../apache/juneau/json/JsonSerializerSession.java | 26 +++----
.../juneau/markdown/MarkdownParserSession.java | 8 +--
.../juneau/markdown/MarkdownSerializerSession.java | 14 ++--
.../juneau/msgpack/MsgPackParserSession.java | 54 +++++++-------
.../juneau/msgpack/MsgPackSerializerSession.java | 32 ++++-----
.../apache/juneau/proto/ProtoParserSession.java | 54 +++++++-------
.../juneau/proto/ProtoSerializerSession.java | 4 +-
.../org/apache/juneau/toml/TomlParserSession.java | 43 +++++------
.../apache/juneau/toml/TomlSerializerSession.java | 40 +++++------
.../org/apache/juneau/uon/UonParserSession.java | 60 ++++++++--------
.../apache/juneau/uon/UonSerializerSession.java | 32 ++++-----
.../urlencoding/UrlEncodingParserSession.java | 6 +-
.../urlencoding/UrlEncodingSerializerSession.java | 6 +-
.../org/apache/juneau/xml/XmlParserSession.java | 48 ++++++-------
.../apache/juneau/xml/XmlSerializerSession.java | 29 ++++----
.../org/apache/juneau/yaml/YamlParserSession.java | 48 ++++++-------
.../apache/juneau/yaml/YamlSerializerSession.java | 8 +--
...ISHED-56-serializer-parser-dispatch-cleanup.md} | 84 ++++++++++++++++++++++
32 files changed, 644 insertions(+), 543 deletions(-)
diff --git
a/juneau-core/juneau-marshall-rdf/src/main/java/org/apache/juneau/jena/RdfParserSession.java
b/juneau-core/juneau-marshall-rdf/src/main/java/org/apache/juneau/jena/RdfParserSession.java
index 2f48def313..05faebef32 100644
---
a/juneau-core/juneau-marshall-rdf/src/main/java/org/apache/juneau/jena/RdfParserSession.java
+++
b/juneau-core/juneau-marshall-rdf/src/main/java/org/apache/juneau/jena/RdfParserSession.java
@@ -402,24 +402,18 @@ public class RdfParserSession extends ReaderParserSession
{
} else {
throw new ParseException(this, "Unrecognized
node type ''{0}'' for object", n);
}
- } else if (sType.isBoolean()) {
- o = convertToType(getValue(n, outer), boolean.class);
- } else if (sType.isCharSequence()) {
- o = decodeString(getValue(n, outer));
- } else if (sType.isChar()) {
- o = parseCharacter(decodeString(getValue(n, outer)));
- } else if (sType.isNumber()) {
- o = parseNumber(getValue(n, outer).toString(), (Class<?
extends Number>)sType.inner());
- } else if (sType.isDate()) {
- o = parseDate(getValue(n, outer).toString(), sType);
- } else if (sType.isCalendar()) {
- o = parseCalendar(getValue(n, outer).toString(), sType);
- } else if (sType.isTemporal()) {
- o = parseTemporal(getValue(n, outer).toString(), sType);
- } else if (sType.isDuration()) {
- o = parseDuration(getValue(n, outer).toString());
- } else if (sType.isPeriod()) {
- o = parsePeriod(getValue(n, outer).toString());
+ } else if (nn(builder)) {
+ var r = n.asResource();
+ if (! urisVisited.add(r))
+ return null;
+ var bm = toBeanMap(builder.create(this, eType));
+ o = builder.build(this, parseIntoBeanMap(r,
bm).getBean(), eType);
+ } else if (sType.canCreateNewBean(outer)) {
+ var r = n.asResource();
+ if (! urisVisited.add(r))
+ return null;
+ var bm = newBeanMap(outer, sType.inner());
+ o = parseIntoBeanMap(r, bm).getBean();
} else if (sType.isMap()) {
var r = n.asResource();
if (! urisVisited.add(r))
@@ -445,20 +439,28 @@ public class RdfParserSession extends ReaderParserSession
{
}
if (sType.isArray() || sType.isArgs())
o = toArray(sType, (Collection)o);
- } else if (nn(builder)) {
- var r = n.asResource();
- if (! urisVisited.add(r))
- return null;
- var bm = toBeanMap(builder.create(this, eType));
- o = builder.build(this, parseIntoBeanMap(r,
bm).getBean(), eType);
- } else if (sType.canCreateNewBean(outer)) {
- var r = n.asResource();
- if (! urisVisited.add(r))
- return null;
- var bm = newBeanMap(outer, sType.inner());
- o = parseIntoBeanMap(r, bm).getBean();
+ } else if (sType.isCharSequence()) {
+ o = decodeString(getValue(n, outer));
+ } else if (sType.isChar()) {
+ o = parseCharacter(decodeString(getValue(n, outer)));
+ } else if (sType.isNumber()) {
+ o = parseNumber(getValue(n, outer).toString(), (Class<?
extends Number>)sType.inner());
+ } else if (sType.isBoolean()) {
+ o = convertToType(getValue(n, outer), boolean.class);
} else if (sType.isUri() && n.isResource()) {
+ // RDF URIs must be reconstructed from the resource's
URI string (not from a literal),
+ // so this branch is kept here to fire before the
temporal/scalar coercion fallbacks.
o = sType.newInstanceFromString(outer,
decodeString(n.asResource().getURI()));
+ } else if (sType.isDate()) {
+ o = parseDate(getValue(n, outer).toString(), sType);
+ } else if (sType.isCalendar()) {
+ o = parseCalendar(getValue(n, outer).toString(), sType);
+ } else if (sType.isTemporal()) {
+ o = parseTemporal(getValue(n, outer).toString(), sType);
+ } else if (sType.isDuration()) {
+ o = parseDuration(getValue(n, outer).toString());
+ } else if (sType.isPeriod()) {
+ o = parsePeriod(getValue(n, outer).toString());
} else if (sType.canCreateNewInstanceFromString(outer)) {
o = sType.newInstanceFromString(outer,
decodeString(getValue(n, outer)));
} else if (n.isResource()) {
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 3ba2ed5cfc..60b3b89249 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
@@ -375,21 +375,22 @@ public class RdfSerializerSession extends
WriterSerializerSession {
}
} else if (sType.isUri() || isURI) {
- // Note that RDF URIs must be absolute to be valid!
+ // RDF URI gate must come before
isBean/isMap/isCharSequence: @Uri-annotated values (where sType could be String
or a bean) need to route through the Resource emission path. RDF URIs must be
absolute to be valid.
var uri = getUri(o, null);
if (isAbsoluteUri(uri))
n = m.createResource(uri);
else
n =
m.createLiteral(encodeTextInvalidChars(uri));
- } else if (sType.isCharSequence() || sType.isChar()) {
- n = m.createLiteral(encodeTextInvalidChars(o));
-
- } else if (sType.isNumber() || sType.isBoolean()) {
- if (! isAddLiteralTypes())
- n = m.createLiteral(o.toString());
- else
- n = m.createTypedLiteral(o);
+ } else if (sType.isBean()) {
+ var bm = toBeanMap(o);
+ Object uri = null;
+ RdfBeanMeta rbm = getRdfBeanMeta(bm.getMeta());
+ if (rbm.hasBeanUri())
+ uri = rbm.getBeanUriProperty().get(bm, null);
+ String uri2 = getUri(uri, null);
+ n = m.createResource(uri2);
+ serializeBeanMap(bm, (Resource)n, typeName);
} else if (sType.isMap() || (nn(wType) && wType.isMap())) {
if (o instanceof BeanMap o2) {
@@ -406,16 +407,6 @@ public class RdfSerializerSession extends
WriterSerializerSession {
serializeMap(m2, (Resource)n, sType);
}
- } else if (sType.isBean()) {
- var bm = toBeanMap(o);
- Object uri = null;
- RdfBeanMeta rbm = getRdfBeanMeta(bm.getMeta());
- if (rbm.hasBeanUri())
- uri = rbm.getBeanUriProperty().get(bm, null);
- String uri2 = getUri(uri, null);
- n = m.createResource(uri2);
- serializeBeanMap(bm, (Resource)n, typeName);
-
} else if (sType.isCollectionOrArray() || (nn(wType) &&
wType.isCollection())) {
var c = sort(sType.isCollection() ? (Collection)o :
toList(sType.inner(), o));
@@ -438,6 +429,15 @@ public class RdfSerializerSession extends
WriterSerializerSession {
};
}
+ } else if (sType.isCharSequence() || sType.isChar()) {
+ n = m.createLiteral(encodeTextInvalidChars(o));
+
+ } else if (sType.isNumber() || sType.isBoolean()) {
+ if (! isAddLiteralTypes())
+ n = m.createLiteral(o.toString());
+ else
+ n = m.createTypedLiteral(o);
+
} else if (sType.isReader()) {
n =
m.createLiteral(encodeTextInvalidChars(read((Reader)o,
SerializerSession::handleThrown)));
} else if (sType.isInputStream()) {
diff --git
a/juneau-core/juneau-marshall-rdf/src/main/java/org/apache/juneau/jena/RdfStreamParserSession.java
b/juneau-core/juneau-marshall-rdf/src/main/java/org/apache/juneau/jena/RdfStreamParserSession.java
index 10f2c39ed1..5a6134fc41 100644
---
a/juneau-core/juneau-marshall-rdf/src/main/java/org/apache/juneau/jena/RdfStreamParserSession.java
+++
b/juneau-core/juneau-marshall-rdf/src/main/java/org/apache/juneau/jena/RdfStreamParserSession.java
@@ -403,37 +403,34 @@ public class RdfStreamParserSession extends
InputStreamParserSession {
} else {
throw new ParseException(this, "Unrecognized
node type ''{0}'' for object", n);
}
- } else if (sType.isBoolean()) {
- o = convertToType(getValue(n, outer), boolean.class);
+ } else if (nn(builder)) {
+ var r = n.asResource();
+ if (! urisVisited.add(r))
+ return null;
+ var bm = toBeanMap(builder.create(this, eType));
+ o = builder.build(this, parseIntoBeanMap(r,
bm).getBean(), eType);
+ } else if (sType.canCreateNewBean(outer)) {
+ var r = n.asResource();
+ if (! urisVisited.add(r))
+ return null;
+ var bm = newBeanMap(outer, sType.inner());
+ o = parseIntoBeanMap(r, bm).getBean();
+ } else if (sType.isMap()) {
+ var r = n.asResource();
+ if (! urisVisited.add(r))
+ return null;
+ var m = (sType.canCreateNewInstance(outer) ?
(Map)sType.newInstance(outer) : newGenericMap(sType));
+ o = parseIntoMap(r, m, eType.getKeyType(),
eType.getValueType(), pMeta);
} else if (sType.isByteArray()) {
+ // Correctness gate: byte[] satisfies
isArray()/isCollectionOrArray() too, but RDF emits
+ // byte[] as a typed base64 literal (not as a
Seq/Bag/RDFList of byte resources). This
+ // branch MUST stay above isCollectionOrArray so the
literal path fires first.
var v = getValue(n, outer);
if (v instanceof byte[] b) {
o = b;
} else if (v != null) {
o =
java.util.Base64.getDecoder().decode(v.toString());
}
- } else if (sType.isCharSequence()) {
- o = decodeString(getValue(n, outer));
- } else if (sType.isChar()) {
- o = parseCharacter(decodeString(getValue(n, outer)));
- } else if (sType.isNumber()) {
- o = parseNumber(getValue(n, outer).toString(), (Class<?
extends Number>)sType.inner());
- } else if (sType.isDate()) {
- o = parseDate(getValue(n, outer).toString(), sType);
- } else if (sType.isCalendar()) {
- o = parseCalendar(getValue(n, outer).toString(), sType);
- } else if (sType.isTemporal()) {
- o = parseTemporal(getValue(n, outer).toString(), sType);
- } else if (sType.isDuration()) {
- o = parseDuration(getValue(n, outer).toString());
- } else if (sType.isPeriod()) {
- o = parsePeriod(getValue(n, outer).toString());
- } else if (sType.isMap()) {
- var r = n.asResource();
- if (! urisVisited.add(r))
- return null;
- var m = (sType.canCreateNewInstance(outer) ?
(Map)sType.newInstance(outer) : newGenericMap(sType));
- o = parseIntoMap(r, m, eType.getKeyType(),
eType.getValueType(), pMeta);
} else if (sType.isCollectionOrArray() || sType.isArgs()) {
if (sType.isArray() || sType.isArgs())
o = list();
@@ -453,20 +450,28 @@ public class RdfStreamParserSession extends
InputStreamParserSession {
}
if (sType.isArray() || sType.isArgs())
o = toArray(sType, (Collection)o);
- } else if (nn(builder)) {
- var r = n.asResource();
- if (! urisVisited.add(r))
- return null;
- var bm = toBeanMap(builder.create(this, eType));
- o = builder.build(this, parseIntoBeanMap(r,
bm).getBean(), eType);
- } else if (sType.canCreateNewBean(outer)) {
- var r = n.asResource();
- if (! urisVisited.add(r))
- return null;
- var bm = newBeanMap(outer, sType.inner());
- o = parseIntoBeanMap(r, bm).getBean();
+ } else if (sType.isCharSequence()) {
+ o = decodeString(getValue(n, outer));
+ } else if (sType.isChar()) {
+ o = parseCharacter(decodeString(getValue(n, outer)));
+ } else if (sType.isNumber()) {
+ o = parseNumber(getValue(n, outer).toString(), (Class<?
extends Number>)sType.inner());
+ } else if (sType.isBoolean()) {
+ o = convertToType(getValue(n, outer), boolean.class);
} else if (sType.isUri() && n.isResource()) {
+ // RDF URIs must be reconstructed from the resource's
URI string (not from a literal),
+ // so this branch is kept here to fire before the
temporal/scalar coercion fallbacks.
o = sType.newInstanceFromString(outer,
decodeString(n.asResource().getURI()));
+ } else if (sType.isDate()) {
+ o = parseDate(getValue(n, outer).toString(), sType);
+ } else if (sType.isCalendar()) {
+ o = parseCalendar(getValue(n, outer).toString(), sType);
+ } else if (sType.isTemporal()) {
+ o = parseTemporal(getValue(n, outer).toString(), sType);
+ } else if (sType.isDuration()) {
+ o = parseDuration(getValue(n, outer).toString());
+ } else if (sType.isPeriod()) {
+ o = parsePeriod(getValue(n, outer).toString());
} else if (sType.canCreateNewInstanceFromString(outer)) {
o = sType.newInstanceFromString(outer,
decodeString(getValue(n, outer)));
} else if (n.isResource()) {
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 50dc5ef960..d1c3a63c23 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
@@ -320,21 +320,21 @@ public class RdfStreamSerializerSession extends
OutputStreamSerializerSession {
n = m.createResource(RDF_NIL);
}
} else if (sType.isUri() || isURI) {
+ // RDF URI gate must come before
isBean/isMap/isCharSequence: @Uri-annotated values need Resource emission, not
literal text.
var uri = getUri(o, null);
if (isAbsoluteUri(uri))
n = m.createResource(uri);
else
n =
m.createLiteral(encodeTextInvalidChars(uri));
- } else if (sType.isCharSequence() || sType.isChar()) {
- n = m.createLiteral(encodeTextInvalidChars(o));
- } else if (sType.isNumber() || sType.isBoolean()) {
- if (!ctx.isAddLiteralTypes())
- n = m.createLiteral(o.toString());
- else
- n = m.createTypedLiteral(o);
- } else if (sType.isByteArray()) {
- var b64 = Base64.getEncoder().encodeToString((byte[])
o);
- n = m.createTypedLiteral(b64,
XSDDatatype.XSDbase64Binary);
+ } else if (sType.isBean()) {
+ var bm = toBeanMap(o);
+ Object uri = null;
+ var rbm = ctx.getRdfBeanMeta(bm.getMeta());
+ if (rbm.hasBeanUri())
+ uri = rbm.getBeanUriProperty().get(bm, null);
+ var uri2 = getUri(uri, null);
+ n = m.createResource(uri2);
+ serializeBeanMap(bm, (Resource)n, typeName);
} else if (sType.isMap() || (nn(wType) && wType.isMap())) {
if (o instanceof BeanMap o2) {
Object uri = null;
@@ -348,15 +348,10 @@ public class RdfStreamSerializerSession extends
OutputStreamSerializerSession {
n = m.createResource();
serializeMap((Map)o, (Resource)n, sType);
}
- } else if (sType.isBean()) {
- var bm = toBeanMap(o);
- Object uri = null;
- var rbm = ctx.getRdfBeanMeta(bm.getMeta());
- if (rbm.hasBeanUri())
- uri = rbm.getBeanUriProperty().get(bm, null);
- var uri2 = getUri(uri, null);
- n = m.createResource(uri2);
- serializeBeanMap(bm, (Resource)n, typeName);
+ } else if (sType.isByteArray()) {
+ // byte[] gate must come before isCollectionOrArray:
byte[] satisfies isArray() but RDF emits it as a typed base64 literal, not as a
Seq of bytes.
+ var b64 = Base64.getEncoder().encodeToString((byte[])
o);
+ n = m.createTypedLiteral(b64,
XSDDatatype.XSDbase64Binary);
} else if (sType.isCollectionOrArray() || (nn(wType) &&
wType.isCollection())) {
var c = sort(sType.isCollection() ? (Collection)o :
toList(sType.inner(), o));
var f = ctx.getCollectionFormat();
@@ -375,6 +370,13 @@ public class RdfStreamSerializerSession extends
OutputStreamSerializerSession {
default -> serializeToContainer(c,
eType, m.createSeq());
};
}
+ } else if (sType.isCharSequence() || sType.isChar()) {
+ n = m.createLiteral(encodeTextInvalidChars(o));
+ } else if (sType.isNumber() || sType.isBoolean()) {
+ if (!ctx.isAddLiteralTypes())
+ n = m.createLiteral(o.toString());
+ else
+ n = m.createTypedLiteral(o);
} else if (sType.isReader()) {
n =
m.createLiteral(encodeTextInvalidChars(read((Reader)o,
SerializerSession::handleThrown)));
} else if (sType.isInputStream()) {
diff --git
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/ClassMeta.java
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/ClassMeta.java
index 0aedd97241..f6635e9d9e 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/ClassMeta.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/ClassMeta.java
@@ -73,7 +73,7 @@ import org.apache.juneau.swap.*;
"java:S1452", // Wildcard required - ClassMeta<?>, ObjectSwap<T,?>,
etc. for element/component types
"java:S6539" // Monster Class: ClassMeta is a focused
reflection-metadata cache; splitting would increase coupling
})
-public class ClassMeta<T> extends BeanInfo<T> {
+public final class ClassMeta<T> extends BeanInfo<T> {
private static class Categories {
int bits;
@@ -1044,7 +1044,7 @@ public class ClassMeta<T> extends BeanInfo<T> {
* @return <jk>true</jk> if this class is a subclass of {@link
Collection}.
*/
@Override
- public boolean isCollection() { return cat != null &&
cat.is(COLLECTION); }
+ public boolean isCollection() { return cat.is(COLLECTION); }
/**
* Returns <jk>true</jk> if this class is a subclass of {@link
Collection} or is an array or {@link Optional}.
@@ -1168,10 +1168,7 @@ public class ClassMeta<T> extends BeanInfo<T> {
* @return <jk>true</jk> if this class is a subclass of {@link Map}.
*/
@Override
- public boolean isMap() {
- // Defensive null-guard: category is expected to be set, but
keep this check for safety.
- return cat != null && cat.is(MAP);
- }
+ public boolean isMap() { return cat.is(MAP); }
/**
* Returns <jk>true</jk> if this class is a subclass of {@link Map} or
it's a bean.
@@ -1274,7 +1271,7 @@ public class ClassMeta<T> extends BeanInfo<T> {
* @return <jk>true</jk> if this class is a {@link URI} or {@link URL}.
*/
@Override
- public boolean isUri() { return cat != null && cat.is(URI); }
+ public boolean isUri() { return cat.is(URI); }
/**
* Converts the specified object into an instance of this class.
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 848150eb81..dade47be23 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
@@ -137,6 +137,38 @@ public class BsonSerializerSession extends
OutputStreamSerializerSession {
if (o == null || (sType.isChar() && ((Character)o).charValue()
== 0)) {
out.writeElement(NULL.value, name);
+ } else if (sType.isBean()) {
+ out.writeElement(DOCUMENT.value, name);
+ var child = out.createChild();
+ child.startDocument();
+ serializeBeanMap(child, toBeanMap(o),
getBeanTypeName(this, eType, aType, pMeta));
+ out.writeChildDocument(child);
+ } else if (sType.isMap()) {
+ if (o instanceof BeanMap o2) {
+ out.writeElement(DOCUMENT.value, name);
+ var child = out.createChild();
+ child.startDocument();
+ serializeBeanMap(child, o2,
getBeanTypeName(this, eType, aType, pMeta));
+ out.writeChildDocument(child);
+ } else {
+ out.writeElement(DOCUMENT.value, name);
+ var child = out.createChild();
+ child.startDocument();
+ serializeMap(child, (Map)o, eType);
+ out.writeChildDocument(child);
+ }
+ } else if (sType.isByteArray()) {
+ out.writeElement(BINARY.value, name);
+ out.writeBinary((byte[])o);
+ } else if (sType.isCollection() || sType.isArray()) {
+ out.writeElement(ARRAY.value, name);
+ var child = out.createChild();
+ child.startDocument();
+ serializeArray(child, sType.isArray() ?
toList(sType.inner(), o) : (Collection)o, eType);
+ out.writeChildDocument(child);
+ } else if (sType.isCharSequence() || sType.isChar() ||
sType.isEnum()) {
+ out.writeElement(STRING.value, name);
+ out.writeString(trim(o));
} else if (sType.isBoolean()) {
out.writeElement(BOOLEAN.value, name);
out.writeBoolean((Boolean)o);
@@ -158,6 +190,9 @@ public class BsonSerializerSession extends
OutputStreamSerializerSession {
out.writeElement(DOUBLE.value, name);
out.writeDouble(((Number)o).doubleValue());
}
+ } else if (sType.isUri() || (nn(pMeta) && pMeta.isUri())) {
+ out.writeElement(STRING.value, name);
+ out.writeString(resolveUri(o.toString()));
} else if (sType.isDate()) {
if (ctx.writeDatesAsDatetime) {
out.writeElement(DATETIME.value, name);
@@ -187,47 +222,12 @@ public class BsonSerializerSession extends
OutputStreamSerializerSession {
} else if (sType.isPeriod()) {
out.writeElement(STRING.value, name);
out.writeString(serializePeriod((Period)o));
- } else if (sType.isBean()) {
- out.writeElement(DOCUMENT.value, name);
- var child = out.createChild();
- child.startDocument();
- serializeBeanMap(child, toBeanMap(o),
getBeanTypeName(this, eType, aType, pMeta));
- out.writeChildDocument(child);
- } else if (sType.isUri() || (nn(pMeta) && pMeta.isUri())) {
- out.writeElement(STRING.value, name);
- out.writeString(resolveUri(o.toString()));
- } else if (sType.isMap()) {
- if (o instanceof BeanMap o2) {
- out.writeElement(DOCUMENT.value, name);
- var child = out.createChild();
- child.startDocument();
- serializeBeanMap(child, o2,
getBeanTypeName(this, eType, aType, pMeta));
- out.writeChildDocument(child);
- } else {
- out.writeElement(DOCUMENT.value, name);
- var child = out.createChild();
- child.startDocument();
- serializeMap(child, (Map)o, eType);
- out.writeChildDocument(child);
- }
- } else if (sType.isByteArray()) {
- out.writeElement(BINARY.value, name);
- out.writeBinary((byte[])o);
- } else if (sType.isCollection() || sType.isArray()) {
- out.writeElement(ARRAY.value, name);
- var child = out.createChild();
- child.startDocument();
- serializeArray(child, sType.isArray() ?
toList(sType.inner(), o) : (Collection)o, eType);
- out.writeChildDocument(child);
} else if (sType.isStreamable()) {
out.writeElement(ARRAY.value, name);
var child = out.createChild();
child.startDocument();
serializeArray(child, toListFromStreamable(o, sType),
eType);
out.writeChildDocument(child);
- } else if (sType.isCharSequence() || sType.isChar() ||
sType.isEnum()) {
- out.writeElement(STRING.value, name);
- out.writeString(trim(o));
} else {
out.writeElement(STRING.value, name);
out.writeString(toString(o));
diff --git
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/cbor/CborParserSession.java
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/cbor/CborParserSession.java
index 47abf51f8c..1bbe5a678b 100644
---
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/cbor/CborParserSession.java
+++
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/cbor/CborParserSession.java
@@ -246,32 +246,6 @@ public class CborParserSession extends
InputStreamParserSession {
if (sType.isObject()) {
// Do nothing.
- } else if (sType.isBoolean() || sType.isCharSequence()
|| sType.isChar() || sType.isNumber() || sType.isByteArray()) {
- o = convertToType(o, sType);
- } else if (sType.isDate()) {
- o = parseDate(String.valueOf(o), sType);
- } else if (sType.isCalendar()) {
- o = parseCalendar(String.valueOf(o), sType);
- } else if (sType.isTemporal()) {
- o = parseTemporal(String.valueOf(o), sType);
- } else if (sType.isDuration()) {
- o = parseDuration(String.valueOf(o));
- } else if (sType.isPeriod()) {
- o = parsePeriod(String.valueOf(o));
- } else if (sType.isMap()) {
- if (dt == MAP) {
- Map m =
(sType.canCreateNewInstance(outer) ? (Map)sType.newInstance(outer) :
newGenericMap(sType));
- for (var i = 0; i < len; i++) {
- Object key =
parseAnything(sType.getKeyType(), is, outer, pMeta);
- var vt = sType.getValueType();
- Object value =
parseAnything(vt, is, m, pMeta);
- setName(vt, value, key);
- m.put(key, value);
- }
- o = m;
- } else {
- throw new ParseException(this, "Invalid
data type {0} encountered for parse type {1}", dt, sType);
- }
} else if (nn(builder) ||
sType.canCreateNewBean(outer)) {
if (dt == MAP) {
BeanMap m = builder == null ?
newBeanMap(outer, sType.inner()) : toBeanMap(builder.create(this, eType));
@@ -299,6 +273,34 @@ public class CborParserSession extends
InputStreamParserSession {
} else {
throw new ParseException(this, "Invalid
data type {0} encountered for parse type {1}", dt, sType);
}
+ } else if (sType.isMap()) {
+ if (dt == MAP) {
+ Map m =
(sType.canCreateNewInstance(outer) ? (Map)sType.newInstance(outer) :
newGenericMap(sType));
+ for (var i = 0; i < len; i++) {
+ Object key =
parseAnything(sType.getKeyType(), is, outer, pMeta);
+ var vt = sType.getValueType();
+ Object value =
parseAnything(vt, is, m, pMeta);
+ setName(vt, value, key);
+ m.put(key, value);
+ }
+ o = m;
+ } else {
+ throw new ParseException(this, "Invalid
data type {0} encountered for parse type {1}", dt, sType);
+ }
+ } else if (sType.isBoolean() || sType.isCharSequence()
|| sType.isChar() || sType.isNumber() || sType.isByteArray()) {
+ // Merged scalar tier: one CBOR data type
(BOOLEAN/UINT/NINT/FLOAT/STRING/BINARY) covers
+ // many scalar Java types — the read already
happened above and convertToType narrows.
+ o = convertToType(o, sType);
+ } else if (sType.isDate()) {
+ o = parseDate(String.valueOf(o), sType);
+ } else if (sType.isCalendar()) {
+ o = parseCalendar(String.valueOf(o), sType);
+ } else if (sType.isTemporal()) {
+ o = parseTemporal(String.valueOf(o), sType);
+ } else if (sType.isDuration()) {
+ o = parseDuration(String.valueOf(o));
+ } else if (sType.isPeriod()) {
+ o = parsePeriod(String.valueOf(o));
} else if (sType.canCreateNewInstanceFromString(outer)
&& dt == STRING) {
o = sType.newInstanceFromString(outer, o ==
null ? "" : o.toString());
} else if (sType.isCollection()) {
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 eb0f894c04..2607e497eb 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
@@ -255,24 +255,8 @@ public class CborSerializerSession extends
OutputStreamSerializerSession {
if (o == null || (sType.isChar() && ((Character)o).charValue()
== 0))
out.appendNull();
- else if (sType.isBoolean())
- out.appendBoolean((Boolean)o);
- else if (sType.isNumber())
- out.appendNumber((Number)o);
- else if (sType.isDate())
- out.appendString(serializeDate((Date)o, sType));
- else if (sType.isCalendar())
- out.appendString(serializeCalendar(o, sType));
- else if (sType.isTemporal())
- out.appendString(serializeTemporal((TemporalAccessor)o,
sType));
- else if (sType.isDuration())
- appendDuration(out, (Duration)o);
- else if (sType.isPeriod())
- out.appendString(serializePeriod((Period)o));
else if (sType.isBean())
serializeBeanMap(out, toBeanMap(o), typeName);
- else if (sType.isUri() || (nn(pMeta) && pMeta.isUri()))
- out.appendString(resolveUri(o.toString()));
else if (sType.isMap()) {
if (o instanceof BeanMap o2)
serializeBeanMap(out, o2, typeName);
@@ -284,6 +268,22 @@ public class CborSerializerSession extends
OutputStreamSerializerSession {
out.appendBinary((byte[])o);
} else if (sType.isArray()) {
serializeCollection(out, toList(sType.inner(), o),
eType);
+ } else if (sType.isBoolean()) {
+ out.appendBoolean((Boolean)o);
+ } else if (sType.isNumber()) {
+ out.appendNumber((Number)o);
+ } else if (sType.isUri() || (nn(pMeta) && pMeta.isUri())) {
+ out.appendString(resolveUri(o.toString()));
+ } else if (sType.isDate()) {
+ out.appendString(serializeDate((Date)o, sType));
+ } else if (sType.isCalendar()) {
+ out.appendString(serializeCalendar(o, sType));
+ } else if (sType.isTemporal()) {
+ out.appendString(serializeTemporal((TemporalAccessor)o,
sType));
+ } else if (sType.isDuration()) {
+ appendDuration(out, (Duration)o);
+ } else if (sType.isPeriod()) {
+ out.appendString(serializePeriod((Period)o));
} else if (sType.isStreamable()) {
serializeCollection(out, toListFromStreamable(o,
sType), eType);
} else if (sType.isReader()) {
diff --git
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/hjson/HjsonSerializerSession.java
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/hjson/HjsonSerializerSession.java
index 38f70777c4..32a7721991 100644
---
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/hjson/HjsonSerializerSession.java
+++
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/hjson/HjsonSerializerSession.java
@@ -241,8 +241,21 @@ public class HjsonSerializerSession extends
WriterSerializerSession {
if (o == null || (sType.isChar() && ((Character) o).charValue()
== 0)) {
out.w("null");
+ } else if (sType.isBean()) {
+ serializeBeanMap(out, toBeanMap(o),
getBeanTypeName(this, eType, aType, pMeta), false);
+ } else if (sType.isMap()) {
+ if (o instanceof BeanMap o2)
+ serializeBeanMap(out, o2, getBeanTypeName(this,
eType, aType, pMeta), false);
+ else
+ serializeMap(out, (Map) o, eType, false);
+ } else if (sType.isCollection()) {
+ serializeCollection(out, (Collection) o, eType);
+ } else if (sType.isArray()) {
+ serializeCollection(out, toList(sType.inner(), o),
eType);
} else if (sType.isNumber() || sType.isBoolean()) {
out.append(o);
+ } else if (sType.isUri() || (nn(pMeta) && pMeta.isUri())) {
+ serializeString(out, getUriResolver().resolve(o));
} else if (sType.isDate()) {
serializeString(out, serializeDate((Date)o, sType));
} else if (sType.isCalendar()) {
@@ -257,19 +270,6 @@ public class HjsonSerializerSession extends
WriterSerializerSession {
serializeString(out, value);
} else if (sType.isPeriod()) {
serializeString(out, serializePeriod((Period)o));
- } else if (sType.isBean()) {
- serializeBeanMap(out, toBeanMap(o),
getBeanTypeName(this, eType, aType, pMeta), false);
- } else if (sType.isUri() || (nn(pMeta) && pMeta.isUri())) {
- serializeString(out, getUriResolver().resolve(o));
- } else if (sType.isMap()) {
- if (o instanceof BeanMap o2)
- serializeBeanMap(out, o2, getBeanTypeName(this,
eType, aType, pMeta), false);
- else
- serializeMap(out, (Map) o, eType, false);
- } else if (sType.isCollection()) {
- serializeCollection(out, (Collection) o, eType);
- } else if (sType.isArray()) {
- serializeCollection(out, toList(sType.inner(), o),
eType);
} else if (sType.isStreamable()) {
serializeStreamable(out, o, sType, eType);
} else if (sType.isReader()) {
diff --git
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/hocon/HoconSerializerSession.java
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/hocon/HoconSerializerSession.java
index ab87213f33..7815e0ae39 100644
---
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/hocon/HoconSerializerSession.java
+++
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/hocon/HoconSerializerSession.java
@@ -266,9 +266,23 @@ public class HoconSerializerSession extends
WriterSerializerSession {
if (o == null || (sType.isChar() && ((Character) o).charValue()
== 0)) {
hw.w("null");
} else if (o instanceof byte[] bytes) {
+ // byte[] gate: encode as Base64 before isArray would
otherwise route it as a generic array.
serializeString(hw,
Base64.getEncoder().encodeToString(bytes));
+ } else if (sType.isBean()) {
+ serializeBeanMap(hw, toBeanMap(o),
getBeanTypeName(this, eType, aType, pMeta), false);
+ } else if (sType.isMap()) {
+ if (o instanceof BeanMap o2)
+ serializeBeanMap(hw, o2, getBeanTypeName(this,
eType, aType, pMeta), false);
+ else
+ serializeMap(hw, (Map) o, eType, false);
+ } else if (sType.isCollection()) {
+ serializeCollection(hw, (Collection) o, eType);
+ } else if (sType.isArray()) {
+ serializeCollection(hw, toList(sType.inner(), o),
eType);
} else if (sType.isNumber() || sType.isBoolean()) {
hw.append(o);
+ } else if (sType.isUri() || (nn(pMeta) && pMeta.isUri())) {
+ serializeString(hw, getUriResolver().resolve(o));
} else if (sType.isDate()) {
serializeString(hw, serializeDate((Date)o, sType));
} else if (sType.isCalendar()) {
@@ -283,19 +297,6 @@ public class HoconSerializerSession extends
WriterSerializerSession {
serializeString(hw, value);
} else if (sType.isPeriod()) {
serializeString(hw, serializePeriod((Period)o));
- } else if (sType.isBean()) {
- serializeBeanMap(hw, toBeanMap(o),
getBeanTypeName(this, eType, aType, pMeta), false);
- } else if (sType.isUri() || (nn(pMeta) && pMeta.isUri())) {
- serializeString(hw, getUriResolver().resolve(o));
- } else if (sType.isMap()) {
- if (o instanceof BeanMap o2)
- serializeBeanMap(hw, o2, getBeanTypeName(this,
eType, aType, pMeta), false);
- else
- serializeMap(hw, (Map) o, eType, false);
- } else if (sType.isCollection()) {
- serializeCollection(hw, (Collection) o, eType);
- } else if (sType.isArray()) {
- serializeCollection(hw, toList(sType.inner(), o),
eType);
} else if (sType.isStreamable()) {
serializeStreamable(hw, o, sType, eType);
} else if (sType.isReader()) {
diff --git
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/html/HtmlParserSession.java
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/html/HtmlParserSession.java
index 1d47cf1c0c..0a36efdf03 100644
---
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/html/HtmlParserSession.java
+++
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/html/HtmlParserSession.java
@@ -351,10 +351,10 @@ public class HtmlParserSession extends XmlParserSession {
o = text;
else if (sType.isChar())
o = parseCharacter(text);
- else if (sType.isBoolean())
- o = Boolean.parseBoolean(text);
else if (sType.isNumber())
o = parseNumber(text, (Class<? extends
Number>)eType.inner());
+ else if (sType.isBoolean())
+ o = Boolean.parseBoolean(text);
else if (sType.isDate())
o = parseDate(text, sType);
else if (sType.isCalendar())
@@ -440,14 +440,14 @@ public class HtmlParserSession extends XmlParserSession {
if (typeName.equals(TAG_object)) {
if (sType.isObject()) {
o = parseIntoMap(r,
newGenericMap(sType), sType.getKeyType(), sType.getValueType(), pMeta);
- } else if (sType.isMap()) {
- o = parseIntoMap(r,
(Map)(sType.canCreateNewInstance(outer) ? sType.newInstance(outer) :
newGenericMap(sType)), sType.getKeyType(), sType.getValueType(), pMeta);
} else if (nn(builder)) {
BeanMap m =
toBeanMap(builder.create(this, eType));
o = builder.build(this,
parseIntoBean(r, m).getBean(), eType);
} else if (sType.canCreateNewBean(outer)) {
BeanMap m = newBeanMap(outer,
sType.inner());
o = parseIntoBean(r, m).getBean();
+ } else if (sType.isMap()) {
+ o = parseIntoMap(r,
(Map)(sType.canCreateNewInstance(outer) ? sType.newInstance(outer) :
newGenericMap(sType)), sType.getKeyType(), sType.getValueType(), pMeta);
} else if
(nn(sType.getProxyInvocationHandler())) {
BeanMap m = newBeanMap(outer,
sType.inner());
o = parseIntoBean(r, m).getBean();
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 54cf4c0e86..5c36c81c75 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
@@ -1049,6 +1049,40 @@ public class HtmlSerializerSession extends
XmlSerializerSession {
out.tag("null");
cr = CR_MIXED;
+ } else if (sType.isBean()) {
+ BeanMap m = toBeanMap(o);
+ if (getAnnotationProvider().has(HtmlLink.class,
aType)) {
+ var uriProperty = Value.<String>empty();
+ var nameProperty =
Value.<String>empty();
+ aType.forEachAnnotation(HtmlLink.class,
x -> ne(x.uriProperty()), x -> uriProperty.set(x.uriProperty()));
+ aType.forEachAnnotation(HtmlLink.class,
x -> ne(x.nameProperty()), x -> nameProperty.set(x.nameProperty()));
+ Object urlProp =
m.get(uriProperty.orElse(""));
+ Object nameProp =
m.get(nameProperty.orElse(""));
+
+ out.oTag("a").attrUri("href",
urlProp).w('>').text(nameProp).eTag("a");
+ cr = CR_MIXED;
+ } else {
+ out.nlIf(! isRoot, xIndent + 2);
+ serializeBeanMap(out, m, eType, pMeta);
+ }
+
+ } else if (sType.isMap() || (nn(wType) &&
wType.isMap())) {
+ out.nlIf(! isRoot, xIndent + 1);
+ if (o instanceof BeanMap o2)
+ serializeBeanMap(out, o2, eType, pMeta);
+ else
+ serializeMap(out, (Map)o, sType,
eType.getKeyType(), eType.getValueType(), typeName, pMeta);
+
+ } else if (sType.isCollection() || sType.isArray() ||
(nn(wType) && wType.isCollection())) {
+ out.nlIf(! isRoot, xIndent + 1);
+ serializeCollection(out, o, sType, eType, name,
pMeta);
+
+ } else if (sType.isStreamable()) {
+ // HTML must inspect elements to decide table
vs. list layout (getTableHeaders), so materialization is unavoidable.
+ out.nlIf(! isRoot, xIndent + 1);
+ var list = toListFromStreamable(o, sType);
+ serializeCollection(out, list,
getClassMeta(List.class), eType, name, pMeta);
+
} else if (sType.isNumber()) {
if (eType.isNumber() && ! (isRoot &&
addJsonTags))
out.append(o);
@@ -1063,6 +1097,13 @@ public class HtmlSerializerSession extends
XmlSerializerSession {
out.sTag("boolean").append(o).eTag("boolean");
cr = CR_MIXED;
+ } else if (isUri(sType, pMeta, o)) {
+ String label = getAnchorText(pMeta, o);
+ out.oTag("a").attrUri("href", o).w('>');
+ out.text(label);
+ out.eTag("a");
+ cr = CR_MIXED;
+
} else if (sType.isDate()) {
String s = serializeDate((Date)o, sType);
if (isRoot && addJsonTags)
@@ -1103,47 +1144,6 @@ public class HtmlSerializerSession extends
XmlSerializerSession {
out.text(s);
cr = CR_MIXED;
- } else if (sType.isMap() || (nn(wType) &&
wType.isMap())) {
- out.nlIf(! isRoot, xIndent + 1);
- if (o instanceof BeanMap o2)
- serializeBeanMap(out, o2, eType, pMeta);
- else
- serializeMap(out, (Map)o, sType,
eType.getKeyType(), eType.getValueType(), typeName, pMeta);
-
- } else if (sType.isBean()) {
- BeanMap m = toBeanMap(o);
- if (getAnnotationProvider().has(HtmlLink.class,
aType)) {
- var uriProperty = Value.<String>empty();
- var nameProperty =
Value.<String>empty();
- aType.forEachAnnotation(HtmlLink.class,
x -> ne(x.uriProperty()), x -> uriProperty.set(x.uriProperty()));
- aType.forEachAnnotation(HtmlLink.class,
x -> ne(x.nameProperty()), x -> nameProperty.set(x.nameProperty()));
- Object urlProp =
m.get(uriProperty.orElse(""));
- Object nameProp =
m.get(nameProperty.orElse(""));
-
- out.oTag("a").attrUri("href",
urlProp).w('>').text(nameProp).eTag("a");
- cr = CR_MIXED;
- } else {
- out.nlIf(! isRoot, xIndent + 2);
- serializeBeanMap(out, m, eType, pMeta);
- }
-
- } else if (sType.isCollection() || sType.isArray() ||
(nn(wType) && wType.isCollection())) {
- out.nlIf(! isRoot, xIndent + 1);
- serializeCollection(out, o, sType, eType, name,
pMeta);
-
- } else if (sType.isStreamable()) {
- // HTML must inspect elements to decide table
vs. list layout (getTableHeaders), so materialization is unavoidable.
- out.nlIf(! isRoot, xIndent + 1);
- var list = toListFromStreamable(o, sType);
- serializeCollection(out, list,
getClassMeta(List.class), eType, name, pMeta);
-
- } else if (isUri(sType, pMeta, o)) {
- String label = getAnchorText(pMeta, o);
- out.oTag("a").attrUri("href", o).w('>');
- out.text(label);
- out.eTag("a");
- cr = CR_MIXED;
-
} else {
if (isRoot && addJsonTags)
out.sTag(CONST_string).text(toString(o)).eTag(CONST_string);
diff --git
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/ini/IniSerializerSession.java
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/ini/IniSerializerSession.java
index 186974204b..8acf67922d 100644
---
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/ini/IniSerializerSession.java
+++
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/ini/IniSerializerSession.java
@@ -263,10 +263,16 @@ public class IniSerializerSession extends
WriterSerializerSession {
}
private String formatSimpleValue(Object value, ClassMeta<?> aType)
throws SerializeException {
+ if (aType.isCharSequence() || aType.isUri()) {
+ var s = toString(value);
+ return needsQuoting(s) ? "'" + s.replace("'", "''") +
"'" : s;
+ }
if (aType.isNumber())
return value.toString();
if (aType.isBoolean())
return ((Boolean)value).toString();
+ if (aType.isEnum())
+ return ((Enum<?>)value).name();
if (aType.isDate())
return serializeDate((Date)value, aType);
if (aType.isCalendar())
@@ -277,12 +283,6 @@ public class IniSerializerSession extends
WriterSerializerSession {
return serializeDuration((Duration)value);
if (aType.isPeriod())
return serializePeriod((Period)value);
- if (aType.isEnum())
- return ((Enum<?>)value).name();
- if (aType.isCharSequence() || aType.isUri()) {
- var s = toString(value);
- return needsQuoting(s) ? "'" + s.replace("'", "''") +
"'" : s;
- }
return toString(value);
}
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 1bb5dcfb0e..df094f3a1a 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
@@ -283,24 +283,12 @@ public class JsonParserSession extends
ReaderParserSession {
parseKeyword("false", r);
o = Boolean.FALSE;
}
- } else if (sType.isBoolean()) {
- o = parseBoolean(r);
- } else if (sType.isCharSequence()) {
- o = parseString(r);
- } else if (sType.isChar()) {
- o = parseCharacter(parseString(r));
- } else if (sType.isNumber()) {
- o = parseNumber(r, (Class<? extends
Number>)sType.inner());
- } else if (sType.isDate()) {
- o = parseDate(parseString(r), sType);
- } else if (sType.isCalendar()) {
- o = parseCalendar(parseString(r), sType);
- } else if (sType.isTemporal()) {
- o = parseTemporal(parseString(r), sType);
- } else if (sType.isDuration()) {
- o = parseDuration(parseString(r));
- } else if (sType.isPeriod()) {
- o = parsePeriod(parseString(r));
+ } else if (nn(builder)) {
+ var m = toBeanMap(builder.create(this, eType));
+ o = builder.build(this, parseIntoBeanMap2(r,
m).getBean(), eType);
+ } else if (sType.canCreateNewBean(outer)) {
+ var m = newBeanMap(outer, sType.inner());
+ o = parseIntoBeanMap2(r, m).getBean();
} else if (sType.isMap()) {
Map m = (sType.canCreateNewInstance(outer) ?
(Map)sType.newInstance(outer) : newGenericMap(sType));
o = parseIntoMap2(r, m, sType.getKeyType(),
sType.getValueType(), pMeta);
@@ -313,14 +301,6 @@ public class JsonParserSession extends ReaderParserSession
{
Collection l =
(sType.canCreateNewInstance(outer) ? (Collection)sType.newInstance() :
newGenericList());
o = parseIntoCollection2(r, l, sType, pMeta);
}
- } else if (nn(builder)) {
- var m = toBeanMap(builder.create(this, eType));
- o = builder.build(this, parseIntoBeanMap2(r,
m).getBean(), eType);
- } else if (sType.canCreateNewBean(outer)) {
- var m = newBeanMap(outer, sType.inner());
- o = parseIntoBeanMap2(r, m).getBean();
- } else if (sType.canCreateNewInstanceFromString(outer) && (c ==
'\'' || c == '"')) {
- o = sType.newInstanceFromString(outer, parseString(r));
} else if (sType.isArray() || sType.isArgs()) {
if (c == '{') {
var m = newGenericMap();
@@ -330,6 +310,26 @@ public class JsonParserSession extends ReaderParserSession
{
var l = (ArrayList)parseIntoCollection2(r,
list(), sType, pMeta);
o = toArray(sType, l);
}
+ } else if (sType.isCharSequence()) {
+ o = parseString(r);
+ } else if (sType.isChar()) {
+ o = parseCharacter(parseString(r));
+ } else if (sType.isNumber()) {
+ o = parseNumber(r, (Class<? extends
Number>)sType.inner());
+ } else if (sType.isBoolean()) {
+ o = parseBoolean(r);
+ } else if (sType.isDate()) {
+ o = parseDate(parseString(r), sType);
+ } else if (sType.isCalendar()) {
+ o = parseCalendar(parseString(r), sType);
+ } else if (sType.isTemporal()) {
+ o = parseTemporal(parseString(r), sType);
+ } else if (sType.isDuration()) {
+ o = parseDuration(parseString(r));
+ } else if (sType.isPeriod()) {
+ o = parsePeriod(parseString(r));
+ } else if (sType.canCreateNewInstanceFromString(outer) && (c ==
'\'' || c == '"')) {
+ o = sType.newInstanceFromString(outer, parseString(r));
} else if (c == '{') {
Map m = newGenericMap();
parseIntoMap2(r, m, sType.getKeyType(),
sType.getValueType(), pMeta);
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 3d54b02020..c213124b70 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
@@ -446,8 +446,21 @@ public class JsonSerializerSession extends
WriterSerializerSession {
// '\0' characters are considered null.
if (o == null || (sType.isChar() && ((Character)o).charValue()
== 0)) {
out.append("null");
+ } else if (sType.isBean()) {
+ serializeBeanMap(out, toBeanMap(o), typeName);
+ } else if (sType.isMap()) {
+ if (o instanceof BeanMap o2)
+ serializeBeanMap(out, o2, typeName);
+ else
+ serializeMap(out, (Map)o, eType);
+ } else if (sType.isCollection()) {
+ serializeCollection(out, (Collection)o, eType);
+ } else if (sType.isArray()) {
+ serializeCollection(out, toList(sType.inner(), o),
eType);
} else if (sType.isNumber() || sType.isBoolean()) {
out.append(o);
+ } else if (sType.isUri() || (nn(pMeta) && pMeta.isUri())) {
+ out.uriValue(o);
} else if (sType.isDate()) {
out.stringValue(serializeDate((Date)o, sType));
} else if (sType.isCalendar()) {
@@ -462,19 +475,6 @@ public class JsonSerializerSession extends
WriterSerializerSession {
out.stringValue(value);
} else if (sType.isPeriod()) {
out.stringValue(serializePeriod((Period)o));
- } else if (sType.isBean()) {
- serializeBeanMap(out, toBeanMap(o), typeName);
- } else if (sType.isUri() || (nn(pMeta) && pMeta.isUri())) {
- out.uriValue(o);
- } else if (sType.isMap()) {
- if (o instanceof BeanMap o2)
- serializeBeanMap(out, o2, typeName);
- else
- serializeMap(out, (Map)o, eType);
- } else if (sType.isCollection()) {
- serializeCollection(out, (Collection)o, eType);
- } else if (sType.isArray()) {
- serializeCollection(out, toList(sType.inner(), o),
eType);
} else if (sType.isStreamable()) {
serializeStreamable(out, o, sType, eType);
} else if (sType.isReader()) {
diff --git
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/markdown/MarkdownParserSession.java
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/markdown/MarkdownParserSession.java
index 1e490f2fc8..f63ebc1b2f 100644
---
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/markdown/MarkdownParserSession.java
+++
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/markdown/MarkdownParserSession.java
@@ -678,16 +678,16 @@ public class MarkdownParserSession extends
ReaderParserSession {
// MarshallingContext.get<Format>() hint reaches the wire-form
coercion. Without this the
// fall-through to convertToType(val, eType) below would route
a bare numeric cell through a
// generic Number → T coercion (e.g. Duration.ofMillis(long))
that drops the format hint.
- if (eType.isDuration())
- return (T) parseDuration(val);
- if (eType.isPeriod())
- return (T) parsePeriod(val);
if (eType.isDate())
return parseDate(val, eType);
if (eType.isCalendar())
return parseCalendar(val, eType);
if (eType.isTemporal())
return parseTemporal(val, eType);
+ if (eType.isDuration())
+ return (T) parseDuration(val);
+ if (eType.isPeriod())
+ return (T) parsePeriod(val);
try {
return convertToType(val, eType);
diff --git
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/markdown/MarkdownSerializerSession.java
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/markdown/MarkdownSerializerSession.java
index 6352dcb0de..4b15c6bb59 100644
---
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/markdown/MarkdownSerializerSession.java
+++
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/markdown/MarkdownSerializerSession.java
@@ -546,6 +546,13 @@ public class MarkdownSerializerSession extends
WriterSerializerSession {
cm = swap.getSwapClassMeta(this);
}
+ if (cm.isCharSequence() || cm.isEnum()) {
+ var s = toString(o);
+ if (isAmbiguousString(s, nullValue))
+ return "`'" + escapeJson5String(s) + "'`";
+ return MarkdownWriter.escapeCell(s);
+ }
+
if (cm.isNumber() || cm.isBoolean())
return o.toString();
@@ -564,13 +571,6 @@ public class MarkdownSerializerSession extends
WriterSerializerSession {
if (cm.isPeriod())
return
MarkdownWriter.escapeCell(serializePeriod((Period)o));
- if (cm.isCharSequence() || cm.isEnum()) {
- var s = toString(o);
- if (isAmbiguousString(s, nullValue))
- return "`'" + escapeJson5String(s) + "'`";
- return MarkdownWriter.escapeCell(s);
- }
-
// Complex value: serialize as JSON5 in backticks — use
context-aware serializer for swaps
try {
var json5 = getJson5Serializer().serialize(o);
diff --git
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/msgpack/MsgPackParserSession.java
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/msgpack/MsgPackParserSession.java
index b42e2bfe85..bbb0faf272 100644
---
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/msgpack/MsgPackParserSession.java
+++
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/msgpack/MsgPackParserSession.java
@@ -241,32 +241,6 @@ public class MsgPackParserSession extends
InputStreamParserSession {
if (sType.isObject()) {
// Do nothing.
- } else if (sType.isBoolean() || sType.isCharSequence()
|| sType.isChar() || sType.isNumber() || sType.isByteArray()) {
- o = convertToType(o, sType);
- } else if (sType.isDate()) {
- o = parseDate(String.valueOf(o), sType);
- } else if (sType.isCalendar()) {
- o = parseCalendar(String.valueOf(o), sType);
- } else if (sType.isTemporal()) {
- o = parseTemporal(String.valueOf(o), sType);
- } else if (sType.isDuration()) {
- o = parseDuration(String.valueOf(o));
- } else if (sType.isPeriod()) {
- o = parsePeriod(String.valueOf(o));
- } else if (sType.isMap()) {
- if (dt == MAP) {
- Map m =
(sType.canCreateNewInstance(outer) ? (Map)sType.newInstance(outer) :
newGenericMap(sType));
- for (var i = 0; i < length; i++) {
- Object key =
parseAnything(sType.getKeyType(), is, outer, pMeta);
- var vt = sType.getValueType();
- Object value =
parseAnything(vt, is, m, pMeta);
- setName(vt, value, key);
- m.put(key, value);
- }
- o = m;
- } else {
- throw new ParseException(this, "Invalid
data type {0} encountered for parse type {1}", dt, sType);
- }
} else if (nn(builder) ||
sType.canCreateNewBean(outer)) {
if (dt == MAP) {
BeanMap m = builder == null ?
newBeanMap(outer, sType.inner()) : toBeanMap(builder.create(this, eType));
@@ -294,6 +268,34 @@ public class MsgPackParserSession extends
InputStreamParserSession {
} else {
throw new ParseException(this, "Invalid
data type {0} encountered for parse type {1}", dt, sType);
}
+ } else if (sType.isMap()) {
+ if (dt == MAP) {
+ Map m =
(sType.canCreateNewInstance(outer) ? (Map)sType.newInstance(outer) :
newGenericMap(sType));
+ for (var i = 0; i < length; i++) {
+ Object key =
parseAnything(sType.getKeyType(), is, outer, pMeta);
+ var vt = sType.getValueType();
+ Object value =
parseAnything(vt, is, m, pMeta);
+ setName(vt, value, key);
+ m.put(key, value);
+ }
+ o = m;
+ } else {
+ throw new ParseException(this, "Invalid
data type {0} encountered for parse type {1}", dt, sType);
+ }
+ } else if (sType.isBoolean() || sType.isCharSequence()
|| sType.isChar() || sType.isNumber() || sType.isByteArray()) {
+ // Merged scalar tier: one wire-type
(BOOLEAN/INT/LONG/FLOAT/DOUBLE/STRING/BIN) covers
+ // many scalar Java types — the read already
happened above and convertToType narrows.
+ o = convertToType(o, sType);
+ } else if (sType.isDate()) {
+ o = parseDate(String.valueOf(o), sType);
+ } else if (sType.isCalendar()) {
+ o = parseCalendar(String.valueOf(o), sType);
+ } else if (sType.isTemporal()) {
+ o = parseTemporal(String.valueOf(o), sType);
+ } else if (sType.isDuration()) {
+ o = parseDuration(String.valueOf(o));
+ } else if (sType.isPeriod()) {
+ o = parsePeriod(String.valueOf(o));
} else if (sType.canCreateNewInstanceFromString(outer)
&& dt == STRING) {
o = sType.newInstanceFromString(outer, o ==
null ? "" : o.toString());
} else if (sType.isCollection()) {
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 87cef9b4a1..51bbb7bdf2 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
@@ -262,24 +262,8 @@ public class MsgPackSerializerSession extends
OutputStreamSerializerSession {
// '\0' characters are considered null.
if (o == null || (sType.isChar() && ((Character)o).charValue()
== 0))
out.appendNull();
- else if (sType.isBoolean())
- out.appendBoolean((Boolean)o);
- else if (sType.isNumber())
- out.appendNumber((Number)o);
- else if (sType.isDate())
- out.appendString(serializeDate((Date)o, sType));
- else if (sType.isCalendar())
- out.appendString(serializeCalendar(o, sType));
- else if (sType.isTemporal())
- out.appendString(serializeTemporal((TemporalAccessor)o,
sType));
- else if (sType.isDuration())
- appendDuration(out, (Duration)o);
- else if (sType.isPeriod())
- out.appendString(serializePeriod((Period)o));
else if (sType.isBean())
serializeBeanMap(out, toBeanMap(o), typeName);
- else if (sType.isUri() || (nn(pMeta) && pMeta.isUri()))
- out.appendString(resolveUri(o.toString()));
else if (sType.isMap()) {
if (o instanceof BeanMap o2)
serializeBeanMap(out, o2, typeName);
@@ -291,6 +275,22 @@ public class MsgPackSerializerSession extends
OutputStreamSerializerSession {
out.appendBinary((byte[])o);
} else if (sType.isArray()) {
serializeCollection(out, toList(sType.inner(), o),
eType);
+ } else if (sType.isBoolean()) {
+ out.appendBoolean((Boolean)o);
+ } else if (sType.isNumber()) {
+ out.appendNumber((Number)o);
+ } else if (sType.isUri() || (nn(pMeta) && pMeta.isUri())) {
+ out.appendString(resolveUri(o.toString()));
+ } else if (sType.isDate()) {
+ out.appendString(serializeDate((Date)o, sType));
+ } else if (sType.isCalendar()) {
+ out.appendString(serializeCalendar(o, sType));
+ } else if (sType.isTemporal()) {
+ out.appendString(serializeTemporal((TemporalAccessor)o,
sType));
+ } else if (sType.isDuration()) {
+ appendDuration(out, (Duration)o);
+ } else if (sType.isPeriod()) {
+ out.appendString(serializePeriod((Period)o));
} else if (sType.isStreamable()) {
// MsgPack protocol requires array size in header
(startArray(size)), so materialization is unavoidable.
serializeCollection(out, toListFromStreamable(o,
sType), eType);
diff --git
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/proto/ProtoParserSession.java
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/proto/ProtoParserSession.java
index 16a89252a7..c3fa4f7c45 100644
---
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/proto/ProtoParserSession.java
+++
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/proto/ProtoParserSession.java
@@ -311,28 +311,30 @@ public class ProtoParserSession extends
ReaderParserSession {
private Object convertValue(Object val, ClassMeta<?> targetType) throws
ParseException, ExecutableException {
if (val == null)
return null;
- if (val instanceof Map val2 &&
JsonMap.class.isAssignableFrom(targetType.inner()))
- return toJsonMap(val2);
- if (val instanceof Map val2 && targetType.isBean()) {
- var typeName = (String)
val2.get(getBeanTypePropertyName(targetType));
- var beanType = targetType;
- if (typeName != null && !typeName.isEmpty()) {
- var resolved = getClassMeta(typeName, null,
targetType);
- if (resolved != null)
- beanType = resolved;
+ if (val instanceof Map val2) {
+ if (JsonMap.class.isAssignableFrom(targetType.inner()))
+ return toJsonMap(val2);
+ if (targetType.isBean()) {
+ var typeName = (String)
val2.get(getBeanTypePropertyName(targetType));
+ var beanType = targetType;
+ if (typeName != null && !typeName.isEmpty()) {
+ var resolved = getClassMeta(typeName,
null, targetType);
+ if (resolved != null)
+ beanType = resolved;
+ }
+ var child =
toBeanMap(beanType.newInstance(getOuter()));
+ populateBeanMap(child, val2);
+ return child.getBean();
+ }
+ if (targetType.isMap()) {
+ // When the bean property's declared key type
is non-String (e.g. Map<TestEnum,String>),
+ // route through the converter's Map→Map path
so keys are coerced to the declared type.
+ // toJsonMap unconditionally toString-keys the
entries which loses the enum/typed key (Bug #7b).
+ var keyType = targetType.getKeyType();
+ if (keyType != null && !keyType.isObject() &&
!keyType.isString())
+ return convertToMemberType(null, val2,
targetType);
+ return toJsonMap(val2);
}
- var child = toBeanMap(beanType.newInstance(getOuter()));
- populateBeanMap(child, val2);
- return child.getBean();
- }
- if (val instanceof Map val2 && targetType.isMap()) {
- // When the bean property's declared key type is
non-String (e.g. Map<TestEnum,String>),
- // route through the converter's Map→Map path so keys
are coerced to the declared type.
- // toJsonMap unconditionally toString-keys the entries
which loses the enum/typed key (Bug #7b).
- var keyType = targetType.getKeyType();
- if (keyType != null && !keyType.isObject() &&
!keyType.isString())
- return convertToMemberType(null, val2,
targetType);
- return toJsonMap(val2);
}
if (val instanceof List val2 &&
targetType.isCollectionOrArray()) {
var elType = targetType.getElementType();
@@ -341,8 +343,12 @@ public class ProtoParserSession extends
ReaderParserSession {
result.add(convertValue(item, elType));
return targetType.isArray() ? toArray(targetType,
result) : result;
}
- if (val instanceof Number val2 && targetType.isNumber())
- return convertToMemberType(null, val2, targetType);
+ if (val instanceof Number val2) {
+ if (targetType.isNumber())
+ return convertToMemberType(null, val2,
targetType);
+ if (targetType.isDateOrCalendarOrTemporal())
+ return
Iso8601Utils.fromEpochMillis(val2.longValue(), targetType, getTimeZone());
+ }
if (val instanceof CharSequence val2) {
if (targetType.isDate())
return parseDate(val2.toString(), targetType);
@@ -375,8 +381,6 @@ public class ProtoParserSession extends ReaderParserSession
{
bytes[i] = (byte) s.charAt(i);
return bytes;
}
- if (val instanceof Number val2 &&
targetType.isDateOrCalendarOrTemporal())
- return Iso8601Utils.fromEpochMillis(val2.longValue(),
targetType, getTimeZone());
return convertToMemberType(null, val, targetType);
}
}
diff --git
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/proto/ProtoSerializerSession.java
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/proto/ProtoSerializerSession.java
index 25521f4bd3..71eb94bfbd 100644
---
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/proto/ProtoSerializerSession.java
+++
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/proto/ProtoSerializerSession.java
@@ -449,6 +449,8 @@ public class ProtoSerializerSession extends
WriterSerializerSession {
out.integerValue(((Number) value).longValue());
} else if (type.isBoolean()) {
out.booleanValue((Boolean) value);
+ } else if (type.isEnum()) {
+ out.enumValue(((Enum<?>) value).name());
} else if (type.isDate()) {
out.stringValue(serializeDate((Date)value, type));
} else if (type.isCalendar()) {
@@ -459,8 +461,6 @@ public class ProtoSerializerSession extends
WriterSerializerSession {
out.stringValue(serializeDuration((Duration)value));
} else if (type.isPeriod()) {
out.stringValue(serializePeriod((Period)value));
- } else if (type.isEnum()) {
- out.enumValue(((Enum<?>) value).name());
} else if (value instanceof byte[] value2) {
out.bytesValue(value2);
} else {
diff --git
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/toml/TomlParserSession.java
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/toml/TomlParserSession.java
index b4871df958..95bdbe95f7 100644
---
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/toml/TomlParserSession.java
+++
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/toml/TomlParserSession.java
@@ -392,13 +392,14 @@ public class TomlParserSession extends
ReaderParserSession {
String nv = ctx != null ? ctx.getNullValue() : null;
if (val instanceof String s && nv != null && s.equals(nv))
return null;
- if (val instanceof Map map &&
JsonMap.class.isAssignableFrom(targetType.inner())) {
- return toJsonMap(map);
- }
- if (val instanceof Map map && targetType.isBean()) {
- BeanMap<?> child =
toBeanMap(targetType.newInstance(getOuter()));
- populateBeanMap(child, map);
- return child.getBean();
+ if (val instanceof Map map) {
+ if (JsonMap.class.isAssignableFrom(targetType.inner()))
+ return toJsonMap(map);
+ if (targetType.isBean()) {
+ BeanMap<?> child =
toBeanMap(targetType.newInstance(getOuter()));
+ populateBeanMap(child, map);
+ return child.getBean();
+ }
}
if (val instanceof List list &&
targetType.isCollectionOrArray()) {
ClassMeta<?> elType = targetType.getElementType();
@@ -408,26 +409,14 @@ public class TomlParserSession extends
ReaderParserSession {
}
return targetType.isArray() ? toArray(targetType,
result) : result;
}
- if (val instanceof Number && targetType.isNumber())
- return convertToMemberType(null, val, targetType);
- if (val instanceof String string) {
- if (targetType.isDate())
- return parseDate(string, targetType);
- if (targetType.isCalendar())
- return parseCalendar(string, targetType);
- if (targetType.isTemporal())
- return parseTemporal(string, targetType);
- if (targetType.isDuration())
- return parseDuration(string);
- if (targetType.isPeriod())
- return parsePeriod(string);
- }
// Bare numeric wire literals (e.g. "2024", "8100000000000")
arrive here as Number values
// from the TOML tokenizer. Route them through the
format-aware parsers so the configured
// MarshallingContext.get<Format>() hint (NANOS, ISO_YEAR,
MILLIS, …) reaches the coercion.
// Without this routing the generic Number → T coercion below
would silently drop the hint
// (e.g. treating Long(2024) as epoch-millis →
1970-01-01T00:00:02.024Z instead of year 2024).
if (val instanceof Number num) {
+ if (targetType.isNumber())
+ return convertToMemberType(null, num,
targetType);
if (targetType.isDuration())
return parseDuration(num.toString());
if (targetType.isPeriod())
@@ -439,6 +428,18 @@ public class TomlParserSession extends ReaderParserSession
{
if (targetType.isTemporal())
return parseTemporal(num.toString(),
targetType);
}
+ if (val instanceof String string) {
+ if (targetType.isDate())
+ return parseDate(string, targetType);
+ if (targetType.isCalendar())
+ return parseCalendar(string, targetType);
+ if (targetType.isTemporal())
+ return parseTemporal(string, targetType);
+ if (targetType.isDuration())
+ return parseDuration(string);
+ if (targetType.isPeriod())
+ return parsePeriod(string);
+ }
// Native TOML datetime literals (Z-zoned / offset / local) are
returned by TomlTokenizer as
// java.time.OffsetDateTime / LocalDateTime / LocalDate /
LocalTime objects. Re-stringify
// through the temporal's own ISO toString() and route through
parseTemporal so the
diff --git
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/toml/TomlSerializerSession.java
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/toml/TomlSerializerSession.java
index 82ff3c188f..0ae9f722cf 100644
---
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/toml/TomlSerializerSession.java
+++
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/toml/TomlSerializerSession.java
@@ -285,13 +285,32 @@ public class TomlSerializerSession extends
WriterSerializerSession {
w.stringValue(ctx.getNullValue());
return;
}
- if (aType.isNumber()) {
+ if (aType.isBean()) {
+ BeanMap<?> bm = toBeanMap(value);
+ if (shouldUseInlineTable(bm)) {
+ w.inlineTableStart();
+ boolean[] first = {true};
+ Predicate<Object> checkNull = x ->
isKeepNullProperties() || nn(x);
+ bm.forEachValue(checkNull, (pm, k, v, th) -> {
+ if (!first[0]) w.w(", ");
+ first[0] = false;
+ writeKey(w, k);
+ w.w(" = ");
+ writeValue(w, v, (ClassMeta<?>)
pm.getBeanInfo(), pm);
+ });
+ w.inlineTableEnd();
+ } else {
+ serializeBean(w, bm, "");
+ }
+ } else if (aType.isNumber()) {
if (value instanceof Float || value instanceof Double)
w.floatValue(((Number)value).doubleValue());
else
w.integerValue(((Number)value).longValue());
} else if (aType.isBoolean()) {
w.booleanValue((Boolean)value);
+ } else if (aType.isEnum()) {
+ w.stringValue(((Enum<?>)value).name());
} else if (aType.isDate()) {
w.w(serializeDate((Date)value, aType));
} else if (aType.isCalendar()) {
@@ -306,25 +325,6 @@ public class TomlSerializerSession extends
WriterSerializerSession {
w.stringValue(serializeDuration((Duration)value));
} else if (aType.isPeriod()) {
w.stringValue(serializePeriod((Period)value));
- } else if (aType.isEnum()) {
- w.stringValue(((Enum<?>)value).name());
- } else if (aType.isBean()) {
- BeanMap<?> bm = toBeanMap(value);
- if (shouldUseInlineTable(bm)) {
- w.inlineTableStart();
- boolean[] first = {true};
- Predicate<Object> checkNull = x ->
isKeepNullProperties() || nn(x);
- bm.forEachValue(checkNull, (pm, k, v, th) -> {
- if (!first[0]) w.w(", ");
- first[0] = false;
- writeKey(w, k);
- w.w(" = ");
- writeValue(w, v, (ClassMeta<?>)
pm.getBeanInfo(), pm);
- });
- w.inlineTableEnd();
- } else {
- serializeBean(w, bm, "");
- }
} else if (value.getClass().isArray()) {
// Bug #11/#12 a04 residual (generalized): when aType
arrives erased — most commonly
// because the value is a typed List<T[]> bean-property
element and the parent List's
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 0da857a8c3..f2ef15d15e 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
@@ -392,24 +392,14 @@ public class UonParserSession extends ReaderParserSession
implements HttpPartPar
o = s;
}
}
- } else if (sType.isBoolean()) {
- o = parseBoolean(r);
- } else if (sType.isCharSequence()) {
- o = parseString(r, isUrlParamValue);
- } else if (sType.isChar()) {
- o = parseCharacter(parseString(r, isUrlParamValue));
- } else if (sType.isNumber()) {
- o = parseNumber(r, (Class<? extends
Number>)sType.inner());
- } else if (sType.isDate()) {
- o = parseDate(parseString(r, isUrlParamValue), sType);
- } else if (sType.isCalendar()) {
- o = parseCalendar(parseString(r, isUrlParamValue),
sType);
- } else if (sType.isTemporal()) {
- o = parseTemporal(parseString(r, isUrlParamValue),
sType);
- } else if (sType.isDuration()) {
- o = parseDuration(parseString(r, isUrlParamValue));
- } else if (sType.isPeriod()) {
- o = parsePeriod(parseString(r, isUrlParamValue));
+ } else if (nn(builder)) {
+ var m = toBeanMap(builder.create(this, eType));
+ m = parseIntoBeanMap(r, m);
+ o = m == null ? null : builder.build(this, m.getBean(),
eType);
+ } else if (sType.canCreateNewBean(outer)) {
+ var m = newBeanMap(outer, sType.inner());
+ m = parseIntoBeanMap(r, m);
+ o = m == null ? null : m.getBean();
} else if (sType.isMap()) {
var m = (sType.canCreateNewInstance(outer) ?
(Map)sType.newInstance(outer) : newGenericMap(sType));
o = parseIntoMap(r, m, sType.getKeyType(),
sType.getValueType(), pMeta);
@@ -430,18 +420,6 @@ public class UonParserSession extends ReaderParserSession
implements HttpPartPar
var l = (sType.canCreateNewInstance(outer) ?
(Collection)sType.newInstance(outer) : newGenericList());
o = parseIntoCollection(r, l, sType,
isUrlParamValue, pMeta);
}
- } else if (nn(builder)) {
- var m = toBeanMap(builder.create(this, eType));
- m = parseIntoBeanMap(r, m);
- o = m == null ? null : builder.build(this, m.getBean(),
eType);
- } else if (sType.canCreateNewBean(outer)) {
- var m = newBeanMap(outer, sType.inner());
- m = parseIntoBeanMap(r, m);
- o = m == null ? null : m.getBean();
- } else if (sType.canCreateNewInstanceFromString(outer)) {
- var s = parseString(r, isUrlParamValue);
- if (nn(s))
- o = sType.newInstanceFromString(outer, s);
} else if (sType.isArray() || sType.isArgs()) {
if (c == '(') {
var m = newGenericMap();
@@ -459,6 +437,28 @@ public class UonParserSession extends ReaderParserSession
implements HttpPartPar
var l = (ArrayList)parseIntoCollection(r,
list(), sType, isUrlParamValue, pMeta);
o = toArray(sType, l);
}
+ } else if (sType.isCharSequence()) {
+ o = parseString(r, isUrlParamValue);
+ } else if (sType.isChar()) {
+ o = parseCharacter(parseString(r, isUrlParamValue));
+ } else if (sType.isNumber()) {
+ o = parseNumber(r, (Class<? extends
Number>)sType.inner());
+ } else if (sType.isBoolean()) {
+ o = parseBoolean(r);
+ } else if (sType.isDate()) {
+ o = parseDate(parseString(r, isUrlParamValue), sType);
+ } else if (sType.isCalendar()) {
+ o = parseCalendar(parseString(r, isUrlParamValue),
sType);
+ } else if (sType.isTemporal()) {
+ o = parseTemporal(parseString(r, isUrlParamValue),
sType);
+ } else if (sType.isDuration()) {
+ o = parseDuration(parseString(r, isUrlParamValue));
+ } else if (sType.isPeriod()) {
+ o = parsePeriod(parseString(r, isUrlParamValue));
+ } else if (sType.canCreateNewInstanceFromString(outer)) {
+ var s = parseString(r, isUrlParamValue);
+ if (nn(s))
+ o = sType.newInstanceFromString(outer, s);
} else if (c == '(') {
// It could be a non-bean with _type attribute.
var m = newGenericMap();
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 f277aa4aff..e73352ed13 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
@@ -507,24 +507,8 @@ public class UonSerializerSession extends
WriterSerializerSession implements Htt
// '\0' characters are considered null.
if (o == null || (sType.isChar() && ((Character)o).charValue()
== 0))
out.appendObject(null, false);
- else if (sType.isBoolean())
- out.appendBoolean(o);
- else if (sType.isNumber())
- out.appendNumber(o);
- else if (sType.isDate())
- out.appendObject(serializeDate((Date)o, sType), false);
- else if (sType.isCalendar())
- out.appendObject(serializeCalendar(o, sType), false);
- else if (sType.isTemporal())
- out.appendObject(serializeTemporal((TemporalAccessor)o,
sType), false);
- else if (sType.isDuration())
- out.appendObject(serializeDuration((Duration)o), false);
- else if (sType.isPeriod())
- out.appendObject(serializePeriod((Period)o), false);
else if (sType.isBean())
serializeBeanMap(out, toBeanMap(o), typeName);
- else if (sType.isUri() || (nn(pMeta) && pMeta.isUri()))
- out.appendUri(o);
else if (sType.isMap()) {
if (o instanceof BeanMap o2)
serializeBeanMap(out, o2, typeName);
@@ -534,6 +518,22 @@ public class UonSerializerSession extends
WriterSerializerSession implements Htt
serializeCollection(out, (Collection)o, eType);
} else if (sType.isArray()) {
serializeCollection(out, toList(sType.inner(), o),
eType);
+ } else if (sType.isBoolean()) {
+ out.appendBoolean(o);
+ } else if (sType.isNumber()) {
+ out.appendNumber(o);
+ } else if (sType.isUri() || (nn(pMeta) && pMeta.isUri())) {
+ out.appendUri(o);
+ } else if (sType.isDate()) {
+ out.appendObject(serializeDate((Date)o, sType), false);
+ } else if (sType.isCalendar()) {
+ out.appendObject(serializeCalendar(o, sType), false);
+ } else if (sType.isTemporal()) {
+ out.appendObject(serializeTemporal((TemporalAccessor)o,
sType), false);
+ } else if (sType.isDuration()) {
+ out.appendObject(serializeDuration((Duration)o), false);
+ } else if (sType.isPeriod()) {
+ out.appendObject(serializePeriod((Period)o), false);
} else if (sType.isStreamable()) {
serializeStreamable(out, o, sType, eType);
} else if (sType.isReader()) {
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 063e84c7da..a1f3c243c3 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
@@ -276,9 +276,6 @@ public class UrlEncodingParserSession extends
UonParserSession {
o = m.get(CONST_value);
else
o = cast(m, null, eType);
- } else if (sType.isMap()) {
- var m = (sType.canCreateNewInstance() ?
(Map)sType.newInstance() : newGenericMap(sType));
- o = parseIntoMap2(r, m, sType, m);
} else if (nn(builder)) {
var m = toBeanMap(builder.create(this, eType));
m = parseIntoBeanMap(r, m);
@@ -287,6 +284,9 @@ public class UrlEncodingParserSession extends
UonParserSession {
var m = newBeanMap(outer, sType.inner());
m = parseIntoBeanMap(r, m);
o = m == null ? null : m.getBean();
+ } else if (sType.isMap()) {
+ var m = (sType.canCreateNewInstance() ?
(Map)sType.newInstance() : newGenericMap(sType));
+ o = parseIntoMap2(r, m, sType, m);
} else if (sType.isCollection() || sType.isArray() ||
sType.isArgs()) {
// ?1=foo&2=bar...
var c2 = ((sType.isArray() || sType.isArgs()) || !
sType.canCreateNewInstance(outer)) ? newGenericList() :
(Collection)sType.newInstance();
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 9e2a5e248d..276d3bb19d 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
@@ -284,13 +284,13 @@ public class UrlEncodingSerializerSession extends
UonSerializerSession {
sType = getClassMetaForObject(o);
}
- if (sType.isMap()) {
+ if (sType.isBean()) {
+ serializeBeanMap(out, toBeanMap(o), typeName);
+ } else if (sType.isMap()) {
if (o instanceof BeanMap o2)
serializeBeanMap(out, o2, typeName);
else
serializeMap(out, (Map)o, sType);
- } else if (sType.isBean()) {
- serializeBeanMap(out, toBeanMap(o), typeName);
} else if (sType.isCollection() || sType.isArray()) {
var m = sType.isCollection() ?
getCollectionMap((Collection)o) : getCollectionMap(o);
serializeCollectionMap(out, m, getClassMeta(Map.class,
Integer.class, Object.class));
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 7e8fa7faf1..873d55cbe7 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
@@ -902,12 +902,21 @@ public class XmlParserSession extends ReaderParserSession
{
o = Boolean.parseBoolean(getElementText(r));
else if (jsonType == UNKNOWN)
o = getUnknown(r);
- } else if (sType.isBoolean()) {
- o = Boolean.parseBoolean(getElementText(r));
- } else if (sType.isCharSequence()) {
- o = getElementText(r);
- } else if (sType.isChar()) {
- o = parseCharacter(getElementText(r));
+ } else if (nn(builder) || sType.canCreateNewBean(outer)) {
+ if (getXmlClassMeta(sType).getFormat() == COLLAPSED) {
+ var fieldName = r.getLocalName();
+ var m = nn(builder) ?
toBeanMap(builder.create(this, eType)) : newBeanMap(outer, sType.inner());
+ var bpm =
getXmlBeanMeta(m.getMeta()).getPropertyMeta(fieldName);
+ var cm = (ClassMeta<?>)
m.getMeta().getBeanInfo();
+ Object value = parseAnything(cm, currAttr, r,
m.getBean(false), false, null);
+ setName(cm, value, currAttr);
+ bpm.set(m, currAttr, value);
+ o = nn(builder) ? builder.build(this,
m.getBean(), eType) : m.getBean();
+ } else {
+ var m = nn(builder) ?
toBeanMap(builder.create(this, eType)) : newBeanMap(outer, sType.inner());
+ m = parseIntoBean(r, m, isNil);
+ o = nn(builder) ? builder.build(this,
m.getBean(), eType) : m.getBean();
+ }
} else if (sType.isMap()) {
var m = (sType.canCreateNewInstance(outer) ?
(Map)sType.newInstance(outer) : newGenericMap(sType));
o = parseIntoMap(r, m, sType.getKeyType(),
sType.getValueType(), pMeta);
@@ -919,8 +928,17 @@ public class XmlParserSession extends ReaderParserSession {
} else if (sType.isCollection()) {
var l = (sType.canCreateNewInstance(outer) ?
(Collection)sType.newInstance(outer) : newGenericList());
o = parseIntoCollection(r, l, sType, pMeta);
+ } else if (sType.isArray() || sType.isArgs()) {
+ var l = (ArrayList)parseIntoCollection(r, list(),
sType, pMeta);
+ o = toArray(sType, l);
+ } else if (sType.isCharSequence()) {
+ o = getElementText(r);
+ } else if (sType.isChar()) {
+ o = parseCharacter(getElementText(r));
} else if (sType.isNumber()) {
o = parseNumber(getElementText(r), (Class<? extends
Number>)sType.inner());
+ } else if (sType.isBoolean()) {
+ o = Boolean.parseBoolean(getElementText(r));
} else if (sType.isDate()) {
o = parseDate(getElementText(r), sType);
} else if (sType.isCalendar()) {
@@ -931,24 +949,6 @@ public class XmlParserSession extends ReaderParserSession {
o = parseDuration(getElementText(r));
} else if (sType.isPeriod()) {
o = parsePeriod(getElementText(r));
- } else if (nn(builder) || sType.canCreateNewBean(outer)) {
- if (getXmlClassMeta(sType).getFormat() == COLLAPSED) {
- var fieldName = r.getLocalName();
- var m = nn(builder) ?
toBeanMap(builder.create(this, eType)) : newBeanMap(outer, sType.inner());
- var bpm =
getXmlBeanMeta(m.getMeta()).getPropertyMeta(fieldName);
- var cm = (ClassMeta<?>)
m.getMeta().getBeanInfo();
- Object value = parseAnything(cm, currAttr, r,
m.getBean(false), false, null);
- setName(cm, value, currAttr);
- bpm.set(m, currAttr, value);
- o = nn(builder) ? builder.build(this,
m.getBean(), eType) : m.getBean();
- } else {
- var m = nn(builder) ?
toBeanMap(builder.create(this, eType)) : newBeanMap(outer, sType.inner());
- m = parseIntoBean(r, m, isNil);
- o = nn(builder) ? builder.build(this,
m.getBean(), eType) : m.getBean();
- }
- } else if (sType.isArray() || sType.isArgs()) {
- var l = (ArrayList)parseIntoCollection(r, list(),
sType, pMeta);
- o = toArray(sType, l);
} else if (sType.canCreateNewInstanceFromString(outer)) {
o = sType.newInstanceFromString(outer,
getElementText(r));
} else if (nn(sType.getProxyInvocationHandler())) {
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 d058428eb6..e153c7f850 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
@@ -1090,7 +1090,21 @@ public class XmlSerializerSession extends
WriterSerializerSession {
// Render the tag contents.
if (nn(o)) {
- if (sType.isUri() || (nn(pMeta) && pMeta.isUri())) {
+ if (sType.isBean()) {
+ rc = serializeBeanMap(out, toBeanMap(o),
elementNamespace, isCollapsed, isMixedOrText);
+ } else if (sType.isMap() || (nn(wType) &&
wType.isMap())) {
+ if (o instanceof BeanMap o2)
+ rc = serializeBeanMap(out, o2,
elementNamespace, isCollapsed, isMixedOrText);
+ else
+ rc = serializeMap(out, (Map)o, sType,
eType.getKeyType(), eType.getValueType(), isMixedOrText);
+ } else if (sType.isCollection() || sType.isArray() ||
(nn(wType) && (wType.isCollection() || wType.isArray()))) {
+ if (isCollapsed)
+ indent--;
+ serializeCollection(out, o, sType, eType,
pMeta, isMixedOrText);
+ if (isCollapsed)
+ indent++;
+ } else if (sType.isUri() || (nn(pMeta) &&
pMeta.isUri())) {
+ // Must come before isCharSequence/isChar:
@Uri-annotated String properties (where sType is String but pMeta.isUri() is
true) need to route here for URI text emission.
out.textUri(o);
} else if (sType.isCharSequence() || sType.isChar()) {
if (isXmlText(format, sType))
@@ -1109,19 +1123,6 @@ public class XmlSerializerSession extends
WriterSerializerSession {
out.text(serializeDuration((Duration)o));
} else if (sType.isPeriod()) {
out.text(serializePeriod((Period)o));
- } else if (sType.isMap() || (nn(wType) &&
wType.isMap())) {
- if (o instanceof BeanMap o2)
- rc = serializeBeanMap(out, o2,
elementNamespace, isCollapsed, isMixedOrText);
- else
- rc = serializeMap(out, (Map)o, sType,
eType.getKeyType(), eType.getValueType(), isMixedOrText);
- } else if (sType.isBean()) {
- rc = serializeBeanMap(out, toBeanMap(o),
elementNamespace, isCollapsed, isMixedOrText);
- } else if (sType.isCollection() || sType.isArray() ||
(nn(wType) && (wType.isCollection() || wType.isArray()))) {
- if (isCollapsed)
- indent--;
- serializeCollection(out, o, sType, eType,
pMeta, isMixedOrText);
- if (isCollapsed)
- indent++;
} else if (sType.isStreamable()) {
if (isCollapsed)
indent--;
diff --git
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/yaml/YamlParserSession.java
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/yaml/YamlParserSession.java
index 2d0a777b62..043efabf83 100644
---
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/yaml/YamlParserSession.java
+++
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/yaml/YamlParserSession.java
@@ -274,6 +274,12 @@ public class YamlParserSession extends ReaderParserSession
{
var m2 = newGenericMap();
parseFlowMapping(r, m2, string(), object(),
pMeta);
o = cast(m2, pMeta, eType);
+ } else if (nn(builder)) {
+ var m = toBeanMap(builder.create(this, eType));
+ o = builder.build(this, parseIntoBeanMap(r,
m).getBean(), eType);
+ } else if (sType.canCreateNewBean(outer)) {
+ var m = newBeanMap(outer, sType.inner());
+ o = parseIntoBeanMap(r, m).getBean();
} else if (sType.isMap()) {
Map m = (sType.canCreateNewInstance(outer) ?
(Map)sType.newInstance(outer) : newGenericMap(sType));
o = parseFlowMapping(r, m, sType.getKeyType(),
sType.getValueType(), pMeta);
@@ -281,12 +287,6 @@ public class YamlParserSession extends ReaderParserSession
{
var m = newGenericMap();
parseFlowMapping(r, m, string(), object(),
pMeta);
o = cast(m, pMeta, eType);
- } else if (nn(builder)) {
- var m = toBeanMap(builder.create(this, eType));
- o = builder.build(this, parseIntoBeanMap(r,
m).getBean(), eType);
- } else if (sType.canCreateNewBean(outer)) {
- var m = newBeanMap(outer, sType.inner());
- o = parseIntoBeanMap(r, m).getBean();
} else if (sType.isArray() || sType.isArgs()) {
var m = newGenericMap();
parseFlowMapping(r, m, string(), object(),
pMeta);
@@ -377,14 +377,6 @@ public class YamlParserSession extends ReaderParserSession
{
m2.put(ts, value);
parseBlockMappingRemainder(r, m2, string(),
object(), pMeta, keyIndent);
return cast(m2, pMeta, eType);
- } else if (sType.isMap()) {
- Map m = (sType.canCreateNewInstance(outer) ?
(Map)sType.newInstance(outer) : newGenericMap(sType));
- Object value =
parseAnything(sType.getValueType(), r, m, pMeta);
- Object key = convertAttrToType(m, trim(s),
sType.getKeyType());
- setName(sType.getValueType(), value, key);
- m.put(key, value);
- parseBlockMappingRemainder(r, m,
sType.getKeyType(), sType.getValueType(), pMeta, keyIndent);
- return m;
} else if (nn(builder)) {
var m = toBeanMap(builder.create(this, eType));
parseBeanProperty(r, m, s);
@@ -395,6 +387,14 @@ public class YamlParserSession extends ReaderParserSession
{
parseBeanProperty(r, m, s);
parseIntoBeanMapBlockRemainder(r, m, keyIndent);
return m.getBean();
+ } else if (sType.isMap()) {
+ Map m = (sType.canCreateNewInstance(outer) ?
(Map)sType.newInstance(outer) : newGenericMap(sType));
+ Object value =
parseAnything(sType.getValueType(), r, m, pMeta);
+ Object key = convertAttrToType(m, trim(s),
sType.getKeyType());
+ setName(sType.getValueType(), value, key);
+ m.put(key, value);
+ parseBlockMappingRemainder(r, m,
sType.getKeyType(), sType.getValueType(), pMeta, keyIndent);
+ return m;
} else {
var m2 = newGenericMap();
Object value = parseAnything(object(), r, m2,
pMeta);
@@ -435,14 +435,6 @@ public class YamlParserSession extends ReaderParserSession
{
m2.put(keyStr, value);
parseBlockMappingRemainder(r, m2, string(),
object(), pMeta, keyIndent);
return cast(m2, pMeta, eType);
- } else if (sType.isMap()) {
- Map m = (sType.canCreateNewInstance(outer) ?
(Map)sType.newInstance(outer) : newGenericMap(sType));
- Object value =
parseAnything(sType.getValueType(), r, m, pMeta);
- Object key = convertAttrToType(m, keyStr,
sType.getKeyType());
- setName(sType.getValueType(), value, key);
- m.put(key, value);
- parseBlockMappingRemainder(r, m,
sType.getKeyType(), sType.getValueType(), pMeta, keyIndent);
- return m;
} else if (nn(builder)) {
var m = toBeanMap(builder.create(this, eType));
parseBeanProperty(r, m, s);
@@ -453,6 +445,14 @@ public class YamlParserSession extends ReaderParserSession
{
parseBeanProperty(r, m, s);
parseIntoBeanMapBlockRemainder(r, m, keyIndent);
return m.getBean();
+ } else if (sType.isMap()) {
+ Map m = (sType.canCreateNewInstance(outer) ?
(Map)sType.newInstance(outer) : newGenericMap(sType));
+ Object value =
parseAnything(sType.getValueType(), r, m, pMeta);
+ Object key = convertAttrToType(m, keyStr,
sType.getKeyType());
+ setName(sType.getValueType(), value, key);
+ m.put(key, value);
+ parseBlockMappingRemainder(r, m,
sType.getKeyType(), sType.getValueType(), pMeta, keyIndent);
+ return m;
} else {
var m2 = newGenericMap();
Object value = parseAnything(object(), r, m2,
pMeta);
@@ -485,14 +485,14 @@ public class YamlParserSession extends
ReaderParserSession {
private Object convertToType(String s, ClassMeta<?> sType, ClassMeta<?>
eType, Object outer, BeanPropertyMeta pMeta) throws ParseException {
if (sType.isObject()) {
return resolveScalarType(trim(s));
- } else if (sType.isBoolean()) {
- return bool(s);
} else if (sType.isCharSequence()) {
return trim(s);
} else if (sType.isChar()) {
return parseCharacter(s);
} else if (sType.isNumber()) {
return StringUtils.parseNumber(s, (Class<? extends
Number>)sType.inner());
+ } else if (sType.isBoolean()) {
+ return bool(s);
} else if (sType.isDate()) {
return parseDate(s, sType);
} else if (sType.isCalendar()) {
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 178b53719e..c0f722c2ae 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
@@ -285,12 +285,8 @@ public class YamlSerializerSession extends
WriterSerializerSession {
if (o == null || (sType.isChar() && ((Character)o).charValue()
== 0)) {
out.append("null");
- } else if (sType.isNumber() || sType.isBoolean()) {
- out.append(o);
} else if (sType.isBean()) {
serializeBeanMap(out, toBeanMap(o), typeName);
- } else if (sType.isUri() || (nn(pMeta) && pMeta.isUri())) {
- out.uriValue(o);
} else if (sType.isMap()) {
if (o instanceof BeanMap o2)
serializeBeanMap(out, o2, typeName);
@@ -300,6 +296,10 @@ public class YamlSerializerSession extends
WriterSerializerSession {
serializeCollection(out, (Collection)o, eType, asField);
} else if (sType.isArray()) {
serializeCollection(out, toList(sType.inner(), o),
eType, asField);
+ } else if (sType.isNumber() || sType.isBoolean()) {
+ out.append(o);
+ } else if (sType.isUri() || (nn(pMeta) && pMeta.isUri())) {
+ out.uriValue(o);
} else if (sType.isReader()) {
pipe((Reader)o, out, SerializerSession::handleThrown);
} else if (sType.isInputStream()) {
diff --git a/todo/TODO-56-serializer-parser-dispatch-cleanup.md
b/todo/FINISHED-56-serializer-parser-dispatch-cleanup.md
similarity index 74%
rename from todo/TODO-56-serializer-parser-dispatch-cleanup.md
rename to todo/FINISHED-56-serializer-parser-dispatch-cleanup.md
index 4540504032..ada9b4f864 100644
--- a/todo/TODO-56-serializer-parser-dispatch-cleanup.md
+++ b/todo/FINISHED-56-serializer-parser-dispatch-cleanup.md
@@ -4,6 +4,90 @@ Source: filed 2026-05-21 in response to the recent
JIT/dispatch analysis on `Cla
---
+## Status (2026-05-22, final closeout)
+
+**Phase 1 parser-side, this pass — all in-scope `*ParserSession` chains
reordered to canonical order, with wire-token-driven correctness gates
preserved.**
+
+Files touched this pass (parser-side):
+-
`juneau-core/juneau-marshall/src/main/java/org/apache/juneau/json/JsonParserSession.java`
— `parseAnything` reordered; structural branches (builder → bean → map →
collection → array → charSeq → char → number → boolean → temporal cluster)
follow the canonical sequence after the `isObject` peek-char dispatch and the
wire-token (`c == '{' / '[' / 'n'`) gates.
+-
`juneau-core/juneau-marshall/src/main/java/org/apache/juneau/uon/UonParserSession.java`
— `parseAnything` reordered; `isVoid` and the URL-blank-param pre-check stay
at top, `builder` / `canCreateNewBean` promoted above `isMap` / `isCollection`
/ `isArray`.
+-
`juneau-core/juneau-marshall/src/main/java/org/apache/juneau/urlencoding/UrlEncodingParserSession.java`
— `parseAnything` reordered; `builder` and `canCreateNewBean` promoted before
`isMap` / `isCollection`.
+-
`juneau-core/juneau-marshall/src/main/java/org/apache/juneau/xml/XmlParserSession.java`
— `parseAnything` structural tail reordered; the `isObject` jsonType-driven
branch stays at top.
+-
`juneau-core/juneau-marshall/src/main/java/org/apache/juneau/html/HtmlParserSession.java`
— both the text-content cascade (`tag == null || tag.isOneOf(BR, BS, FF, SP)`)
scalar order and the TABLE/object cascade structural tail reordered. Outer
tag-first dispatch left alone (correctness-load-bearing per the inventory note).
+-
`juneau-core/juneau-marshall/src/main/java/org/apache/juneau/yaml/YamlParserSession.java`
— `parseAnything` (the `c == '{'` cascade), `handleQuotedScalar`,
`handlePlainScalar`, and `convertToType` reordered.
+-
`juneau-core/juneau-marshall/src/main/java/org/apache/juneau/markdown/MarkdownParserSession.java`
— `parseCellValue` temporal cluster reordered to canonical sequence (`isDate`
→ `isCalendar` → `isTemporal` → `isDuration` → `isPeriod`).
+-
`juneau-core/juneau-marshall/src/main/java/org/apache/juneau/msgpack/MsgPackParserSession.java`
— `parseAnything` structural tail reordered, keeping the merged-scalar tier
and wire-type pre-dispatch in place.
+-
`juneau-core/juneau-marshall/src/main/java/org/apache/juneau/cbor/CborParserSession.java`
— mirror of MsgPack reorder.
+-
`juneau-core/juneau-marshall-rdf/src/main/java/org/apache/juneau/jena/RdfParserSession.java`
— `parseAnything` structural tail reordered, after the RDF_NIL guard and
`isObject` literal/resource/Seq pre-dispatch.
+-
`juneau-core/juneau-marshall-rdf/src/main/java/org/apache/juneau/jena/RdfStreamParserSession.java`
— `parseAnything` structural tail reordered. **Important:** `isByteArray`
deliberately stays *adjacent to the scalar tier* (after `isCharSequence`) — and
crucially *below* `isCollectionOrArray` — because the RDF byte-array node is a
typed base64 literal that's read through the same scalar-path helper
(`getValue(n, outer)`); moving `isByteArray` earlier (above
`isCollectionOrArray`) caused [...]
+
+Files reviewed but unchanged (already in canonical order, wire-token-shaped,
or not a reorder candidate):
+-
`juneau-core/juneau-marshall/src/main/java/org/apache/juneau/hjson/HjsonParserSession.java`
— no top-level canonical chain; piecemeal sites already in order.
+-
`juneau-core/juneau-marshall/src/main/java/org/apache/juneau/hocon/HoconParserSession.java`
— same as Hjson.
+-
`juneau-core/juneau-marshall/src/main/java/org/apache/juneau/ini/IniParserSession.java`
— `parseValue` is wire-token-driven and the type branches are already
structural-first; no reorder needed.
+-
`juneau-core/juneau-marshall/src/main/java/org/apache/juneau/toml/TomlParserSession.java`
— `convertValue` already addressed in Phase 2.
+-
`juneau-core/juneau-marshall/src/main/java/org/apache/juneau/proto/ProtoParserSession.java`
— `convertValue` already addressed in Phase 2; `parseAnything` delegates.
+-
`juneau-core/juneau-marshall/src/main/java/org/apache/juneau/bson/BsonParserSession.java`
— no canonical chain (convertToType-driven).
+-
`juneau-core/juneau-marshall/src/main/java/org/apache/juneau/csv/CsvParserSession.java`
— highly specialized row-shape parser; `parseAnything` and `parseCellValue`
are structural-first already, no reorder candidate.
+-
`juneau-core/juneau-marshall/src/main/java/org/apache/juneau/parquet/ParquetParserSession.java`
— out of scope per the Phase-1 carve-out (row-oriented, schema-driven).
+
+**Verification (final, this pass):**
+- `mvn -pl juneau-utest -am
-Dtest='Proto*Test,Hjson*Test,Hocon*Test,Bson*Test,Toml*Test,Csv*Test,Markdown*Test,Yaml*Test,Ini*Test,Json5*Test,JsonParser*Test,XmlParser*Test,UrlEncodingParser*Test,UonParser*Test'
…` — green.
+- `./scripts/test.py -v` (clean build + tests) — **126,680 tests pass, 0
failures, 0 errors, 20 skipped** (baseline restored after the
`RdfStreamParserSession` byte[] ordering regression was fixed mid-pass).
+- `./scripts/test.py -b` (mvn clean install) — green.
+
+**Latent bugs surfaced this pass:** none net-net. One *self-inflicted*
regression was caught and fixed during testing: an earlier attempt at
reordering `RdfStreamParserSession.parseAnything` put `isByteArray` above
`isCollectionOrArray` for symmetry with the canonical order, which broke
base64-typed-literal parsing (`ResourceRequiredException` on
`"AQ=="^^xsd:base64Binary`). The ordering constraint is now commented in the
file.
+
+**Phase 4 / Phase 5 disposition:**
+- **Phase 4** (`Category primaryCategory()` switch pilot) — punted as
**explicitly optional** per the plan's own "Roll-out decision" note. Not gating
completion.
+- **Phase 5** (`MarshallDispatchBenchmark` JMH) — punted as **explicitly
optional** per the plan's "sanity check, not a pre-commit blocker" framing. Not
gating completion.
+
+Phase 1 (both sides), Phase 2, and Phase 3 are now complete; that satisfies
the readability + behavior-preserving goal the plan was filed to deliver. Plan
archived to `FINISHED-56-serializer-parser-dispatch-cleanup.md`.
+
+---
+
+## Status (2026-05-22 worker pass — prior serializer-side pass)
+
+**Done:**
+- **Phase 2** — both files hoisted:
+ - `ProtoParserSession.convertValue` — three `Map val2` and two `Number val2`
checks collapsed into single outer pattern-match blocks; `CharSequence val2`
left as-is (already hoisted).
+ - `TomlParserSession.convertValue` — two `Map map` checks hoisted into one
outer block; two `Number num` checks (separated only by a `String` block that
can never match a Number) merged into a single outer `Number` block with
`isNumber` checked first.
+- **Phase 3** — `ClassMeta` polish:
+ - Marked `ClassMeta<T>` class `final` (no `extends ClassMeta` consumers
found in `juneau-marshall`, `juneau-marshall-rdf`, `juneau-utest`,
`juneau-rest-*`, `juneau-microservice-*`, `juneau-bean-*`, or `juneau-docs`).
+ - Dropped the defensive `cat != null &&` guards from `isCollection()`,
`isMap()`, and `isUri()`; removed the obsolete "Defensive null-guard …" comment
from `isMap()`.
+ - Did **not** add `final` to individual `isXxx` methods (class-level `final`
already covers them per the plan).
+- **Phase 1 — serializer-side reorders applied** (canonical bean → map →
collection → array → charSeq → number/boolean → uri → temporal cluster →
streamable/reader/inputstream → tail, with pre-dispatch correctness gates
preserved):
+ - `JsonSerializerSession.serializeAnything` — the canonical "winner" file;
reorder applied.
+ - `UonSerializerSession.serializeAnything` — same shape as JSON, reordered.
+ - `UrlEncodingSerializerSession.serializeAnything` — minor swap of `isMap` ↔
`isBean` to align with canonical order.
+ - `HjsonSerializerSession.serializeAnything` — same shape as JSON, reordered.
+ - `HoconSerializerSession.serializeAnything` — same shape as JSON,
reordered; `byte[]` Base64 gate preserved at top after the null gate.
+ - `YamlSerializerSession.serializeAnything` — reordered; YAML omits the
temporal cluster (falls through to `toString`) per the inventory note.
+ - `MarkdownSerializerSession.serializeInlineValue` — scalar-tail polish:
`isCharSequence || isEnum` lifted above the temporal cluster. Main
`serializeAnything` was already structural-first and was left as-is.
+ - `HtmlSerializerSession.serializeAnything` (write pass) — reordered;
`isReader || isInputStream` short-circuit and HTML-specific `isXml` /
`isPlainText` gates preserved at the top.
+ - `XmlSerializerSession.serializeAnything` (write pass at 1093-1133) —
reordered; classify pass at 988-1004 left alone (correctness-load-bearing).
**Important:** `isUri || pMeta.isUri()` deliberately stays *before*
`isCharSequence || isChar` because `@Uri`-annotated `String` properties (where
`sType` is `String` but `pMeta.isUri()` is true) must route through the URI
text-emission path; a comment was added at the branch.
+ - `IniSerializerSession.formatSimpleValue` — scalar-tail polish:
`isCharSequence || isUri` lifted above number/temporal.
+ - `TomlSerializerSession.writeValue` — `isBean` promoted to the top of the
leaf-value chain; rest left in place (the runtime `value.getClass().isArray()`
gate stays *before* `isCollection() || isArray()` so erased-array values still
hit the inline-array emission path).
+ - `MsgPackSerializerSession.serializeAnything` — reordered; the
binary-format `isByteArray` branch stays adjacent to `isCollection` (between
collection and generic array dispatch).
+ - `CborSerializerSession.serializeAnything` — mirror of MsgPack reorder.
+ - `BsonSerializerSession.writeElement` — reordered; `isCharSequence ||
isChar || isEnum` lifted from near the bottom to its canonical slot.
+ - `ProtoSerializerSession.serializeScalarValue` — chain was essentially
already in canonical order at the scalar-leaf level; only `isEnum` ordering
verified. Top-level `serializeAnything` (131-237) untouched (already
structural-first per the inventory note).
+ - `RdfSerializerSession.serializeAnything` and
`RdfStreamSerializerSession.serializeAnything` — `isBean` / `isMap` /
`isCollectionOrArray` promoted above `isCharSequence` / `isNumber`.
**Important:** `isUri || isURI` deliberately stays at the top (after the null
gate) because RDF URIs must emit as `Resource`s, not literals; a comment was
added. For `RdfStreamSerializerSession`, `isByteArray` was kept *before*
`isCollectionOrArray` (byte[] satisfies `isArray()` but RDF emits it as a typ
[...]
+
+**Verification:**
+- Baseline `mvn -pl juneau-utest -am
-Dtest='Proto*Test,Hjson*Test,Hocon*Test,Bson*Test,Toml*Test,Csv*Test,Markdown*Test,Yaml*Test,Ini*Test,Json5*Test,JsonParser*Test,XmlParser*Test,UrlEncodingParser*Test,UonParser*Test'
…` — green (1315 tests).
+- Per-format target tests run incrementally during each file's edit — all
green.
+- Final `./scripts/test.py -v` — **126,680 tests pass, 0 failures, 0 errors,
20 skipped** (the skipped count is the baseline; no regressions).
+- Final `./scripts/test.py -b` (mvn clean install) — green.
+
+**Deferred — picked up in the 2026-05-22 final closeout above:**
+- **Phase 1, parser-side chains** — done in the closeout pass. See the file
list at the top of this status section.
+- **Phase 4** and **Phase 5** — both remain explicitly optional and are punted
per the plan's own optional-marker language. Not gating completion.
+
+**Latent bugs surfaced:** none. All reorders were behavior-preserving; the
comments added on `XmlSerializerSession`, `RdfSerializerSession`,
`RdfStreamSerializerSession`, and `HoconSerializerSession` document the
ordering constraints that prevent a future reorder from regressing them.
+
+---
+
## Background
### Why the dispatch chains came up