SJF4J 1.2.0: Jackson 3 Support, Instance-Based Runtime, and More Predictable JSON Semantics

java dev.to

Java already has excellent JSON libraries. So why build another layer on top?

Because in real applications, JSON work is rarely just "parse this string into a POJO". It quickly expands into:

  • navigating nested structures
  • applying JSON Patch or Merge Patch
  • validating with JSON Schema
  • mapping between object graphs
  • keeping behavior consistent across Jackson, Gson, Fastjson2, JSON-P, YAML, and in-memory nodes

That is the problem space SJF4J is trying to solve.

SJF4J is a lightweight structural processing framework for Java that provides a unified JSON-semantic layer across different backends and data shapes. It works with regular POJOs, dynamic JSON-like structures, JSON Path, JSON Patch, JSON Schema, and multiple runtime backends, while keeping the programming model consistent.

Version 1.2.0 is an important release. It adds Jackson 3 support, introduces a cleaner instance-based runtime API, and tightens semantic consistency in several areas that matter in production systems.

What SJF4J Is

SJF4J is not trying to replace Jackson or Gson.

Instead, it sits one level above them and gives you a consistent structural API for:

  • modeling object-based node trees
  • parsing JSON and YAML
  • navigating with JSON Path and JSON Pointer
  • patching with JSON Patch and Merge Patch
  • validating with JSON Schema Draft 2020-12
  • mapping across native object graphs

It also supports runtime backend auto-detection, so the same SJF4J-facing code can work across multiple JSON libraries.

What’s New in 1.2.0

1. Jackson 3 support

SJF4J 1.2.0 adds Jackson 3 facade integration.

At runtime, SJF4J can automatically select an available backend in this priority order:

  • Jackson 3
  • Jackson 2
  • Gson
  • Fastjson2
  • JSON-P
  • built-in simple fallback

2. Sjf4j is now instance-based

This is the biggest API change in 1.2.0.

  • Sjf4j.global() for shared process-wide defaults
  • new Sjf4j() for a fresh default instance
  • Sjf4j.builder() for explicit runtime configuration

Migration example

Before:

User user = Sjf4j.fromJson(json, User.class);
Enter fullscreen mode Exit fullscreen mode

After:

User user = Sjf4j.global().fromJson(json, User.class);
Enter fullscreen mode Exit fullscreen mode

If you want an isolated runtime instead of global defaults:

Sjf4j sjf4j = Sjf4j.builder()
    .jsonFacade(new Jackson3JsonFacade())
    .build();

User user = sjf4j.fromJson(json, User.class);
Enter fullscreen mode Exit fullscreen mode

This change makes runtime configuration more explicit and easier to reason about, especially in applications that care about isolation, testing, or framework integration.

3. @NodeBinding makes POJO binding rules explicit

Another important addition in 1.2.0 is @NodeBinding.

It moves binding behavior like naming strategy and access policy onto the type itself, instead of relying on mutable global behavior.

For example:

@NodeBinding(naming = NamingStrategy.SNAKE_CASE)
class UserProfile {
    public String userName;
    public int loginCount;
}
Enter fullscreen mode Exit fullscreen mode

Now JSON like this:

{"user_name":"han","login_count":7}
Enter fullscreen mode Exit fullscreen mode

can map cleanly without per-field annotations.

You can also control access strategy:

@NodeBinding(access = AccessStrategy.FIELD_BASED)
class PrivateUserProfile {
    String userName;
    int loginCount;
}
Enter fullscreen mode Exit fullscreen mode

This is a good example of SJF4J’s overall direction in 1.2.0: make semantics more explicit, cacheable, and predictable.

4. Better consistency for containers and object graph conversion

SJF4J 1.2.0 improves how it handles concrete container types such as:

  • Map
  • List
  • Set

In previous edge cases, framework-level conversion could fall back to generic mutable containers even when more specific target container information was available. In 1.2.0, container metadata and factory paths are improved so declared concrete container implementations are preserved more consistently when supported.

This matters when your application logic depends on more than just the abstract interface type.

5. More correct behavior in Path, Patch, and Schema

This release also includes a long list of semantic fixes across some of the hardest parts of structured data processing.

JSON Schema Draft 2020-12

SJF4J already supports JSON Schema Draft 2020-12, and 1.2.0 improves several edge cases in compilation and validation, including:

  • unknown keywords and formats
  • relative $ref resolution
  • local schemas without root $id
  • null subschema handling
  • Unicode code point length for strings
  • stricter format checks for hostname, IPv6, URI template, and relative JSON Pointer

For teams using schema validation in production APIs, these details are much more important than flashy surface-level features.

Quick Start

If you want to try it:

Gradle

implementation("org.sjf4j:sjf4j:1.2.0")
Enter fullscreen mode Exit fullscreen mode

Maven

<dependency>
  <groupId>org.sjf4j</groupId>
  <artifactId>sjf4j</artifactId>
  <version>1.2.0</version>
</dependency>
Enter fullscreen mode Exit fullscreen mode

Then start with the global runtime:

Sjf4j sjf4j = Sjf4j.global();
User user = sjf4j.fromJson(json, User.class);
Enter fullscreen mode Exit fullscreen mode

Final Thoughts

SJF4J 1.2.0 feels like a solid step forward for Java developers who want a single structural programming model across different JSON backends and data-processing tasks.

If your application only needs plain Jackson databinding, you probably do not need another abstraction layer.

But if your system combines parsing, path navigation, patching, schema validation, dynamic fields, and backend flexibility, SJF4J is solving a real problem, and 1.2.0 makes that solution cleaner and more production-friendly.

Project links:

Source: dev.to

arrow_back Back to Tutorials