Skip to content

AER-4590 Avoid redundant work in JSONObjectHandle - #82

Merged
JornC merged 1 commit into
aerius:mainfrom
JornC:json-has-avoid-double-keyset
Sep 23, 2026
Merged

JornC merged 1 commit into
aerius:mainfrom
JornC:json-has-avoid-double-keyset

Conversation

@JornC

@JornC JornC commented Aug 3, 2026

Copy link
Copy Markdown
Member

This contains some proven non-controversial optimizations in the JSON parser framework.


LLM-generated technical summary

Two changes in JSONObjectHandle, both provably equivalent.

has() enumerated the object twice per call. It was:

return getInner() != null && keySet() != null && keySet().contains(key);

keySet() delegates to GWT's JSONObject.keySet(), which on every call runs a full for-in with hasOwnProperty, allocating a fresh String[] and an anonymous AbstractSet. Nothing is cached — size() even carries a comment about having to recheck for foreign changes.

Crucially, the returned set overrides contains to delegate straight back to containsKey, so the key array it just built is never read:

public boolean contains(Object o) {
  return (o instanceof String) && containsKey((String) o);
}

So both enumerations were pure waste, and inner.containsKey(key) reaches the identical native key in jsObject. Equivalence holds by construction rather than by argument, including for keys whose value is JSON null and for prototype-chain names such as toString (which has() already reported as present — that pre-existing quirk is preserved).

keySet() can never return null, so that guard was dead. A key != null check was added to keep has(null) returning false: without it, null in jsObject coerces to the property name "null".

In one AERIUS Calculator boot this is called ~15,400 times, so ~30,800 object enumerations disappear.

getStringOrDefault allocated a wrapper around its own state. It called new JSONObjectHandle(inner).getString(key). inner is the class's only field and the constructor merely assigns it, so the new instance was identical to this; getString(key) is the same call without the allocation.

Verified against the GWT sources shipped in org.gwtproject:gwt-user:2.13.1; JSONObject.java is byte-identical across 2.10.0, 2.12.1, 2.13.0 and 2.13.1, so this does not depend on the GWT version in use.

Two things a reviewer should know. The module contains no test files, so mvn test passes having run nothing — compilation is the only automated evidence here, and real validation is a client boot. And the runtime saving has not been measured in a browser; the change is justified by strictly removing work, not by a benchmark.

has() built the key set twice per call and discarded both; getStringOrDefault allocated a wrapper around its own inner object to call a method on itself.
@sonarqubecloud

sonarqubecloud Bot commented Aug 3, 2026

Copy link
Copy Markdown

@JornC JornC changed the title Avoid redundant work in JSONObjectHandle AER-4590 Avoid redundant work in JSONObjectHandle Aug 3, 2026
@JornC
JornC requested a review from BertScholten September 22, 2026 20:38

@BertScholten BertScholten left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@JornC
JornC merged commit 311c7ab into aerius:main Sep 23, 2026
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants