Skip to content

4.101.0

Latest

Choose a tag to compare

@jdereg jdereg released this 19 Apr 22:20

json-io 4.101.0

Maven Central: com.cedarsoftware:json-io:4.101.0 (requires java-util 4.101.0+)

Highlights

New APIs

  • WriteOptionsBuilder.standardJson() — one-call convenience setting showTypeInfoNever(), showRootTypeInfo(false), cycleSupport(false), stringifyMapKeys(true), useMetaPrefixDollar(), and ISO-8601 date formatting. Produces Jackson-compatible JSON for normal POJO/List/Map cases. Chainable. Will become the default in 5.0.0.
  • WriteOptionsBuilder.namingStrategy(IoNaming.Strategy) — global naming strategy applied to all classes without a per-class @IoNaming/@JsonNaming. Priority: per-field @IoProperty/@JsonProperty > per-class annotation > global strategy > field name as-is. Two new enum values: UPPER_SNAKE_CASE and LOWER_CASE (full set: SNAKE_CASE, UPPER_SNAKE_CASE, KEBAB_CASE, UPPER_CAMEL_CASE, LOWER_DOT_CASE, LOWER_CASE).
  • WriteOptionsBuilder.stringifyMapKeys(boolean) — non-String map keys with bidirectional String conversion (Long, UUID, Enum, Date, etc.) written as plain JSON object keys instead of @keys/@items parallel-array form. Default false for JSON (backward-compat), true for JSON5.
  • WriteOptionsBuilder.preserveLeafContainerIdentity(boolean) — when false (the new default), traceReferences skips containers holding only non-referenceable leaves (List<String>, Map<UUID, Date>, String[], etc.), matching Jackson's default identity semantics.
  • WriteOptionsBuilder.writeOptionalAsObject(boolean) — set to true for legacy {"present":true,"value":X} form; default false writes Optionals as bare primitive values.
  • 1-arg convenience overloads: JsonIo.toJson(obj), toToon(obj), toJava(json), toJava(stream), fromToon(toon), fromToon(stream).

Performance

  • Full-suite performance pass — all 8 Read/Write ratios under 2.0x vs Jackson on a warm JVM (best 1.32x JsonIo Read toMaps, worst ~1.97x Toon Read toJava).
  • Switched all hot-path ClassValueMap/ClassValueSet lookups to the new getByClass(Class) / containsClass(Class) fast-path APIs (added in java-util 4.101.0).
  • AnnotationResolver.getMetadata — split into trivially-inlineable fast path + scanAndCache cold path. Fast-path self-time dropped ~50%.
  • ObjectResolver.traverseFields — hoisted per-object AnnotationResolver.getMetadata call out of the per-field loop (~20% of Resolver-phase samples).
  • ReadOptions.isNonReferenceableClass / isNotCustomReaderClass — memoized via per-instance ClassValue<Boolean> caches (mirrors WriteOptions.nonRefCache).
  • JsonWriter.traceReferences — filters non-referenceable leaves at push site (save deque push+pop per leaf). JsonIo Write cycle=true toJava −5.8%, toMaps −7.5%.
  • ToonWriter — precomputed key-quoting decision at WriteFieldPlan build time (eliminates per-field ConcurrentHashMap.get — 11.7% of ToonWriter samples). Toon Write cycle=false toJava −5.0%.
  • JsonWriter.writeField / ToonWriter.writeFieldEntry — primitive+String fast paths bypass full dispatch for the most common field-value types.
  • ToonWriter.writeMap — skips hasComplexKeys iteration when the enclosing field's declared Map key type is Converter-stringifiable.
  • JsonWriter.writeCollectionElement — POJO short-circuit for cycleSupport=false collapses 4-level dispatch to 2 levels.

Bug fixes

  • Optional, OptionalInt, OptionalLong, OptionalDouble — all four now write Jackson/Gson-compatible primitive form by default (Optional.empty()null, Optional.of(X)X). Prior behavior emitted invalid JSON for Optional ({null} or {"hello"}) and broken POJO form for the three primitive Optionals. Field-type-aware coercion wraps bare scalars into the appropriate Optional variant on read. Reader accepts both new and legacy object form for backward compatibility. Reported by Jim Ronan (*/dxg Health).
  • JsonWriter.writeLongDirect() — inner digit-extraction loop used int q which silently truncated Long.MIN_VALUE (rendered as -206158430208 instead of -9223372036854775808). Fixed by using long q.

Jackson-alignment (opt-in)

  • WriteOptionsBuilder.standardJson() and json5() now also configure ISO-8601 date formatting for java.util.Date / java.sql.Date. Matches Spring Boot's default Jackson configuration (WRITE_DATES_AS_TIMESTAMPS=false).

Full changelog: https://github.com/jdereg/json-io/blob/master/changelog.md