Ben Weidig created TAP5-2837:
--------------------------------
Summary: Improve JSON serialization performance
(toString/toCompactString)
Key: TAP5-2837
URL: https://issues.apache.org/jira/browse/TAP5-2837
Project: Tapestry 5
Issue Type: Improvement
Components: tapestry-json
Affects Versions: 5.10.0
Reporter: Ben Weidig
h3. Overview
{{JSONObject}}/{{JSONArray}}'s {{toString()}} and {{toCompactString()}} are
slower than necessary due to synchronization overhead and per-{{String}}
allocation in the print path.
My sandbox implementation at
https://github.com/benweidig/tapestry-json-improvements (non-breaking, verified
byte-for-byte against current output) shows a ~4-6x speedup across payload
sizes and both compact/pretty formatting, with no public API changes.
h3. Problem
* {{toString()}}/{{toCompactString()}} route output through {{CharArrayWriter}}
wrapped in {{PrintWriter}}, both use {{synchronized}} methods on every write.
This is pure overhead for single-threaded string building.
* {{JSONObject.quote(String)}} allocates a new {{JSONStringer}} (own
{{StringBuilder}} + {{ArrayList}} scope stack) for every quoted string, like
keys and string values in a payload.
* Extended-Unicode escaping goes through {{String.format}}, which parses the
format string on every call.
* Output buffers start at JDK default capacity with no pre-sizing, causing
repeated grow/copy for larger trees.
h3. Proposed changes
Delete {{JSONStringer}} and inline its escaping loop directly into
{{JSONObject}} as a static {{escapeInto(...)}} helper, called directly by
{{quote()}} and the print sessions.
Replace {{String.format}} hex escaping with manual nibble extraction + lookup
table.
Drop {{CharArrayWriter}}/{{PrintWriter}} for
{{toString()}}/{{toCompactString()}}.
Instead, build directly into a {{StringBuilder}}.
Pre-size the output buffer based on collection size instead of the JDK default.
All changes are additive/internal/package-private only, without any no
signature changes, no behavior changes.
Full test suite plus a new baseline-equivalence test confirmed identical output
to 5.9.1 in my sandbox.
h3. Risks
* Low functional risk: escaping logic is a straight extraction/refactor,
covered by existing tests.
* Removing {{JSONStringer}} is a *breaking change* for any external caller
referencing that class directly (it's currently public): Needs a
compatibility/deprecation decision before merge.
--
This message was sent by Atlassian Jira
(v8.20.10#820010)