You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@tapestry.apache.org by "Ben Weidig (Jira)" <ji...@apache.org> on 2026/07/26 07:35:00 UTC
[jira] [Created] (TAP5-2837) Improve JSON serialization performance (toString/toCompactString)
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)