Skip to content

feat: collapsable inner records for to(Class) access#95

Merged
jbee merged 6 commits into
mainfrom
v1.9next-next
May 6, 2026
Merged

feat: collapsable inner records for to(Class) access#95
jbee merged 6 commits into
mainfrom
v1.9next-next

Conversation

@jbee

@jbee jbee commented Apr 29, 2026

Copy link
Copy Markdown
Contributor

API Changes

These changes were made to provide a more versatile API while at the same time have less specialized methods and avoid unnecessary re-wrapping or API elevation on the caller side as in case of Iterator => Stream.

Backwards incompatible changes:

  • 🆎 object keys() now returns Streamable.Sized
  • 🆎 object entries() now returns Streamable.Sized
  • ❌ object values() is obsolete as entries() is identical (values() for objects needed to be removed as it otherwise would have clashed with newly added method of same name for arrays as JsonMixed extends both)
  • ❌ removed 1.9 array additions of listValues, streamValues and values(Function) which all can done via values

Backwards compatible changes (apart from potential name clashes in extending types):

  • 🆕 array values() allows array element access as Streamable.Sized<JsonMixed> (enables use in for-each while also provide stream access)
  • 🆕 array values(Index) (same as above but with control over index behaviour)
  • 🆕 array values(Class) (same as above but with included access as a "mapped" type, e.g. a record)
  • JsonMixed now extends JsonPrimitive as well
  • 🆎 JsonNode#members now returns Streamable.Sized (not Streamable)
  • 🆎 JsonNode#paths now returns Streamable.Sized (not Streamable)
  • 🆎 JsonNode#elements now returns Streamable.Sized (not Streamable)
  • 🆎 JsonNode#values now returns Streamable.Sized (not Streamable)

Compose to-targets using @Collapsed inner records

  • 🆕 when accessing objects as record types the records now can have components that are annotated with new annotation @Collapsed to map a "flat" JSON object to a structured Java composition of components from different types. This is quite essential for record types as inheritance as a means of composition is not possible. With this feature records can now achieve the equivalent of multiple-inheritance by composing multiple inner @Collapsed records within a root or parent record type.
  • 🆕 JsonObject#collapsedProperties to get a types properties with @Collapsed inner properties flattened into the list

Note that inner records are never null when accessed via to even if all of their properties are not present in the input JSON. This is so there is a simple, clear contract that avoids NPEs and is easy to implement.

Other Improvements

  • ✨ Java Number of a JSON number value with numeric zero value having 0 decimal digit(s) does not result in TextualNumber but a Double
  • 🆕 Streamable.Sized now has map and toList (like a Stream) which often avoid the need to even elevate to a Stream so that iteration occurs directly on a mapped Iterator
  • 🆕 Class properties are now automatically considered string properties

Bugfixes

  • 🐛 fixed that properties that accept all nodes types are accepted implicitly must not be considered required because of it
  • 🐛 fixed that some non-zero non-numeric inputs such as . where wrongly considered zero by TextualNumber#isNumericZero

Automatic Testing

  • new cases where added to test the bugs found in TextualNumber
  • existing test scenarios were extended to contain examples of @Collapsed inner records

@jbee jbee self-assigned this Apr 29, 2026
@sonarqubecloud

sonarqubecloud Bot commented May 6, 2026

Copy link
Copy Markdown

@jbee jbee marked this pull request as ready for review May 6, 2026 08:53
@jbee jbee merged commit 1bf10f6 into main May 6, 2026
3 checks passed
@jbee jbee deleted the v1.9next-next branch May 6, 2026 08:53
@jbee jbee mentioned this pull request May 6, 2026
3 tasks
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.

1 participant