Changelog
All notable changes to SJF4J (Simple JSON Facade for Java) will be documented in this file.
The format is based on Keep a Changelog, and this project adheres to Semantic Versioning.
[Unreleased]
Added
- Added
FacadeNodes.removeIfInObject(...)with Jackson 2, Jackson 3, and Gson backend support so native facade object nodes can remove matching properties in place.
Changed
- Changed patch merge naming and semantics to distinguish RFC 7386
mergePatch(...)from SJF4JindexedMerge(...); indexed array merge now supports sparse index updates with skip-on-null entries and trailing-null tail truncation such as[null] -> []and[1, 2, null] -> [1, 2].
Removed
- Removed
JsonContainerconvenience overloads for the old merge naming, includingmerge(...),mergeWithCopy(...), and the single-argumentindexedMerge(...)/indexedMergeWithCopy(...)variants, and removed the instanceJsonContainer.mergePatch(...)wrapper in favor of explicitindexedMerge(patch, overwrite, deepCopy)and staticPatches.mergePatch(target, patch)entry points.
Fixed
- Fixed
Nodes.removeIfInObject(...)to stay property-only: structural POJO fields are preserved, while removable JOJO dynamic entries and facade-backed object properties can still be deleted safely.
[1.2.2] - 2026.04.30
Added
- Added
Nodes.removeIfInObject(...)for safe in-place object-member removal during traversal against live object-key views. - Added
Sjf4j.bindNode(...)plusJsonContainer.bindNode(...)so callers can opt into alias-preserving node binding without the deep-copy isolation offromNode(...)/toNode(...).
Changed
- Changed schema registry naming to use
SchemaRegistryconsistently across schema compilation, export, loading, and validator APIs. - Changed schema validation diagnostics to report both instance and keyword JSON Pointer paths, and deprecated
ValidationMessage.getPs()in favor of structuredgetInstancePath()/getKeywordPath()accessors.
Removed
- Removed the old
SchemaStoretype and its legacytoStore()/compile(SchemaStore)naming in favor ofSchemaRegistryandtoRegistry().
Fixed
- Fixed
ObjectSchemapost-compile mutation paths to become read-only, preventing schema tree edits from drifting away from compiled evaluator and reference-resolution state. - Fixed
Nodes.removeInObject(...)to reject POJO structural field removal with the intended POJO-specific error path. - Fixed fail-fast schema validation diagnostics so nested failures like
additionalProperties: false, nestedtype, andpropertyNameserrors retain the offending instance member path alongside the triggering schema keyword path.
[1.2.1] - 2026.04.27
Added
- Added
Nodes.shape(...)andJsonContainer.shape()to produce compact inspect-style structural summaries that keep supported container structure while rendering terminal values by simple runtime type name. - Added Jackson 3 facade-node mutation support for object put/remove, array set/append/insert/remove, and JSONPath writes against Jackson 3 native tree nodes.
- Added
@NodeBinding(readDynamic = ... , writeDynamic = ...)for JOJO types so unknown-field retention on read and dynamic-property emission on write can be controlled per type. - Added instance-scoped
StreamingContext, facade providers, and newSjf4j.Builderhooks so each runtime can build isolated JSON/YAML/properties/node facades with its own streaming mode. - Added
ValueFormatMapping, namedValueCodecformats,Sjf4j.Builder.defaultValueFormat(...), and@NodeProperty(valueFormat = ...)so value-codec selection can be configured per runtime, field, and creator parameter. - Added
Sjf4j.Builder.includeNulls(...)so each runtime can choose whether JSON serialization keeps or omitsnullproperties across Gson, Jackson 2, Jackson 3, and Fastjson2 facades.
Changed
- Changed Jackson 2 and Fastjson2 exclusive streaming IO paths to use backend-native typed read/write implementations for POJOs, containers,
AnyOf, and value-codec flows while keeping sharedStreamingIOsemantics. - Changed shared and backend-native POJO object writing paths to use dedicated
writePojo(...)flows, keeping JOJO dynamic fields aligned across shared, Jackson 2, and Fastjson2 serializers. - Changed snake-case conversion to live in
Strings.toSnakeCase(...), withNamingStrategy.SNAKE_CASEdelegating to the shared helper. - Changed
SchemaValidatorconvention lookup to try<simple-name>.jsonfirst and then<snake-name>.json, instead of probing<full-class-name>.json. - Changed node traversal helper naming from
visit*/anyMatchIn*toforEach*/anyMatch*across shared node utilities and facade adapters. - Changed JSONPath missing-container creation to recognize Jackson 3 native object/array node types.
- Changed
NodesandJsonObjectobject views to expose readable members only, while keeping direct write paths available for writable-only bindings. - Changed shared and backend-native facade integrations to route through context-aware
StreamingIO, with plugin-module fallbacks for SJF4J-managed value-codec andAnyOfcases. - Changed Jackson 2 and Fastjson2 module reader/writer selection to resolve plain
JsonObject/JsonArrayseparately from JOJO/POJO metadata-backed types, preserving owner type information for generic bindings. - Changed path/schema traversal internals to use lighter
PathSegmentandInstancedNodemetadata while standardizing rooted error-path reporting on JSONPath and JSON Pointer expressions.
Fixed
- Fixed backend-native Jackson/Fastjson2 streaming and module paths to skip formatted value-codec resolution when a type has no registered codecs, reducing unnecessary metadata work and avoiding null-driven fallback drift.
- Fixed
JsonObjectwritable traversal so dynamic entries honorwriteDynamicduring backend-native object serialization. - Fixed
Typesgeneric substitution and resolution for parameterized types so raw-type preservation no longer depends on unsafeClasscasts. - Fixed
Nodes.to(...)so@NodeValueand registeredValueCodectarget types are converted through the shared node-facade binding path instead of failing as unsupported types. - Fixed facade-node access metadata so Jackson 2, Jackson 3, and Gson object members report insertable child slots consistently, and array access reports appendable tail positions without forcing out-of-range reads.
- Fixed
JsonPath.ensurePut(...)so single paths containing append segments (/-or[+]) can auto-create nested containers while appending new array elements. - Fixed shared/simple/Jackson/Fastjson2 readable-member serialization and POJO projection paths so write-only bindings no longer leak into object traversal or output.
- Fixed field- and creator-bound non-default value formats so shared IO, exclusive IO, plugin-module reads/writes, node conversion, and
Sjf4jruntime APIs all honor the same codec selection. - Fixed deferred parent-scope
AnyOfbinding and runtime node conversion paths to use the owningSjf4jinstance instead of process-global facade defaults.
[1.2.0] - 2026.04.12
Breaking Changes
Sjf4jis no longer a static facade. Migrate calls likeSjf4j.fromJson(...)toSjf4j.global().fromJson(...)for process-wide defaults, or create an isolated instance withnew Sjf4j()orSjf4j.builder().build().
Added
- Added Jackson 3 facade integration with runtime auto-detection, global config entry points, Jackson3
JsonNodesupport, and JDK 17 coverage/JMH evaluation. - Added container metadata and factory paths in
NodeRegistryfor concreteMap/List/Settarget types. - Added
@NodeBindingwith type-levelnamingandaccess = AccessStrategy.BEAN_BASED/FIELD_BASEDso POJO binding semantics are cached per type instead of driven by mutable global defaults.
Improved
- Improved
Nodes.to(...),NodeFacade.readNode(...), and streaming IO binding so concreteMap/List/Settargets are created with their declared container implementations when supported. - Improved
Nodes.copy(...)anddeepNode(...)to preserve concrete container types when possible and fall back to default mutable containers only on unsupported source implementations. - Improved streaming
AnyOfbinding by caching container element/valueAnyOfmetadata onFieldInfoand avoiding redundant runtimeTypeInfolookups on hot read paths. - Improved Gson facade integration by routing plugin-module reads and writes through shared
StreamingIO, removing the separate Gson-exclusive streaming path, and aligninghasAnywrite performance with native Gson baselines. - Improved plain-POJO fallback rules so default binding stays bean-oriented,
@NodePropertyis the only field-level force-bind signal, and record component accessors continue to work underBEAN_BASED. - Improved shared/Jackson/Gson/Fastjson2 streaming readers by separating raw node reads from typed dispatch, reducing duplicated
Object.classhot-path work and closing the Fastjson2 JOJO gap against native any-setter baselines. - Improved JSONPath/JSON Pointer handling so numeric pointer tokens preserve object-key semantics, filter strings unescape consistently, regex flags parse more strictly, and
&&/||short-circuit during filter evaluation.
Changed
- Changed
@AnyOf.Scope.SELFtoCURRENTfor discriminator lookup naming. - Changed
NodeRegistryPOJO routing flags from framework-centric reader/writer naming torequiresPojoReader/requiresPojoWriter, and removedPojoInfo.newCreationSession()in favor of directPojoCreationSessionconstruction. - Changed POJO metadata analysis to read naming and field-access strategy only from
@NodeBinding;@NodeNaminghas been removed. - Changed JSON Patch and RFC 7386 root-application APIs so
JsonPatch.apply(...),PatchOperation.apply(...),Patches.mergeRfc7386(...), and theJsonContainerwrappers return the possibly replaced root document.
Removed
- Breaking: removed
Sjf4j.toPojo(...)andSjf4j.mapperBuilder(...)from theSjf4jentry point; usefromNode(...)andNodeMapperBuilderdirectly instead.
Fixed
- Fixed binding consistency for concrete container fields and root targets across shared and exclusive streaming backends.
- Fixed transient-field precedence so transient members are always ignored first, and transient fields annotated with
@NodePropertynow fail fast during metadata analysis. - Fixed backend contract drift in tests and plugin-module routing for plain POJOs, including Gson/Fastjson2 private-field behavior under
BEAN_BASEDandFIELD_BASED. - Fixed Jackson/Jackson3 module installation so existing mapper annotation introspectors remain active alongside SJF4J
@NodePropertysupport. - Fixed JSON Pointer parsing to reject invalid
~escapes, preserve leading-zero numeric tokens, and route numeric pointer segments to object keys when the runtime container is object-shaped. - Fixed
stddev()to return standard deviation instead of variance, and reject terminal descendant paths like$..during compile time. - Fixed JSON Patch / Merge Patch semantics for root replacement,
copy/moveof explicitnull, deep-copycopy, atomicmove, and numeric leaf equality duringdiff. - Fixed JSON Schema compilation and validation edge cases so unknown keywords and formats are tolerated per draft 2020-12, local schemas without root
$idretain their retrieval URI base for relative$ref,nullsubschemas fail fast, string length uses Unicode code points, and strict format checks cover core hostname / IPv6 / URI-template / relative JSON Pointer cases. - Fixed JSON Schema resource URI bookkeeping by separating retrieval and canonical URIs during compile time, while keeping store registration keyed by canonical
$id-resolved resource URIs.
[1.1.6] - 2026.04.02
Added
- Added
JsonPath.compileCached(String)to provide an explicit cached compile path. - Added
PathCacheinterface with built-inConcurrentHashMapas default implementation. - Added
JsonPath.compute(...)overloads to update every matched target from its current content. - Added
NodeConverter,NodeMapper, andNodeMapperBuilderfor path-driven object graph mapping. - Added
NamingStrategyand@NodeNamingto map JSON property names likesnake_caseto Java fields without per-field annotations.
Improved
- Improved node conversion extensibility so exact source/target converters can participate in nested POJO and collection binding flows.
Changed
- Changed
new JsonArray(...)/new JsonObject(...)toJsonArray.of(...)andJsonObject.of(...)for simpler literal-style container creation. - Changed
SchemaValidatorto validate@ValidJsonSchemaalong class inheritance chains (parent and child annotations both applied).
Fixed
- Fixed inherited POJO field resolution when parent and child define the same key, ensuring child field metadata is preserved and parent metadata does not overwrite it.
[1.1.5] - 2026.03.11
Added
- Added
JSON-Pfacade integration with runtime auto-detection inFacadeFactory. - Added
AnyOfresolution support inStreamingFacadeandNodeFacade.
Improved
- Improved streaming read performance with an array container-kind fast path.
- Improved node conversion internals and reduced duplicated conversion paths in
SimpleNodeFacade. - Improved consistency of constructor discovery and AnyOf handling across streaming and node conversion pipelines.
Changed
- Changed
NodeFacadeconversion contract to supportreadNode(node, type, deepCopy)and route deep copy through a unified path. - Changed
Nodes.toPojo(...)to delegate POJO materialization toNodeFacadefor centralized conversion behavior. - Changed exception mapping to use more unified and compact binding/conversion error messages.
Fixed
- Fixed several semantic consistency issues across node/path/patch behavior.
- Fixed edge-case conversion mismatches in POJO and dynamic-field binding flows.
[1.1.4] - 2026.02.24
Added
- Added
@ValidJsonSchemaandSchemaValidatorfor schema-based validation. - Added
FacadeNodeswith backend adaptersJacksonNodesandGsonNodes. - Added/expanded tests for schema/path/facade/JDK17 scenarios.
Improved
- Optimized JSON Schema validation hot paths and compile/store flow.
- Improved consistency of streaming IO behavior across facades.
- Improved JsonPath internals by moving token model to segment model.
- Improved cross-module behavior consistency across node/path/patch operations.
Changed
- Renamed
NodeType->NodeKind. - Renamed
PathToken->PathSegment. - Renamed
PathUtil->Paths. - Renamed
PatchUtil->Patches. - Renamed annotations:
@Decode->@RawToValue@Encode->@ValueToRaw@Copy->@ValueCopy
Fixed
- Fixed multiple node/path/patch semantic alignment issues.
- Fixed schema loading/compilation edge cases and validation result handling.
- Fixed backend-specific streaming conversion consistency issues.
[1.1.3] - 2026.02.04
Added
- Added
skipNode()method toStreamingReaderinterface, enabling efficient skipping of entire JSON nodes during streaming parsing without fully deserializing them. - Added
@NodeCreatorannotation to support custom object construction with parameterized constructors.
Improved
- Enhanced POJO deserialization to automatically support Java records (JDK 14+). Record classes are now recognized and handled seamlessly, with their canonical constructors used for instantiation without requiring explicit
@NodeCreatorannotations. - Improved constructor parameter name resolution for
@NodeCreatorannotated constructors, supporting both@NodePropertyexplicit naming and automatic parameter name detection (when compiled with-parametersflag).
[1.1.1] - 2026.01.26
Fixed
- Make
SchemaStore.registerpublic
[1.1.0] - 2026.01.25
Added
- Introduced
JsonSchemamodule for JSON Schema validation (see: json-schema.org). Fully implements JSON Schema Draft 2020-12, with all official test cases passing. - Added
@NodeFieldannotation to allow custom mapping between POJO fields and node/property names.
Improved
- Unified and optimized
asMap,asList, andasArrayAPIs acrossNode,JsonObject, andJsonPathfor more consistent structural access.
Changed
- Renamed:
NodeUtiltoNodes - Renamed:
FunctionRegistrytoPathFunctionRegistry - Renamed:
@Convertibleto@NodeValue
Fixed
@NodeValuenow correctly supports annotation overrides in subclasses, even when the annotation is declared on a superclass.- Fixed incorrect detection logic for missing no-argument constructors in POJO binding scenarios.
[1.0.3] - 2026.01.04
Improved
- Differentiated the semantics of
equals()andnodeEquals() - Clarified the distinction between
toNode()anddeepNode() - Improved the output format of
inspect()
Changed
- Minor renaming and alignment of core API method names
Fixed
- Benchmark issues
[1.0.2] - 2025.12.25
Added
- Added support for JSON Patch (RFC 6902) via the
JsonPatchAPI. - Added the
JsonPointerclass, providing an API consistent withJsonPathwhile exclusively supporting JSON Pointer (RFC 6901) expressions. - Introduced the
@Convertibleannotation and theNodeRegistryclass to enable a pluggable custom type conversion mechanism. - Extended JsonPath filter expressions with the
=~operator, providing full regular expression matching support. - Added native support for
enumtypes.
Improved
- Optimized
JsonPathevaluation performance - Improved overall conversion and traversal efficiency
[1.0.1] - 2025.12.15
Added
- A simple build-in JSON reader/writer
- SJF4J now Fully Supports JSONPath.
- Added support for
FilterandFunction, including theeval()methods. - Added support for registering custom functions via
FunctionRegistry.
- Added support for
[1.0.0] - 2025.12.05
Added
- All this project.