<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Yu Han</title>
    <description>The latest articles on DEV Community by Yu Han (@hannyu).</description>
    <link>https://dev.to/hannyu</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3695478%2F1408961a-08f6-449c-ae0d-167d9795cb8f.jpg</url>
      <title>DEV Community: Yu Han</title>
      <link>https://dev.to/hannyu</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/hannyu"/>
    <language>en</language>
    <item>
      <title>Structural Mapping with SJF4J</title>
      <dc:creator>Yu Han</dc:creator>
      <pubDate>Sat, 15 Aug 2026 15:36:53 +0000</pubDate>
      <link>https://dev.to/hannyu/structural-mapping-with-sjf4j-5ake</link>
      <guid>https://dev.to/hannyu/structural-mapping-with-sjf4j-5ake</guid>
      <description>&lt;p&gt;&lt;em&gt;Compile-time mapping does not have to stop at Java properties.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Java object mapping is usually expressed in terms of properties:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nd"&gt;@Mapping&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;target&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"displayName"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;source&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"name"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="nc"&gt;UserDto&lt;/span&gt; &lt;span class="nf"&gt;toDto&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;User&lt;/span&gt; &lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That model works well when both sides are ordinary Java objects.&lt;/p&gt;

&lt;p&gt;But structured data is often broader than a pair of Java types. A value may live several levels deep. The source may be a &lt;code&gt;Map&lt;/code&gt; or a JSON-like object. The target may itself be nested. A value may need to be assembled from several locations.&lt;/p&gt;

&lt;p&gt;SJF4J approaches these cases as &lt;strong&gt;structural mapping&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Instead of limiting mapping endpoints to Java properties, &lt;code&gt;@CompiledMapper&lt;/code&gt; can work with locations inside a structured object graph:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nd"&gt;@Mapping&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;source&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"$.customer.address.city"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;target&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"$.shipping.destination.city"&lt;/span&gt;
&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="nc"&gt;OrderView&lt;/span&gt; &lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Order&lt;/span&gt; &lt;span class="n"&gt;source&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The mapper still generates direct Java code at compile time.&lt;/p&gt;

&lt;p&gt;The difference is the abstraction it compiles.&lt;/p&gt;

&lt;h2&gt;
  
  
  The structural model behind it
&lt;/h2&gt;

&lt;p&gt;SJF4J is built around a common structural model called the &lt;strong&gt;Object-Based Node Tree (OBNT)&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;OBNT represents structured data using native Java objects. A POJO, &lt;code&gt;Map&lt;/code&gt;, or &lt;code&gt;JsonObject&lt;/code&gt; can represent a JSON object; a &lt;code&gt;List&lt;/code&gt;, array, or &lt;code&gt;JsonArray&lt;/code&gt; can represent a JSON array; ordinary Java scalar values represent JSON values.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fv0r5a086sdrvrc8g08dp.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fv0r5a086sdrvrc8g08dp.png" alt="OBNT" width="800" height="391"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The objects remain ordinary Java objects. SJF4J does not require them to be converted into an intermediate JSON tree before structural operations can be applied.&lt;/p&gt;

&lt;p&gt;The same OBNT model is shared across SJF4J's navigation, binding, patching, validation, and mapping APIs.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;@CompiledMapper&lt;/code&gt; builds compile-time transformation on top of that model. A mapping therefore operates on structure first; the concrete Java representation is simply how that structure happens to be stored.&lt;/p&gt;

&lt;h2&gt;
  
  
  Start with ordinary object mapping
&lt;/h2&gt;

&lt;p&gt;The simplest mapper remains familiar.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;User&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;age&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

    &lt;span class="c1"&gt;// getters and setters&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;UserDto&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;age&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

    &lt;span class="c1"&gt;// getters and setters&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Declare the mapper:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nd"&gt;@CompiledMapper&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;interface&lt;/span&gt; &lt;span class="nc"&gt;UserMapper&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="nc"&gt;UserDto&lt;/span&gt; &lt;span class="nf"&gt;toDto&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;User&lt;/span&gt; &lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then obtain the generated implementation:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nc"&gt;UserMapper&lt;/span&gt; &lt;span class="n"&gt;mapper&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;CompiledNodes&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;instanceOf&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;UserMapper&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;span class="nc"&gt;UserDto&lt;/span&gt; &lt;span class="n"&gt;dto&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;mapper&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;toDto&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Compatible members with matching names are mapped automatically.&lt;/p&gt;

&lt;p&gt;When names differ, describe only the difference:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nd"&gt;@CompiledMapper&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;interface&lt;/span&gt; &lt;span class="nc"&gt;UserMapper&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;

    &lt;span class="nd"&gt;@Mapping&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;target&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"displayName"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;source&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"name"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
    &lt;span class="nc"&gt;UserDto&lt;/span&gt; &lt;span class="nf"&gt;toDto&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;User&lt;/span&gt; &lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The annotation processor generates the implementation during compilation, so runtime mapping does not need reflective property discovery.&lt;/p&gt;

&lt;h2&gt;
  
  
  Map nested values directly
&lt;/h2&gt;

&lt;p&gt;Consider a source with nested data:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Alice"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"profile"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"address"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"city"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Seattle"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"country"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"US"&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The target may only need &lt;code&gt;city&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;With &lt;code&gt;@CompiledMapper&lt;/code&gt;, the mapping can describe the actual structural location:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nd"&gt;@CompiledMapper&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;interface&lt;/span&gt; &lt;span class="nc"&gt;UserMapper&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;

    &lt;span class="nd"&gt;@Mapping&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;target&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"city"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;source&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"$.profile.address.city"&lt;/span&gt;
    &lt;span class="o"&gt;)&lt;/span&gt;
    &lt;span class="nc"&gt;UserDto&lt;/span&gt; &lt;span class="nf"&gt;toDto&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;User&lt;/span&gt; &lt;span class="n"&gt;source&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The source can also be expressed as JSON Pointer:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nd"&gt;@CompiledMapper&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;interface&lt;/span&gt; &lt;span class="nc"&gt;UserMapper&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;

    &lt;span class="nd"&gt;@Mapping&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;target&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"country"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;source&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"/profile/address/country"&lt;/span&gt;
    &lt;span class="o"&gt;)&lt;/span&gt;
    &lt;span class="nc"&gt;UserDto&lt;/span&gt; &lt;span class="nf"&gt;toDto&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;User&lt;/span&gt; &lt;span class="n"&gt;source&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;There is no need to flatten the input model first or introduce another intermediate DTO just to expose the nested value.&lt;/p&gt;

&lt;h2&gt;
  
  
  Targets can be paths too
&lt;/h2&gt;

&lt;p&gt;Structural mapping works in both directions.&lt;/p&gt;

&lt;p&gt;A target can itself be nested:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nd"&gt;@CompiledMapper&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;interface&lt;/span&gt; &lt;span class="nc"&gt;UserMapper&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;

    &lt;span class="nd"&gt;@Mapping&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;target&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"$.profile.displayName"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;source&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"name"&lt;/span&gt;
    &lt;span class="o"&gt;)&lt;/span&gt;
    &lt;span class="nc"&gt;UserView&lt;/span&gt; &lt;span class="nf"&gt;toView&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;User&lt;/span&gt; &lt;span class="n"&gt;source&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Both sides can be structural locations:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nd"&gt;@CompiledMapper&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;interface&lt;/span&gt; &lt;span class="nc"&gt;OrderMapper&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;

    &lt;span class="nd"&gt;@Mapping&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;source&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"$.customer.address.city"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;target&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"$.shipping.destination.city"&lt;/span&gt;
    &lt;span class="o"&gt;)&lt;/span&gt;
    &lt;span class="nc"&gt;OrderView&lt;/span&gt; &lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Order&lt;/span&gt; &lt;span class="n"&gt;source&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;At this point, the mapping declaration is no longer just copying one property to another. It describes a transformation between locations in a structured object graph.&lt;/p&gt;

&lt;h2&gt;
  
  
  Maps and JSON-like objects use the same model
&lt;/h2&gt;

&lt;p&gt;A mapper does not require every source to be a dedicated Java class.&lt;/p&gt;

&lt;p&gt;For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nd"&gt;@CompiledMapper&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;interface&lt;/span&gt; &lt;span class="nc"&gt;UserMapper&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="nc"&gt;UserDto&lt;/span&gt; &lt;span class="nf"&gt;toDto&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Map&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;Object&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;source&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The reverse direction works as well:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nd"&gt;@CompiledMapper&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;interface&lt;/span&gt; &lt;span class="nc"&gt;UserMapper&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="nc"&gt;Map&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;Object&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;toMap&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;User&lt;/span&gt; &lt;span class="n"&gt;source&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;SJF4J's JSON-like objects participate in the same OBNT model.&lt;/p&gt;

&lt;p&gt;The point is not that every combination needs a special mapper. POJOs, maps, and JSON-like objects are simply different representations of structured data handled by the same mapping model.&lt;/p&gt;

&lt;h2&gt;
  
  
  Compute values from multiple sources
&lt;/h2&gt;

&lt;p&gt;Some target values naturally depend on more than one source location.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nd"&gt;@CompiledMapper&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;interface&lt;/span&gt; &lt;span class="nc"&gt;UserMapper&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;

    &lt;span class="nd"&gt;@Mapping&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;target&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"fullName"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;sources&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;&lt;span class="s"&gt;"firstName"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"lastName"&lt;/span&gt;&lt;span class="o"&gt;},&lt;/span&gt;
        &lt;span class="n"&gt;compute&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"(first, last) -&amp;gt; first + \" \" + last"&lt;/span&gt;
    &lt;span class="o"&gt;)&lt;/span&gt;
    &lt;span class="nc"&gt;UserDto&lt;/span&gt; &lt;span class="nf"&gt;toDto&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;User&lt;/span&gt; &lt;span class="n"&gt;source&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The computation is processed during annotation processing and emitted into the generated Java implementation.&lt;/p&gt;

&lt;p&gt;There is no runtime expression interpreter in the mapping path.&lt;/p&gt;

&lt;p&gt;Sources can also be nested paths:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nd"&gt;@CompiledMapper&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;interface&lt;/span&gt; &lt;span class="nc"&gt;UserMapper&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;

    &lt;span class="nd"&gt;@Mapping&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;target&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"fullName"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;sources&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="s"&gt;"$.profile.firstName"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
            &lt;span class="s"&gt;"$.profile.lastName"&lt;/span&gt;
        &lt;span class="o"&gt;},&lt;/span&gt;
        &lt;span class="n"&gt;compute&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"this::join"&lt;/span&gt;
    &lt;span class="o"&gt;)&lt;/span&gt;
    &lt;span class="nc"&gt;UserDto&lt;/span&gt; &lt;span class="nf"&gt;toDto&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;User&lt;/span&gt; &lt;span class="n"&gt;source&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;

    &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="nf"&gt;join&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;first&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;last&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;first&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="s"&gt;" "&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;last&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This lets the mapper describe both where values come from and how they are combined, while non-trivial logic remains ordinary Java code.&lt;/p&gt;

&lt;h2&gt;
  
  
  Structural sources beyond object graphs
&lt;/h2&gt;

&lt;p&gt;The same compile-time approach also applies to data that does not naturally look like a Java object graph.&lt;/p&gt;

&lt;p&gt;For JDBC results, SJF4J provides &lt;code&gt;@CompiledJdbcMapper&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nd"&gt;@CompiledJdbcMapper&lt;/span&gt;
&lt;span class="kd"&gt;interface&lt;/span&gt; &lt;span class="nc"&gt;UserJdbcMapper&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;

    &lt;span class="nd"&gt;@Mapping&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;target&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"name"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;source&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"full_name"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
    &lt;span class="nc"&gt;User&lt;/span&gt; &lt;span class="nf"&gt;user&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;ResultSet&lt;/span&gt; &lt;span class="n"&gt;resultSet&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The annotation processor generates the &lt;code&gt;ResultSet&lt;/code&gt; access and target assignments ahead of time.&lt;/p&gt;

&lt;p&gt;JDBC uses a dedicated mapper because a &lt;code&gt;ResultSet&lt;/code&gt; has its own access semantics, but the design remains consistent: describe the transformation and generate direct Java code at compile time.&lt;/p&gt;

&lt;h2&gt;
  
  
  Compile-time generation
&lt;/h2&gt;

&lt;p&gt;Add SJF4J and its annotation processor:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight groovy"&gt;&lt;code&gt;&lt;span class="n"&gt;implementation&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"org.sjf4j:sjf4j:{version}"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;annotationProcessor&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"org.sjf4j:sjf4j-processor:{version}"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For an interface such as:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nd"&gt;@CompiledMapper&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;interface&lt;/span&gt; &lt;span class="nc"&gt;UserMapper&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;

    &lt;span class="nd"&gt;@Mapping&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;target&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"displayName"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;source&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"name"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
    &lt;span class="nc"&gt;UserDto&lt;/span&gt; &lt;span class="nf"&gt;toDto&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;User&lt;/span&gt; &lt;span class="n"&gt;source&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;SJF4J generates ordinary Java code corresponding to the mapping.&lt;/p&gt;

&lt;p&gt;The generated implementation can directly read known members, navigate known structural paths, perform configured conversions, and assign target values.&lt;/p&gt;

&lt;p&gt;The mapping decisions are made during compilation rather than repeatedly resolved at runtime.&lt;/p&gt;

&lt;h2&gt;
  
  
  Performance
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;@CompiledMapper&lt;/code&gt; is included in the independent&lt;br&gt;
&lt;a href="https://github.com/arey/java-object-mapper-benchmark" rel="noopener noreferrer"&gt;Java Object Mapper Benchmark&lt;/a&gt;,&lt;br&gt;
which compares a range of Java object mapping frameworks on conventional object-to-object workloads.&lt;/p&gt;

&lt;p&gt;The benchmark covers the familiar Java object mapping case, while SJF4J's mapping model also extends to structural paths and other representations.&lt;/p&gt;

&lt;p&gt;See the independent&lt;br&gt;
&lt;a href="https://github.com/arey/java-object-mapper-benchmark" rel="noopener noreferrer"&gt;Java Object Mapper Benchmark&lt;/a&gt;&lt;br&gt;
for the full comparison.&lt;/p&gt;

&lt;h2&gt;
  
  
  Structural mapping
&lt;/h2&gt;

&lt;p&gt;SJF4J mapping is not primarily about adding more source and target types to a bean mapper.&lt;/p&gt;

&lt;p&gt;It is built on OBNT, the same structural model used across the framework. Properties, nested paths, maps, JSON-like objects, and other structured sources can participate in the same compile-time transformation model.&lt;/p&gt;

&lt;p&gt;That is what SJF4J means by &lt;strong&gt;structural mapping&lt;/strong&gt;.&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;Tags:&lt;/strong&gt; &lt;code&gt;java&lt;/code&gt; &lt;code&gt;json&lt;/code&gt; &lt;code&gt;mapping&lt;/code&gt; &lt;code&gt;performance&lt;/code&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Documentation: &lt;a href="https://sjf4j.org/docs/mapping" rel="noopener noreferrer"&gt;https://sjf4j.org/docs/mapping&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;GitHub: &lt;a href="https://github.com/sjf4j-projects/sjf4j" rel="noopener noreferrer"&gt;https://github.com/sjf4j-projects/sjf4j&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>java</category>
      <category>json</category>
      <category>programming</category>
      <category>opensource</category>
    </item>
    <item>
      <title>No parser. No interpreter. Just Java. That's how `@CompiledPath` gets so close to native performance.</title>
      <dc:creator>Yu Han</dc:creator>
      <pubDate>Wed, 10 Jun 2026 14:52:07 +0000</pubDate>
      <link>https://dev.to/hannyu/no-parser-no-interpreter-just-java-thats-how-compiledpath-gets-so-close-to-native-50cj</link>
      <guid>https://dev.to/hannyu/no-parser-no-interpreter-just-java-thats-how-compiledpath-gets-so-close-to-native-50cj</guid>
      <description>&lt;div class="ltag__link--embedded"&gt;
  &lt;div class="crayons-story "&gt;
  &lt;a href="https://dev.to/hannyu/143x-faster-jsonpath-by-removing-jsonpath-o79" class="crayons-story__hidden-navigation-link"&gt;143x Faster JSONPath by Removing JSONPath&lt;/a&gt;


  &lt;div class="crayons-story__body crayons-story__body-full_post"&gt;
    &lt;div class="crayons-story__top"&gt;
      &lt;div class="crayons-story__meta"&gt;
        &lt;div class="crayons-story__author-pic"&gt;

          &lt;a href="/hannyu" class="crayons-avatar  crayons-avatar--l  "&gt;
            &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3695478%2F1408961a-08f6-449c-ae0d-167d9795cb8f.jpg" alt="hannyu profile" class="crayons-avatar__image"&gt;
          &lt;/a&gt;
        &lt;/div&gt;
        &lt;div&gt;
          &lt;div&gt;
            &lt;a href="/hannyu" class="crayons-story__secondary fw-medium m:hidden"&gt;
              Yu Han
            &lt;/a&gt;
            &lt;div class="profile-preview-card relative mb-4 s:mb-0 fw-medium hidden m:inline-block"&gt;
              
                Yu Han
                
              
              &lt;div id="story-author-preview-content-3866547" class="profile-preview-card__content crayons-dropdown branded-7 p-4 pt-0"&gt;
                &lt;div class="gap-4 grid"&gt;
                  &lt;div class="-mt-4"&gt;
                    &lt;a href="/hannyu" class="flex"&gt;
                      &lt;span class="crayons-avatar crayons-avatar--xl mr-2 shrink-0"&gt;
                        &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3695478%2F1408961a-08f6-449c-ae0d-167d9795cb8f.jpg" class="crayons-avatar__image" alt=""&gt;
                      &lt;/span&gt;
                      &lt;span class="crayons-link crayons-subtitle-2 mt-5"&gt;Yu Han&lt;/span&gt;
                    &lt;/a&gt;
                  &lt;/div&gt;
                  &lt;div class="print-hidden"&gt;
                    
                      Follow
                    
                  &lt;/div&gt;
                  &lt;div class="author-preview-metadata-container"&gt;&lt;/div&gt;
                &lt;/div&gt;
              &lt;/div&gt;
            &lt;/div&gt;

          &lt;/div&gt;
          &lt;a href="https://dev.to/hannyu/143x-faster-jsonpath-by-removing-jsonpath-o79" class="crayons-story__tertiary fs-xs"&gt;&lt;time&gt;Jun 10&lt;/time&gt;&lt;span class="time-ago-indicator-initial-placeholder"&gt;&lt;/span&gt;&lt;/a&gt;
        &lt;/div&gt;
      &lt;/div&gt;

    &lt;/div&gt;

    &lt;div class="crayons-story__indention"&gt;
      &lt;h2 class="crayons-story__title crayons-story__title-full_post"&gt;
        &lt;a href="https://dev.to/hannyu/143x-faster-jsonpath-by-removing-jsonpath-o79" id="article-link-3866547"&gt;
          143x Faster JSONPath by Removing JSONPath
        &lt;/a&gt;
      &lt;/h2&gt;
        &lt;div class="crayons-story__tags"&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/java"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;java&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/json"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;json&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/performance"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;performance&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/opensource"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;opensource&lt;/a&gt;
        &lt;/div&gt;
      &lt;div class="crayons-story__bottom"&gt;
        &lt;div class="crayons-story__details"&gt;
          &lt;a href="https://dev.to/hannyu/143x-faster-jsonpath-by-removing-jsonpath-o79" class="crayons-btn crayons-btn--s crayons-btn--ghost crayons-btn--icon-left"&gt;
            &lt;div class="multiple_reactions_aggregate"&gt;
              &lt;span class="multiple_reactions_icons_container"&gt;
                  &lt;span class="crayons_icon_container"&gt;
                    &lt;img src="https://assets.dev.to/assets/exploding-head-daceb38d627e6ae9b730f36a1e390fca556a4289d5a41abb2c35068ad3e2c4b5.svg" width="18" height="18"&gt;
                  &lt;/span&gt;
              &lt;/span&gt;
              &lt;span class="aggregate_reactions_counter"&gt;1&lt;span class="hidden s:inline"&gt;&amp;nbsp;reaction&lt;/span&gt;&lt;/span&gt;
            &lt;/div&gt;
          &lt;/a&gt;
            &lt;a href="https://dev.to/hannyu/143x-faster-jsonpath-by-removing-jsonpath-o79#comments" class="crayons-btn crayons-btn--s crayons-btn--ghost crayons-btn--icon-left flex items-center"&gt;
              

              &lt;span class="hidden s:inline"&gt;Add&amp;nbsp;Comment&lt;/span&gt;
            &lt;/a&gt;
        &lt;/div&gt;
        &lt;div class="crayons-story__save"&gt;
          &lt;small class="crayons-story__tertiary fs-xs mr-2"&gt;
            4 min read
          &lt;/small&gt;
            
              &lt;span class="bm-initial crayons-icon c-btn__icon"&gt;
                

              &lt;/span&gt;
              &lt;span class="bm-success crayons-icon c-btn__icon"&gt;
                

              &lt;/span&gt;
            
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;/div&gt;


</description>
      <category>backend</category>
      <category>java</category>
      <category>performance</category>
      <category>showdev</category>
    </item>
    <item>
      <title>143x Faster JSONPath by Removing JSONPath</title>
      <dc:creator>Yu Han</dc:creator>
      <pubDate>Wed, 10 Jun 2026 14:43:15 +0000</pubDate>
      <link>https://dev.to/hannyu/143x-faster-jsonpath-by-removing-jsonpath-o79</link>
      <guid>https://dev.to/hannyu/143x-faster-jsonpath-by-removing-jsonpath-o79</guid>
      <description>&lt;p&gt;This benchmark result surprised even me:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Implementation&lt;/th&gt;
&lt;th&gt;Time&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Jayway JsonPath&lt;/td&gt;
&lt;td&gt;143.477 ns/op&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;SJF4J Runtime &lt;code&gt;JsonPath&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;26.284 ns/op&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;SJF4J APT-based &lt;code&gt;@CompiledPath&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;0.988 ns/op&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Native Java&lt;/td&gt;
&lt;td&gt;0.877 ns/op&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;For this simple path:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="err"&gt;$&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;store&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;bicycle&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;color&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;@CompiledPath&lt;/code&gt; is roughly &lt;strong&gt;143× faster than Jayway JsonPath&lt;/strong&gt; and nearly identical to hand-written Java code.&lt;/p&gt;

&lt;p&gt;How?&lt;/p&gt;

&lt;p&gt;The answer is surprisingly simple:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;code&gt;@CompiledPath&lt;/code&gt; does not make JSONPath interpretation faster.&lt;/p&gt;

&lt;p&gt;It removes JSONPath interpretation from the runtime entirely.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  The Hidden Cost of JSONPath
&lt;/h2&gt;

&lt;p&gt;Consider a typical JSONPath lookup:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;color&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;JsonPath&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;read&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;document&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
    &lt;span class="s"&gt;"$.store.bicycle.color"&lt;/span&gt;
&lt;span class="o"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Even when the expression is precompiled, the runtime still needs to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;walk path segments;&lt;/li&gt;
&lt;li&gt;inspect object types;&lt;/li&gt;
&lt;li&gt;navigate containers;&lt;/li&gt;
&lt;li&gt;resolve properties dynamically;&lt;/li&gt;
&lt;li&gt;return and convert the result.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That flexibility is exactly what makes JSONPath useful.&lt;/p&gt;

&lt;p&gt;But if the same path executes millions of times, the interpreter itself becomes part of the cost.&lt;/p&gt;

&lt;p&gt;The JVM would much rather execute something like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;color&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;store&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;bicycle&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;color&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;No parser.&lt;/p&gt;

&lt;p&gt;No AST.&lt;/p&gt;

&lt;p&gt;No reflection.&lt;/p&gt;

&lt;p&gt;No path interpreter.&lt;/p&gt;

&lt;p&gt;Just Java.&lt;/p&gt;




&lt;h2&gt;
  
  
  Turning JSONPath into Java Code
&lt;/h2&gt;

&lt;p&gt;With SJF4J, you declare a path interface:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nd"&gt;@CompiledPath&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;interface&lt;/span&gt; &lt;span class="nc"&gt;StorePaths&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;

    &lt;span class="nd"&gt;@GetByPath&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"$.store.bicycle.color"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
    &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="nf"&gt;color&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;BookStore&lt;/span&gt; &lt;span class="n"&gt;root&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;

&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And use it like any other Java API:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nc"&gt;StorePaths&lt;/span&gt; &lt;span class="n"&gt;paths&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;CompiledNodes&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;instanceOf&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;StorePaths&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;

&lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;color&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;paths&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;color&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;store&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;During compilation, the annotation processor generates an implementation.&lt;/p&gt;

&lt;p&gt;Conceptually, the generated code looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nd"&gt;@Override&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="nf"&gt;color&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;BookStore&lt;/span&gt; &lt;span class="n"&gt;root&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;root&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

    &lt;span class="nc"&gt;Store&lt;/span&gt; &lt;span class="n"&gt;store&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;root&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;store&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;store&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

    &lt;span class="nc"&gt;Bicycle&lt;/span&gt; &lt;span class="n"&gt;bicycle&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;store&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;bicycle&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;bicycle&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;bicycle&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;color&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That's the entire trick.&lt;/p&gt;

&lt;p&gt;There is no runtime JSONPath evaluation anymore.&lt;/p&gt;

&lt;p&gt;The generated method is simply normal Java code.&lt;/p&gt;




&lt;h2&gt;
  
  
  Why It Gets So Close to Native Speed
&lt;/h2&gt;

&lt;p&gt;The speedup comes from removing layers of work.&lt;/p&gt;

&lt;h3&gt;
  
  
  No Runtime Parser
&lt;/h3&gt;

&lt;p&gt;The path expression is processed during compilation.&lt;/p&gt;

&lt;p&gt;Nothing needs to be parsed when the application runs.&lt;/p&gt;

&lt;h3&gt;
  
  
  No Path Interpreter
&lt;/h3&gt;

&lt;p&gt;There is no AST traversal loop.&lt;/p&gt;

&lt;p&gt;There is no segment-dispatch mechanism.&lt;/p&gt;

&lt;p&gt;There is no dynamic path evaluation.&lt;/p&gt;

&lt;h3&gt;
  
  
  Direct Property Access
&lt;/h3&gt;

&lt;p&gt;The generated implementation can directly navigate:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;POJOs&lt;/li&gt;
&lt;li&gt;Records&lt;/li&gt;
&lt;li&gt;Maps&lt;/li&gt;
&lt;li&gt;Lists&lt;/li&gt;
&lt;li&gt;&lt;code&gt;JsonObject&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;JsonArray&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;using the most direct access strategy available.&lt;/p&gt;

&lt;h3&gt;
  
  
  JVM-Friendly Code
&lt;/h3&gt;

&lt;p&gt;Because the generated code looks like ordinary Java methods, the JIT compiler can inline and optimize it aggressively.&lt;/p&gt;

&lt;p&gt;From the JVM's perspective, there is nothing special happening.&lt;/p&gt;




&lt;h2&gt;
  
  
  Compile-Time Validation Included
&lt;/h2&gt;

&lt;p&gt;Performance is only part of the story.&lt;/p&gt;

&lt;p&gt;Because paths are analyzed during compilation, invalid paths fail the build.&lt;/p&gt;

&lt;p&gt;Suppose your model contains:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="n"&gt;store&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;book&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;but you accidentally write:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nd"&gt;@GetByPath&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"$.store.books.price"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Instead of discovering the problem in production, compilation fails immediately:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Unknown property 'books' on Store
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The path becomes part of your application's contract.&lt;/p&gt;

&lt;p&gt;If you've used MapStruct, QueryDSL, or jOOQ, the experience will feel familiar.&lt;/p&gt;




&lt;h2&gt;
  
  
  Reads and Writes
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;@CompiledPath&lt;/code&gt; supports both read and write operations.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nd"&gt;@CompiledPath&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;interface&lt;/span&gt; &lt;span class="nc"&gt;StorePaths&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;

    &lt;span class="nd"&gt;@GetByPath&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"$.store.book[{idx}].price"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
    &lt;span class="nc"&gt;Double&lt;/span&gt; &lt;span class="nf"&gt;bookPrice&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;BookStore&lt;/span&gt; &lt;span class="n"&gt;root&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;idx&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;

    &lt;span class="nd"&gt;@PutByPath&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"$.store.book[{idx}].price"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
    &lt;span class="nc"&gt;Double&lt;/span&gt; &lt;span class="nf"&gt;replaceBookPrice&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;
        &lt;span class="nc"&gt;BookStore&lt;/span&gt; &lt;span class="n"&gt;root&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
        &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;idx&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
        &lt;span class="nc"&gt;Double&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt;
    &lt;span class="o"&gt;);&lt;/span&gt;

    &lt;span class="nd"&gt;@EnsurePutByPath&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"$.store.bicycle.price"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
    &lt;span class="nc"&gt;Double&lt;/span&gt; &lt;span class="nf"&gt;ensureBicyclePrice&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;
        &lt;span class="nc"&gt;BookStore&lt;/span&gt; &lt;span class="n"&gt;root&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
        &lt;span class="nc"&gt;Double&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt;
    &lt;span class="o"&gt;);&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Dynamic placeholders are mapped directly from method parameters:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nd"&gt;@GetByPath&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"$.users[{idx}].profile[{key}]"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="nc"&gt;Object&lt;/span&gt; &lt;span class="nf"&gt;value&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Model&lt;/span&gt; &lt;span class="n"&gt;root&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;idx&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;int&lt;/code&gt; parameters address array/list indexes&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;String&lt;/code&gt; parameters address object keys&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The generated implementation performs direct navigation without evaluating a runtime expression tree.&lt;/p&gt;




&lt;h2&gt;
  
  
  Benchmark Snapshot
&lt;/h2&gt;

&lt;p&gt;The following benchmark was executed against the same object graph:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Operation&lt;/th&gt;
&lt;th&gt;Runtime &lt;code&gt;JsonPath&lt;/code&gt;
&lt;/th&gt;
&lt;th&gt;&lt;code&gt;@CompiledPath&lt;/code&gt;&lt;/th&gt;
&lt;th&gt;Native Java&lt;/th&gt;
&lt;th&gt;Speedup&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;get_bookPrice&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;92.485 ns/op&lt;/td&gt;
&lt;td&gt;1.793 ns/op&lt;/td&gt;
&lt;td&gt;1.627 ns/op&lt;/td&gt;
&lt;td&gt;51.58×&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;get_color&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;91.491 ns/op&lt;/td&gt;
&lt;td&gt;0.988 ns/op&lt;/td&gt;
&lt;td&gt;0.877 ns/op&lt;/td&gt;
&lt;td&gt;92.60×&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;get_price&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;80.996 ns/op&lt;/td&gt;
&lt;td&gt;0.984 ns/op&lt;/td&gt;
&lt;td&gt;0.949 ns/op&lt;/td&gt;
&lt;td&gt;82.31×&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;put_bookPrice&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;99.874 ns/op&lt;/td&gt;
&lt;td&gt;18.911 ns/op&lt;/td&gt;
&lt;td&gt;18.697 ns/op&lt;/td&gt;
&lt;td&gt;5.28×&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;put_price&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;86.607 ns/op&lt;/td&gt;
&lt;td&gt;19.587 ns/op&lt;/td&gt;
&lt;td&gt;19.157 ns/op&lt;/td&gt;
&lt;td&gt;4.42×&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The exact numbers depend on the model, JVM, hardware, and path shape.&lt;/p&gt;

&lt;p&gt;The architectural takeaway is more important:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;code&gt;@CompiledPath&lt;/code&gt; moves path resolution from runtime to build time.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  When Should You Use It?
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;@CompiledPath&lt;/code&gt; is a good fit when:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;path expressions are known during development;&lt;/li&gt;
&lt;li&gt;the same paths execute frequently;&lt;/li&gt;
&lt;li&gt;performance matters;&lt;/li&gt;
&lt;li&gt;compile-time safety is desirable.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Typical use cases include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;validation engines;&lt;/li&gt;
&lt;li&gt;pricing systems;&lt;/li&gt;
&lt;li&gt;routing rules;&lt;/li&gt;
&lt;li&gt;DTO projections;&lt;/li&gt;
&lt;li&gt;data transformation pipelines;&lt;/li&gt;
&lt;li&gt;high-frequency service code.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For user-supplied or highly dynamic expressions, runtime &lt;code&gt;JsonPath&lt;/code&gt; remains the right tool.&lt;/p&gt;

&lt;p&gt;The two approaches are complementary.&lt;/p&gt;




&lt;h2&gt;
  
  
  Setup
&lt;/h2&gt;

&lt;p&gt;Add the annotation processor:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight groovy"&gt;&lt;code&gt;&lt;span class="n"&gt;dependencies&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;implementation&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"org.sjf4j:sjf4j:{version}"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;annotationProcessor&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"org.sjf4j:sjf4j-processor:{version}"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The implementation classes are generated automatically during compilation.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Real Idea
&lt;/h2&gt;

&lt;p&gt;Most JSONPath libraries focus on evaluating path expressions as efficiently as possible.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;@CompiledPath&lt;/code&gt; takes a different route.&lt;/p&gt;

&lt;p&gt;Instead of optimizing the interpreter, it removes the interpreter.&lt;/p&gt;

&lt;p&gt;The path expression becomes Java code.&lt;/p&gt;

&lt;p&gt;And once that happens, the JVM can optimize it exactly like code you wrote yourself.&lt;/p&gt;

&lt;p&gt;That is how a JSONPath expression ends up running at nearly the same speed as native Java.&lt;/p&gt;

&lt;h2&gt;
  
  
  Learn More
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Home: &lt;a href="https://sjf4j.org" rel="noopener noreferrer"&gt;https://sjf4j.org&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;GitHub: &lt;a href="https://github.com/sjf4j-projects/sjf4j" rel="noopener noreferrer"&gt;https://github.com/sjf4j-projects/sjf4j&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Navigating (JSON Path): &lt;a href="https://sjf4j.org/docs/navigating" rel="noopener noreferrer"&gt;https://sjf4j.org/docs/navigating&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Benchmarks: &lt;a href="https://sjf4j.org/docs/benchmarks#json-path-benchmark" rel="noopener noreferrer"&gt;https://sjf4j.org/docs/benchmarks#json-path-benchmark&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>java</category>
      <category>json</category>
      <category>performance</category>
      <category>opensource</category>
    </item>
    <item>
      <title>No JSON round trip! No ugly generated maps!</title>
      <dc:creator>Yu Han</dc:creator>
      <pubDate>Fri, 29 May 2026 10:50:25 +0000</pubDate>
      <link>https://dev.to/hannyu/no-json-round-trip-no-ugly-generated-maps-574a</link>
      <guid>https://dev.to/hannyu/no-json-round-trip-no-ugly-generated-maps-574a</guid>
      <description>&lt;div class="ltag__link--embedded"&gt;
  &lt;div class="crayons-story "&gt;
  &lt;a href="https://dev.to/hannyu/json-schema-to-java-a-better-object-model-50h0" class="crayons-story__hidden-navigation-link"&gt;JSON Schema to Java: A Better Object Model&lt;/a&gt;


  &lt;div class="crayons-story__body crayons-story__body-full_post"&gt;
    &lt;div class="crayons-story__top"&gt;
      &lt;div class="crayons-story__meta"&gt;
        &lt;div class="crayons-story__author-pic"&gt;

          &lt;a href="/hannyu" class="crayons-avatar  crayons-avatar--l  "&gt;
            &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3695478%2F1408961a-08f6-449c-ae0d-167d9795cb8f.jpg" alt="hannyu profile" class="crayons-avatar__image"&gt;
          &lt;/a&gt;
        &lt;/div&gt;
        &lt;div&gt;
          &lt;div&gt;
            &lt;a href="/hannyu" class="crayons-story__secondary fw-medium m:hidden"&gt;
              Yu Han
            &lt;/a&gt;
            &lt;div class="profile-preview-card relative mb-4 s:mb-0 fw-medium hidden m:inline-block"&gt;
              
                Yu Han
                
              
              &lt;div id="story-author-preview-content-3777572" class="profile-preview-card__content crayons-dropdown branded-7 p-4 pt-0"&gt;
                &lt;div class="gap-4 grid"&gt;
                  &lt;div class="-mt-4"&gt;
                    &lt;a href="/hannyu" class="flex"&gt;
                      &lt;span class="crayons-avatar crayons-avatar--xl mr-2 shrink-0"&gt;
                        &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3695478%2F1408961a-08f6-449c-ae0d-167d9795cb8f.jpg" class="crayons-avatar__image" alt=""&gt;
                      &lt;/span&gt;
                      &lt;span class="crayons-link crayons-subtitle-2 mt-5"&gt;Yu Han&lt;/span&gt;
                    &lt;/a&gt;
                  &lt;/div&gt;
                  &lt;div class="print-hidden"&gt;
                    
                      Follow
                    
                  &lt;/div&gt;
                  &lt;div class="author-preview-metadata-container"&gt;&lt;/div&gt;
                &lt;/div&gt;
              &lt;/div&gt;
            &lt;/div&gt;

          &lt;/div&gt;
          &lt;a href="https://dev.to/hannyu/json-schema-to-java-a-better-object-model-50h0" class="crayons-story__tertiary fs-xs"&gt;&lt;time&gt;May 29&lt;/time&gt;&lt;span class="time-ago-indicator-initial-placeholder"&gt;&lt;/span&gt;&lt;/a&gt;
        &lt;/div&gt;
      &lt;/div&gt;

    &lt;/div&gt;

    &lt;div class="crayons-story__indention"&gt;
      &lt;h2 class="crayons-story__title crayons-story__title-full_post"&gt;
        &lt;a href="https://dev.to/hannyu/json-schema-to-java-a-better-object-model-50h0" id="article-link-3777572"&gt;
          JSON Schema to Java: A Better Object Model
        &lt;/a&gt;
      &lt;/h2&gt;
        &lt;div class="crayons-story__tags"&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/java"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;java&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/jsonschema"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;jsonschema&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/codegen"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;codegen&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/performance"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;performance&lt;/a&gt;
        &lt;/div&gt;
      &lt;div class="crayons-story__bottom"&gt;
        &lt;div class="crayons-story__details"&gt;
          &lt;a href="https://dev.to/hannyu/json-schema-to-java-a-better-object-model-50h0" class="crayons-btn crayons-btn--s crayons-btn--ghost crayons-btn--icon-left"&gt;
            &lt;div class="multiple_reactions_aggregate"&gt;
              &lt;span class="multiple_reactions_icons_container"&gt;
                  &lt;span class="crayons_icon_container"&gt;
                    &lt;img src="https://assets.dev.to/assets/sparkle-heart-5f9bee3767e18deb1bb725290cb151c25234768a0e9a2bd39370c382d02920cf.svg" width="18" height="18"&gt;
                  &lt;/span&gt;
              &lt;/span&gt;
              &lt;span class="aggregate_reactions_counter"&gt;1&lt;span class="hidden s:inline"&gt;&amp;nbsp;reaction&lt;/span&gt;&lt;/span&gt;
            &lt;/div&gt;
          &lt;/a&gt;
            &lt;a href="https://dev.to/hannyu/json-schema-to-java-a-better-object-model-50h0#comments" class="crayons-btn crayons-btn--s crayons-btn--ghost crayons-btn--icon-left flex items-center"&gt;
              

              &lt;span class="hidden s:inline"&gt;Add&amp;nbsp;Comment&lt;/span&gt;
            &lt;/a&gt;
        &lt;/div&gt;
        &lt;div class="crayons-story__save"&gt;
          &lt;small class="crayons-story__tertiary fs-xs mr-2"&gt;
            3 min read
          &lt;/small&gt;
            
              &lt;span class="bm-initial"&gt;
                

              &lt;/span&gt;
              &lt;span class="bm-success"&gt;
                

              &lt;/span&gt;
            
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;/div&gt;


</description>
    </item>
    <item>
      <title>JSON Schema to Java: A Better Object Model</title>
      <dc:creator>Yu Han</dc:creator>
      <pubDate>Fri, 29 May 2026 10:47:06 +0000</pubDate>
      <link>https://dev.to/hannyu/json-schema-to-java-a-better-object-model-50h0</link>
      <guid>https://dev.to/hannyu/json-schema-to-java-a-better-object-model-50h0</guid>
      <description>&lt;p&gt;Start with a simple schema:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"$schema"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"https://json-schema.org/draft/2020-12/schema"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"title"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Order"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"object"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"required"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"id"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"amount"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"customer"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"properties"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"string"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"amount"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"number"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"customer"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"object"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"properties"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"email"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"string"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Because &lt;code&gt;additionalProperties&lt;/code&gt; defaults to &lt;code&gt;true&lt;/code&gt;, many JSON Schema-to-Java generators produce a POJO like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Order&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;BigDecimal&lt;/span&gt; &lt;span class="n"&gt;amount&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;Customer&lt;/span&gt; &lt;span class="n"&gt;customer&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;Map&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;Object&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;additionalProperties&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;LinkedHashMap&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;gt;();&lt;/span&gt;

    &lt;span class="c1"&gt;// normal getters and setters...&lt;/span&gt;

    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;Map&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;Object&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;getAdditionalProperties&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;additionalProperties&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It works.&lt;/p&gt;

&lt;p&gt;But it is ugly.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;additionalProperties&lt;/code&gt; is a JSON Schema concept. Exposing it as part of every generated Java model leaks schema internals into your application API.&lt;/p&gt;

&lt;p&gt;Generated code is still code. Developers read it, debug it, autocomplete it, and often build long-lived systems around it. So the generated model should look like Java, not like a schema engine dump.&lt;/p&gt;

&lt;h2&gt;
  
  
  A cleaner approach
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://github.com/sjf4j-projects/sjf4j" rel="noopener noreferrer"&gt;SJF4J&lt;/a&gt; takes a different route.&lt;/p&gt;

&lt;p&gt;Instead of forcing dynamic JSON properties into a public &lt;code&gt;additionalProperties&lt;/code&gt; map, SJF4J can generate JOJO-style models: Java objects that extend &lt;code&gt;JsonObject&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Order&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;JsonObject&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;BigDecimal&lt;/span&gt; &lt;span class="n"&gt;amount&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;Customer&lt;/span&gt; &lt;span class="n"&gt;customer&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

    &lt;span class="c1"&gt;// normal getters and setters...&lt;/span&gt;

    &lt;span class="c1"&gt;// no generated additionalProperties map&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;No &lt;code&gt;getAdditionalProperties()&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The model stays clean, while still supporting JSON-style dynamic properties when the schema allows them. The object model carries the dynamic behavior; the generated Java API does not have to expose a schema keyword as a public map.&lt;/p&gt;

&lt;p&gt;If the schema says &lt;code&gt;additionalProperties: false&lt;/code&gt;, SJF4J can also generate stricter POJO-style models or disable dynamic reads depending on the selected strategy.&lt;/p&gt;

&lt;h2&gt;
  
  
  Online generator
&lt;/h2&gt;

&lt;p&gt;You can try it here:&lt;/p&gt;

&lt;p&gt;👉 &lt;a href="https://sjf4j.org/generator" rel="noopener noreferrer"&gt;https://sjf4j.org/generator&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The generator supports options like:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;JOJO or POJO modeling&lt;/li&gt;
&lt;li&gt;Lombok or explicit getters/setters&lt;/li&gt;
&lt;li&gt;validation annotations&lt;/li&gt;
&lt;li&gt;enum/date/time mapping&lt;/li&gt;
&lt;li&gt;path-only models&lt;/li&gt;
&lt;li&gt;generated JSON Path accessors&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So a nested schema field can become a convenient Java method instead of boilerplate object walking.&lt;/p&gt;

&lt;h2&gt;
  
  
  Direct schema validation on Java objects
&lt;/h2&gt;

&lt;p&gt;The other important part: SJF4J validates Java object graphs directly against JSON Schema.&lt;/p&gt;

&lt;p&gt;Typical validation often looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Java object -&amp;gt; JSON string -&amp;gt; JSON tree -&amp;gt; schema validation
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;SJF4J avoids that extra round trip.  &lt;/p&gt;

&lt;p&gt;A schema can be compiled into a &lt;code&gt;SchemaPlan&lt;/code&gt; and applied directly to a Java object, including a plain POJO:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nc"&gt;SchemaPlan&lt;/span&gt; &lt;span class="n"&gt;plan&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;JsonSchema&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;fromJson&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;schemaText&lt;/span&gt;&lt;span class="o"&gt;).&lt;/span&gt;&lt;span class="na"&gt;createPlan&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
&lt;span class="nc"&gt;ValidationResult&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;plan&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;validate&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;order&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you want to bind the schema to the generated Java model, you can declare the schema reference on the class:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nd"&gt;@ValidJsonSchema&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ref&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"Order.json"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Order&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;JsonObject&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// generated fields&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The schema can live as a normal classpath resource, for example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;src/main/resources/json-schemas/Order.json
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then validation becomes even more direct:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nc"&gt;SchemaValidator&lt;/span&gt; &lt;span class="n"&gt;validator&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;SchemaValidator&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
&lt;span class="nc"&gt;ValidationResult&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;validator&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;validate&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;order&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The schema lookup and compiled validation plan can be cached and reused, which makes this model suitable for hot paths as well.&lt;/p&gt;

&lt;p&gt;No serialization.&lt;br&gt;&lt;br&gt;
No parsing back into a JSON tree.&lt;br&gt;&lt;br&gt;
Just JSON Schema semantics applied to the Java object graph.&lt;/p&gt;

&lt;p&gt;That is simpler and faster.&lt;/p&gt;

&lt;p&gt;SJF4J supports JSON Schema Draft 2020-12 / 2019-09 / draft-07 and performs well in public benchmarks such as Creek Service:&lt;/p&gt;

&lt;p&gt;👉 &lt;a href="https://www.creekservice.org/json-schema-validation-comparison/" rel="noopener noreferrer"&gt;https://www.creekservice.org/json-schema-validation-comparison/&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The bigger picture
&lt;/h2&gt;

&lt;p&gt;JSON Schema should be more than a document-bound validation format.&lt;/p&gt;

&lt;p&gt;In Java applications, the data often already exists as objects. The interesting question is whether JSON semantics can operate on those objects directly.&lt;/p&gt;

&lt;p&gt;SJF4J's answer is yes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;generate Java-friendly models from JSON Schema&lt;/li&gt;
&lt;li&gt;keep dynamic object behavior available when the schema allows it&lt;/li&gt;
&lt;li&gt;validate native Java object graphs without a JSON round trip&lt;/li&gt;
&lt;li&gt;use the same object graph with JSON Path, JSON Pointer, JSON Patch, and mapping APIs&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That is the larger model: schema, validation, navigation, and transformation working on the same in-memory Java structure.&lt;/p&gt;

&lt;p&gt;Try it:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Generator: &lt;a href="https://sjf4j.org/generator" rel="noopener noreferrer"&gt;https://sjf4j.org/generator&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Project: &lt;a href="https://github.com/sjf4j-projects/sjf4j" rel="noopener noreferrer"&gt;https://github.com/sjf4j-projects/sjf4j&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Benchmarks: &lt;a href="https://sjf4j.org/docs/benchmarks" rel="noopener noreferrer"&gt;https://sjf4j.org/docs/benchmarks&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Curious what others think:&lt;/p&gt;

&lt;p&gt;Should JSON Schema in Java stay tied to serialized JSON documents, or should JSON semantics work directly on native Java object graphs?&lt;/p&gt;

</description>
      <category>java</category>
      <category>jsonschema</category>
      <category>codegen</category>
      <category>performance</category>
    </item>
    <item>
      <title>SJF4J makes Java JSON Schema validation fast not just by validating quickly, but by avoiding the extra JSON-tree step entirely.</title>
      <dc:creator>Yu Han</dc:creator>
      <pubDate>Wed, 13 May 2026 08:40:39 +0000</pubDate>
      <link>https://dev.to/hannyu/sjf4j-makes-java-json-schema-validation-fast-not-just-by-validating-quickly-but-by-avoiding-the-1jdn</link>
      <guid>https://dev.to/hannyu/sjf4j-makes-java-json-schema-validation-fast-not-just-by-validating-quickly-but-by-avoiding-the-1jdn</guid>
      <description>&lt;div class="ltag__link--embedded"&gt;
  &lt;div class="crayons-story "&gt;
  &lt;a href="https://dev.to/hannyu/is-sjf4j-the-fastest-json-schema-validator-for-java-fhb" class="crayons-story__hidden-navigation-link"&gt;Is SJF4J the fastest JSON Schema validator for Java?&lt;/a&gt;


  &lt;div class="crayons-story__body crayons-story__body-full_post"&gt;
    &lt;div class="crayons-story__top"&gt;
      &lt;div class="crayons-story__meta"&gt;
        &lt;div class="crayons-story__author-pic"&gt;

          &lt;a href="/hannyu" class="crayons-avatar  crayons-avatar--l  "&gt;
            &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3695478%2F1408961a-08f6-449c-ae0d-167d9795cb8f.jpg" alt="hannyu profile" class="crayons-avatar__image"&gt;
          &lt;/a&gt;
        &lt;/div&gt;
        &lt;div&gt;
          &lt;div&gt;
            &lt;a href="/hannyu" class="crayons-story__secondary fw-medium m:hidden"&gt;
              Yu Han
            &lt;/a&gt;
            &lt;div class="profile-preview-card relative mb-4 s:mb-0 fw-medium hidden m:inline-block"&gt;
              
                Yu Han
                
                
              
              &lt;div id="story-author-preview-content-3661399" class="profile-preview-card__content crayons-dropdown branded-7 p-4 pt-0"&gt;
                &lt;div class="gap-4 grid"&gt;
                  &lt;div class="-mt-4"&gt;
                    &lt;a href="/hannyu" class="flex"&gt;
                      &lt;span class="crayons-avatar crayons-avatar--xl mr-2 shrink-0"&gt;
                        &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3695478%2F1408961a-08f6-449c-ae0d-167d9795cb8f.jpg" class="crayons-avatar__image" alt=""&gt;
                      &lt;/span&gt;
                      &lt;span class="crayons-link crayons-subtitle-2 mt-5"&gt;Yu Han&lt;/span&gt;
                    &lt;/a&gt;
                  &lt;/div&gt;
                  &lt;div class="print-hidden"&gt;
                    
                      Follow
                    
                  &lt;/div&gt;
                  &lt;div class="author-preview-metadata-container"&gt;&lt;/div&gt;
                &lt;/div&gt;
              &lt;/div&gt;
            &lt;/div&gt;

          &lt;/div&gt;
          &lt;a href="https://dev.to/hannyu/is-sjf4j-the-fastest-json-schema-validator-for-java-fhb" class="crayons-story__tertiary fs-xs"&gt;&lt;time&gt;May 13&lt;/time&gt;&lt;span class="time-ago-indicator-initial-placeholder"&gt;&lt;/span&gt;&lt;/a&gt;
        &lt;/div&gt;
      &lt;/div&gt;

    &lt;/div&gt;

    &lt;div class="crayons-story__indention"&gt;
      &lt;h2 class="crayons-story__title crayons-story__title-full_post"&gt;
        &lt;a href="https://dev.to/hannyu/is-sjf4j-the-fastest-json-schema-validator-for-java-fhb" id="article-link-3661399"&gt;
          Is SJF4J the fastest JSON Schema validator for Java?
        &lt;/a&gt;
      &lt;/h2&gt;
        &lt;div class="crayons-story__tags"&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/java"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;java&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/jsonschema"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;jsonschema&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/opensource"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;opensource&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/performance"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;performance&lt;/a&gt;
        &lt;/div&gt;
      &lt;div class="crayons-story__bottom"&gt;
        &lt;div class="crayons-story__details"&gt;
          &lt;a href="https://dev.to/hannyu/is-sjf4j-the-fastest-json-schema-validator-for-java-fhb" class="crayons-btn crayons-btn--s crayons-btn--ghost crayons-btn--icon-left"&gt;
            &lt;div class="multiple_reactions_aggregate"&gt;
              &lt;span class="multiple_reactions_icons_container"&gt;
                  &lt;span class="crayons_icon_container"&gt;
                    &lt;img src="https://assets.dev.to/assets/multi-unicorn-b44d6f8c23cdd00964192bedc38af3e82463978aa611b4365bd33a0f1f4f3e97.svg" width="18" height="18"&gt;
                  &lt;/span&gt;
              &lt;/span&gt;
              &lt;span class="aggregate_reactions_counter"&gt;1&lt;span class="hidden s:inline"&gt;&amp;nbsp;reaction&lt;/span&gt;&lt;/span&gt;
            &lt;/div&gt;
          &lt;/a&gt;
            &lt;a href="https://dev.to/hannyu/is-sjf4j-the-fastest-json-schema-validator-for-java-fhb#comments" class="crayons-btn crayons-btn--s crayons-btn--ghost crayons-btn--icon-left flex items-center"&gt;
              

              &lt;span class="hidden s:inline"&gt;Add&amp;nbsp;Comment&lt;/span&gt;
            &lt;/a&gt;
        &lt;/div&gt;
        &lt;div class="crayons-story__save"&gt;
          &lt;small class="crayons-story__tertiary fs-xs mr-2"&gt;
            4 min read
          &lt;/small&gt;
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;/div&gt;


</description>
    </item>
    <item>
      <title>Is SJF4J the fastest JSON Schema validator for Java?</title>
      <dc:creator>Yu Han</dc:creator>
      <pubDate>Wed, 13 May 2026 08:38:55 +0000</pubDate>
      <link>https://dev.to/hannyu/is-sjf4j-the-fastest-json-schema-validator-for-java-fhb</link>
      <guid>https://dev.to/hannyu/is-sjf4j-the-fastest-json-schema-validator-for-java-fhb</guid>
      <description>&lt;p&gt;If you benchmark JSON Schema validators in Java, one question matters more than it first appears:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;does the validator work directly on your Java object graph, or does it first force you through a JSON tree?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;SJF4J is built around the first path.&lt;/p&gt;

&lt;p&gt;That is why the recent independent benchmark work from Creek Service is interesting.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F22v202g2zo0p7s1vwnfs.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F22v202g2zo0p7s1vwnfs.png" alt="validation performance" width="799" height="368"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Because SJF4J's story is not just "we are fast".&lt;/p&gt;

&lt;p&gt;It is: &lt;strong&gt;we avoid work that many Java validation pipelines still force you to do.&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  An independent signal worth paying attention to
&lt;/h2&gt;

&lt;p&gt;Creek Service maintains an independent comparison of JVM JSON Schema validators:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.creekservice.org/json-schema-validation-comparison/" rel="noopener noreferrer"&gt;JSON Schema validator comparison&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.creekservice.org/json-schema-validation-comparison/performance" rel="noopener noreferrer"&gt;Performance comparison&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;What makes this benchmark especially useful is that it looks at validation from two angles:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;pure validation&lt;/strong&gt; against the JSON Schema test suite&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;serde-style workflows&lt;/strong&gt;, where data is serialized, validated, read back, validated again, and deserialized&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The first tells you whether a validator is strong at validation itself.&lt;br&gt;
The second tells you how it behaves in something much closer to a real application pipeline.&lt;/p&gt;
&lt;h2&gt;
  
  
  Why this is good news for SJF4J
&lt;/h2&gt;

&lt;p&gt;Creek Service's results reinforce two things SJF4J has been designed around from the start.&lt;/p&gt;
&lt;h3&gt;
  
  
  1) SJF4J is fast at pure validation
&lt;/h3&gt;

&lt;p&gt;First: SJF4J is simply strong at &lt;strong&gt;pure validation&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;That matters because the baseline job of a validator is still the same:&lt;/p&gt;

&lt;p&gt;if you already have the schema and already have the data, validation should be fast and boring.&lt;/p&gt;

&lt;p&gt;That alone already puts it in very serious company.&lt;/p&gt;
&lt;h3&gt;
  
  
  2) SJF4J gets more interesting as the workflow gets more real
&lt;/h3&gt;

&lt;p&gt;This is the part that makes SJF4J more than just another validator with a benchmark chart.&lt;/p&gt;

&lt;p&gt;Most validators are still easiest to understand as &lt;strong&gt;JSON validators&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;SJF4J is better understood as a &lt;strong&gt;structural data processor for Java object graphs&lt;/strong&gt; that also includes JSON Schema validation.&lt;/p&gt;

&lt;p&gt;Instead, it can validate directly over:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;Map&lt;/code&gt; / &lt;code&gt;List&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;POJOs&lt;/li&gt;
&lt;li&gt;JOJOs (JSON-Object Java Object)&lt;/li&gt;
&lt;li&gt;other OBNT-compatible object graphs&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So when your application is already working with Java objects, SJF4J does &lt;strong&gt;not&lt;/strong&gt; need an extra parse/build pass just to begin validation.&lt;/p&gt;

&lt;p&gt;In other words:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;less conversion, less representation switching, less wasted work.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;And that is exactly the kind of advantage that shows up in serde-style benchmarks.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fptqzho3z8o1oen3e8j0e.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fptqzho3z8o1oen3e8j0e.png" alt="serde benchmark chart" width="799" height="375"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Why this matters beyond benchmark screenshots
&lt;/h2&gt;

&lt;p&gt;Because the real question is not just:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;who wins a benchmark?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;It is also:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;who forces the least unnecessary work into my application?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;In many Java systems, validation is not an isolated toy benchmark. It sits inside a larger flow:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;HTTP request handling&lt;/li&gt;
&lt;li&gt;event ingestion&lt;/li&gt;
&lt;li&gt;Kafka or queue consumers&lt;/li&gt;
&lt;li&gt;persistence pipelines&lt;/li&gt;
&lt;li&gt;DTO ↔ domain transformations&lt;/li&gt;
&lt;li&gt;configuration or document processing&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If your validation layer keeps forcing this shape:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;POJO -&amp;gt; JSON/tree -&amp;gt; validation -&amp;gt; POJO/domain&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;then the validator is only part of the cost story.&lt;/p&gt;

&lt;p&gt;SJF4J reduces that friction by keeping validation inside the same structural processing model used for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;parsing&lt;/li&gt;
&lt;li&gt;navigating&lt;/li&gt;
&lt;li&gt;patching&lt;/li&gt;
&lt;li&gt;mapping&lt;/li&gt;
&lt;li&gt;validating&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That gives you a simpler developer model and, very often, a faster runtime path.&lt;/p&gt;
&lt;h2&gt;
  
  
  A quick example
&lt;/h2&gt;

&lt;p&gt;With SJF4J, schema validation can sit directly on top of a Java model:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nd"&gt;@ValidJsonSchema&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"""
{
  "type": "object",
  "required": ["id", "email"],
  "properties": {
    "id": { "type": "integer" },
    "email": { "type": "string", "format": "email" }
  }
}
"""&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;UserDto&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;email&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;

&lt;span class="nc"&gt;SchemaValidator&lt;/span&gt; &lt;span class="n"&gt;validator&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;SchemaValidator&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
&lt;span class="nc"&gt;ValidationResult&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;validator&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;validate&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;userDto&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Or you can compile a reusable schema plan explicitly and validate native Java data directly:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nc"&gt;JsonSchema&lt;/span&gt; &lt;span class="n"&gt;schema&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;JsonSchema&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;fromJson&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"""
{
  "type": "object",
  "properties": {
    "name": { "type": "string" },
    "age": { "type": "integer", "minimum": 0 }
  },
  "required": ["name"]
}
"""&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;

&lt;span class="nc"&gt;SchemaPlan&lt;/span&gt; &lt;span class="n"&gt;plan&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;schema&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;createPlan&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;

&lt;span class="nc"&gt;Map&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;Object&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Map&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;of&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;
    &lt;span class="s"&gt;"name"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Ada"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
    &lt;span class="s"&gt;"age"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;18&lt;/span&gt;
&lt;span class="o"&gt;);&lt;/span&gt;

&lt;span class="kt"&gt;boolean&lt;/span&gt; &lt;span class="n"&gt;ok&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;plan&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;isValid&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The key point is not just the API.&lt;/p&gt;

&lt;p&gt;The key point is this:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;validation happens over the object graph you already have.&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  SJF4J is not just a validator benchmark story
&lt;/h2&gt;

&lt;p&gt;Another reason this matters: SJF4J is not a one-feature library.&lt;/p&gt;

&lt;p&gt;It provides one structural model and one API family across:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;JSON / YAML / Properties parsing&lt;/li&gt;
&lt;li&gt;JSON Path navigation&lt;/li&gt;
&lt;li&gt;JSON Patch / Merge Patch processing&lt;/li&gt;
&lt;li&gt;JSON Schema validation&lt;/li&gt;
&lt;li&gt;object graph mapping&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So if your application needs more than "just validate a schema", SJF4J can simplify more of the pipeline instead of becoming one more isolated dependency with one narrow responsibility.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where to look next
&lt;/h2&gt;

&lt;p&gt;If you want to explore SJF4J further:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;GitHub: &lt;a href="https://github.com/sjf4j-projects/sjf4j" rel="noopener noreferrer"&gt;sjf4j-projects/sjf4j&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Docs: &lt;a href="https://sjf4j.org" rel="noopener noreferrer"&gt;https://sjf4j.org&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Validation guide: &lt;a href="https://sjf4j.org/docs/validating" rel="noopener noreferrer"&gt;https://sjf4j.org/docs/validating&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Benchmarks: &lt;a href="https://sjf4j.org/docs/benchmarks" rel="noopener noreferrer"&gt;https://sjf4j.org/docs/benchmarks&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And if you want the benchmark context directly:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Creek Service comparison: &lt;a href="https://www.creekservice.org/json-schema-validation-comparison/" rel="noopener noreferrer"&gt;https://www.creekservice.org/json-schema-validation-comparison/&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Creek Service performance page: &lt;a href="https://www.creekservice.org/json-schema-validation-comparison/performance" rel="noopener noreferrer"&gt;https://www.creekservice.org/json-schema-validation-comparison/performance&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Final takeaway
&lt;/h2&gt;

&lt;p&gt;Creek Service's independent benchmark is a good reminder that JSON Schema performance is not only about raw validation speed.&lt;/p&gt;

&lt;p&gt;It is also about &lt;strong&gt;how much extra work your validation architecture forces you to do&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;SJF4J performs well in pure validation.&lt;/p&gt;

&lt;p&gt;But the more important point is this:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;when your data is already in Java object graphs, validating those object graphs directly is often the better design.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That is the design SJF4J is built around.&lt;/p&gt;

&lt;p&gt;And that may be exactly why it feels so fast in real Java workloads.&lt;/p&gt;

</description>
      <category>java</category>
      <category>jsonschema</category>
      <category>opensource</category>
      <category>performance</category>
    </item>
    <item>
      <title>Stop switching between POJO and JsonNode in Java. 
What if your objects themselves were the JSON tree?</title>
      <dc:creator>Yu Han</dc:creator>
      <pubDate>Sun, 26 Apr 2026 13:31:15 +0000</pubDate>
      <link>https://dev.to/hannyu/stop-switching-between-pojo-and-jsonnode-in-java-what-if-your-objects-themselves-were-the-json-3anm</link>
      <guid>https://dev.to/hannyu/stop-switching-between-pojo-and-jsonnode-in-java-what-if-your-objects-themselves-were-the-json-3anm</guid>
      <description>&lt;div class="ltag__link--embedded"&gt;
  &lt;div class="crayons-story "&gt;
  &lt;a href="https://dev.to/hannyu/beyond-pojo-and-jsonnode-a-more-cohesive-way-to-handle-json-in-java-j4a" class="crayons-story__hidden-navigation-link"&gt;Beyond POJO and JsonNode: A More Cohesive Way to Handle JSON in Java&lt;/a&gt;


  &lt;div class="crayons-story__body crayons-story__body-full_post"&gt;
    &lt;div class="crayons-story__top"&gt;
      &lt;div class="crayons-story__meta"&gt;
        &lt;div class="crayons-story__author-pic"&gt;

          &lt;a href="/hannyu" class="crayons-avatar  crayons-avatar--l  "&gt;
            &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3695478%2F1408961a-08f6-449c-ae0d-167d9795cb8f.jpg" alt="hannyu profile" class="crayons-avatar__image"&gt;
          &lt;/a&gt;
        &lt;/div&gt;
        &lt;div&gt;
          &lt;div&gt;
            &lt;a href="/hannyu" class="crayons-story__secondary fw-medium m:hidden"&gt;
              Yu Han
            &lt;/a&gt;
            &lt;div class="profile-preview-card relative mb-4 s:mb-0 fw-medium hidden m:inline-block"&gt;
              
                Yu Han
                
                
              
              &lt;div id="story-author-preview-content-3553364" class="profile-preview-card__content crayons-dropdown branded-7 p-4 pt-0"&gt;
                &lt;div class="gap-4 grid"&gt;
                  &lt;div class="-mt-4"&gt;
                    &lt;a href="/hannyu" class="flex"&gt;
                      &lt;span class="crayons-avatar crayons-avatar--xl mr-2 shrink-0"&gt;
                        &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3695478%2F1408961a-08f6-449c-ae0d-167d9795cb8f.jpg" class="crayons-avatar__image" alt=""&gt;
                      &lt;/span&gt;
                      &lt;span class="crayons-link crayons-subtitle-2 mt-5"&gt;Yu Han&lt;/span&gt;
                    &lt;/a&gt;
                  &lt;/div&gt;
                  &lt;div class="print-hidden"&gt;
                    
                      Follow
                    
                  &lt;/div&gt;
                  &lt;div class="author-preview-metadata-container"&gt;&lt;/div&gt;
                &lt;/div&gt;
              &lt;/div&gt;
            &lt;/div&gt;

          &lt;/div&gt;
          &lt;a href="https://dev.to/hannyu/beyond-pojo-and-jsonnode-a-more-cohesive-way-to-handle-json-in-java-j4a" class="crayons-story__tertiary fs-xs"&gt;&lt;time&gt;Apr 26&lt;/time&gt;&lt;span class="time-ago-indicator-initial-placeholder"&gt;&lt;/span&gt;&lt;/a&gt;
        &lt;/div&gt;
      &lt;/div&gt;

    &lt;/div&gt;

    &lt;div class="crayons-story__indention"&gt;
      &lt;h2 class="crayons-story__title crayons-story__title-full_post"&gt;
        &lt;a href="https://dev.to/hannyu/beyond-pojo-and-jsonnode-a-more-cohesive-way-to-handle-json-in-java-j4a" id="article-link-3553364"&gt;
          Beyond POJO and JsonNode: A More Cohesive Way to Handle JSON in Java
        &lt;/a&gt;
      &lt;/h2&gt;
        &lt;div class="crayons-story__tags"&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/java"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;java&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/json"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;json&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/opensource"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;opensource&lt;/a&gt;
        &lt;/div&gt;
      &lt;div class="crayons-story__bottom"&gt;
        &lt;div class="crayons-story__details"&gt;
          &lt;a href="https://dev.to/hannyu/beyond-pojo-and-jsonnode-a-more-cohesive-way-to-handle-json-in-java-j4a" class="crayons-btn crayons-btn--s crayons-btn--ghost crayons-btn--icon-left"&gt;
            &lt;div class="multiple_reactions_aggregate"&gt;
              &lt;span class="multiple_reactions_icons_container"&gt;
                  &lt;span class="crayons_icon_container"&gt;
                    &lt;img src="https://assets.dev.to/assets/exploding-head-daceb38d627e6ae9b730f36a1e390fca556a4289d5a41abb2c35068ad3e2c4b5.svg" width="18" height="18"&gt;
                  &lt;/span&gt;
              &lt;/span&gt;
              &lt;span class="aggregate_reactions_counter"&gt;1&lt;span class="hidden s:inline"&gt;&amp;nbsp;reaction&lt;/span&gt;&lt;/span&gt;
            &lt;/div&gt;
          &lt;/a&gt;
            &lt;a href="https://dev.to/hannyu/beyond-pojo-and-jsonnode-a-more-cohesive-way-to-handle-json-in-java-j4a#comments" class="crayons-btn crayons-btn--s crayons-btn--ghost crayons-btn--icon-left flex items-center"&gt;
              

              &lt;span class="hidden s:inline"&gt;Add&amp;nbsp;Comment&lt;/span&gt;
            &lt;/a&gt;
        &lt;/div&gt;
        &lt;div class="crayons-story__save"&gt;
          &lt;small class="crayons-story__tertiary fs-xs mr-2"&gt;
            5 min read
          &lt;/small&gt;
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;/div&gt;


</description>
    </item>
    <item>
      <title>Beyond POJO and JsonNode: A More Cohesive Way to Handle JSON in Java</title>
      <dc:creator>Yu Han</dc:creator>
      <pubDate>Sun, 26 Apr 2026 13:24:54 +0000</pubDate>
      <link>https://dev.to/hannyu/beyond-pojo-and-jsonnode-a-more-cohesive-way-to-handle-json-in-java-j4a</link>
      <guid>https://dev.to/hannyu/beyond-pojo-and-jsonnode-a-more-cohesive-way-to-handle-json-in-java-j4a</guid>
      <description>&lt;p&gt;Jackson is excellent at binding JSON to POJOs, but in real projects, JSON handling rarely ends at deserialization. After binding, we often still need to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;query nested fields&lt;/li&gt;
&lt;li&gt;preserve unknown properties&lt;/li&gt;
&lt;li&gt;apply partial updates&lt;/li&gt;
&lt;li&gt;validate data against JSON Schema&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That is when many codebases begin to bounce between two models—and the cost is not just conceptual, but structural.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;POJO&lt;/strong&gt; for typed business logic&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;JsonNode&lt;/code&gt;&lt;/strong&gt; for structural operations&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Every transition between POJO and JsonNode introduces friction: data copying, lost type information, or duplicated logic.&lt;/p&gt;

&lt;p&gt;This article focuses on a question:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;If Jackson already handles JSON-to-POJO mapping well, why do we still end up converting back to &lt;code&gt;JsonNode&lt;/code&gt; for path access, patching, or validation?&lt;br&gt;&lt;br&gt;
And more importantly: what if we didn’t have to switch models at all?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Where the friction starts
&lt;/h2&gt;

&lt;p&gt;A POJO is great for representing a stable Java model. But operations like JSON Path, JSON Patch, and JSON Schema are inherently structural.&lt;/p&gt;

&lt;p&gt;That leads to a familiar pattern:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nc"&gt;Order&lt;/span&gt; &lt;span class="n"&gt;order&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;objectMapper&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;readValue&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;Order&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is clean and natural. But later, requirements change:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;we need to read &lt;code&gt;$.customer.address.city&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;a &lt;code&gt;PATCH&lt;/code&gt; request updates &lt;code&gt;/items/0/price&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;the payload contains fields the POJO does not declare&lt;/li&gt;
&lt;li&gt;validation rules are described as JSON Schema rather than Java annotations&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So the code shifts to tree mode:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nc"&gt;JsonNode&lt;/span&gt; &lt;span class="n"&gt;root&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;objectMapper&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;readTree&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;city&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;root&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"customer"&lt;/span&gt;&lt;span class="o"&gt;).&lt;/span&gt;&lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"address"&lt;/span&gt;&lt;span class="o"&gt;).&lt;/span&gt;&lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"city"&lt;/span&gt;&lt;span class="o"&gt;).&lt;/span&gt;&lt;span class="na"&gt;asText&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This works too. The problem is not either API on its own. The real friction comes from &lt;strong&gt;switching models inside the same workflow&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Over time, the codebase becomes fragmented:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;business logic talks in fields and getters&lt;/li&gt;
&lt;li&gt;structural logic talks in tree nodes&lt;/li&gt;
&lt;li&gt;patching introduces another abstraction&lt;/li&gt;
&lt;li&gt;validation may rely on yet another model&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  A more cohesive direction
&lt;/h2&gt;

&lt;p&gt;In most JSON libraries, once the workflow becomes structural, we usually move into a dedicated tree model such as &lt;code&gt;JsonNode&lt;/code&gt;.  &lt;/p&gt;

&lt;p&gt;SJF4J takes a different route: it removes the need for a separate tree model altogether.&lt;br&gt;&lt;br&gt;
Instead of introducing an AST like JsonNode, it treats ordinary Java objects themselves as nodes in a JSON-semantic tree.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Faok519upljr4nocdw55b.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Faok519upljr4nocdw55b.png" alt="Figure: OBNT lets plain Java objects participate directly in a JSON-semantic tree, instead of forcing everything into a separate AST first." width="800" height="387"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In practice, that means:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;a JSON object can be represented by &lt;code&gt;Map&lt;/code&gt;, &lt;code&gt;JsonObject&lt;/code&gt;, &lt;code&gt;POJO&lt;/code&gt;, or &lt;code&gt;JOJO&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;a JSON array can be represented by &lt;code&gt;List&lt;/code&gt;, &lt;code&gt;JsonArray&lt;/code&gt;, Java arrays, or &lt;code&gt;Set&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;a JSON value can be represented by &lt;code&gt;String&lt;/code&gt;, &lt;code&gt;Number&lt;/code&gt;, &lt;code&gt;Boolean&lt;/code&gt;, &lt;code&gt;null&lt;/code&gt;, or adapted value types&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That is the key design move.&lt;/p&gt;

&lt;p&gt;Once these runtime objects participate in the same structural model, operations such as JsonPath, JsonPatch, and JsonSchema no longer need a separate tree representation in order to work. The object graph itself becomes the thing we navigate, patch, validate, and map.&lt;/p&gt;

&lt;p&gt;So the real shift is not just “one more JSON library.” It is this:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;instead of switching from Java objects to a JSON tree when the workflow becomes more structural,&lt;br&gt;&lt;br&gt;
SJF4J keeps the object graph itself structurally available from the beginning.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2&gt;
  
  
  Why JOJO is a useful middle ground
&lt;/h2&gt;

&lt;p&gt;One practical consequence of OBNT is &lt;strong&gt;JOJO (JSON-Object Java Object)&lt;/strong&gt;: a typed Java object that also behaves like a JSON object.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Order&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;JsonObject&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;Customer&lt;/span&gt; &lt;span class="n"&gt;customer&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;List&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Item&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;items&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then you can work with the same object in multiple ways:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nc"&gt;Order&lt;/span&gt; &lt;span class="n"&gt;order&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Sjf4j&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;fromJson&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;Order&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;

&lt;span class="n"&gt;order&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getId&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;                                     &lt;span class="c1"&gt;// typed access&lt;/span&gt;
&lt;span class="n"&gt;order&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getStringByPath&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"$.customer.address.city"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;  &lt;span class="c1"&gt;// path access&lt;/span&gt;
&lt;span class="n"&gt;order&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getString&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"sourceSystem"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;                   &lt;span class="c1"&gt;// dynamic property&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is useful because many real payloads are only &lt;strong&gt;mostly stable&lt;/strong&gt;. &lt;/p&gt;

&lt;p&gt;In practice, upstream systems evolve faster than your Java model.&lt;/p&gt;

&lt;p&gt;Some fields belong to the core Java model. Others are optional, evolving, or owned by upstream systems. A plain POJO can feel too closed for that. A raw tree can feel too loose. JOJO sits comfortably in between.&lt;/p&gt;

&lt;h2&gt;
  
  
  A small example
&lt;/h2&gt;

&lt;p&gt;Imagine an external order payload like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"A1001"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"customer"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Alice"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"address"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"city"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Shanghai"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"items"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"sku"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"P1"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"price"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"sourceSystem"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"partner-x"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With a closed POJO model, &lt;code&gt;sourceSystem&lt;/code&gt; may be ignored unless it is modeled explicitly.&lt;/p&gt;

&lt;p&gt;With JOJO:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;source&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;order&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getString&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"sourceSystem"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;city&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;order&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getStringByPath&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"$.customer.address.city"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It is a small difference in code, but a big difference in modeling style: typed fields and flexible JSON-style access can live together.&lt;/p&gt;

&lt;h2&gt;
  
  
  JsonPath becomes more than a convenience
&lt;/h2&gt;

&lt;p&gt;Because the object graph itself is navigable, JsonPath is no longer an add-on—it becomes a natural way to interact with your data.&lt;/p&gt;

&lt;p&gt;With direct field access:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;city&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;order&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getCustomer&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;
                   &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getAddress&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;
                   &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getCity&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is perfectly fine when the structure is fixed and shallow.&lt;/p&gt;

&lt;p&gt;But once the data becomes deeper, more dynamic, or only partially known, path-based access can be much cleaner:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;city&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;order&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getStringByPath&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"$.customer.address.city"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It also scales naturally to bulk queries:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nc"&gt;List&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Integer&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;prices&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;order&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;findByPath&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"$.items[*].price"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;Integer&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Or filtered queries:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nc"&gt;List&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;skus&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;order&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;findByPath&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"$.items[?@.price &amp;gt;= 100].sku"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;No, this is not the same as direct field access in absolute raw speed. But that trade-off is often worth it. Like many higher-level abstractions in Java, it introduces some overhead while saving code, reducing traversal boilerplate, and improving flexibility.&lt;/p&gt;

&lt;p&gt;Learn more → &lt;a href="https://sjf4j.org/docs/navigating" rel="noopener noreferrer"&gt;Navigating (JSON Path)&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Patch fits naturally too
&lt;/h2&gt;

&lt;p&gt;Once the object graph is treated structurally, patching no longer feels bolted on.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nc"&gt;JsonPatch&lt;/span&gt; &lt;span class="n"&gt;patch&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;JsonPatch&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;fromJson&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"""
[
  { "op": "replace", "path": "/customer/name", "value": "Alice Zhang" },
  { "op": "add", "path": "/items/0/discount", "value": 15 }
]
"""&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;

&lt;span class="n"&gt;patch&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;apply&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;order&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Or direct path mutation:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="n"&gt;order&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;ensurePutByPath&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"$.shipping.trackingNo"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"SF123456"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is especially useful for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;HTTP PATCH endpoints&lt;/li&gt;
&lt;li&gt;partial state updates&lt;/li&gt;
&lt;li&gt;integration events&lt;/li&gt;
&lt;li&gt;targeted nested mutations&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Learn more → &lt;a href="https://sjf4j.org/docs/patching" rel="noopener noreferrer"&gt;Patching (JSON Patch)&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Validation stays in the same flow
&lt;/h2&gt;

&lt;p&gt;Schema validation also becomes easier to place in the workflow when it operates on the same runtime structure:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nd"&gt;@ValidJsonSchema&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"""
{ "type": "object", "required": ["id"] }
"""&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Order&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;JsonObject&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// ...&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;

&lt;span class="kt"&gt;boolean&lt;/span&gt; &lt;span class="n"&gt;valid&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;SchemaValidator&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;validate&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;order&lt;/span&gt;&lt;span class="o"&gt;).&lt;/span&gt;&lt;span class="na"&gt;isValid&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The benefit is not only fewer conversion steps. More importantly, query, mutation, and validation all operate with the same object graph.&lt;/p&gt;

&lt;p&gt;Learn more → &lt;a href="https://sjf4j.org/docs/validating" rel="noopener noreferrer"&gt;Validating (JSON Schema)&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Final thought
&lt;/h2&gt;

&lt;p&gt;JSON in Java is not just about converting strings into objects.&lt;/p&gt;

&lt;p&gt;It is about how those objects participate in the rest of your system.&lt;/p&gt;

&lt;p&gt;By treating ordinary objects as part of a JSON-semantic tree, SJF4J removes an entire layer of indirection—and with it, a surprising amount of complexity.&lt;/p&gt;

&lt;p&gt;Project links:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;GitHub: &lt;a href="https://github.com/sjf4j-projects/sjf4j" rel="noopener noreferrer"&gt;https://github.com/sjf4j-projects/sjf4j&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Docs: &lt;a href="https://sjf4j.org" rel="noopener noreferrer"&gt;https://sjf4j.org&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>java</category>
      <category>json</category>
      <category>opensource</category>
    </item>
    <item>
      <title>A new jsonschema2jojo online tool!</title>
      <dc:creator>Yu Han</dc:creator>
      <pubDate>Tue, 21 Apr 2026 00:08:37 +0000</pubDate>
      <link>https://dev.to/hannyu/a-new-jsonschema2jojo-online-tool-1leh</link>
      <guid>https://dev.to/hannyu/a-new-jsonschema2jojo-online-tool-1leh</guid>
      <description>&lt;div class="ltag__link--embedded"&gt;
  &lt;div class="crayons-story "&gt;
  &lt;a href="https://dev.to/hannyu/generating-java-from-json-schema-6kf" class="crayons-story__hidden-navigation-link"&gt;Generating Java from JSON Schema&lt;/a&gt;


  &lt;div class="crayons-story__body crayons-story__body-full_post"&gt;
    &lt;div class="crayons-story__top"&gt;
      &lt;div class="crayons-story__meta"&gt;
        &lt;div class="crayons-story__author-pic"&gt;

          &lt;a href="/hannyu" class="crayons-avatar  crayons-avatar--l  "&gt;
            &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3695478%2F1408961a-08f6-449c-ae0d-167d9795cb8f.jpg" alt="hannyu profile" class="crayons-avatar__image"&gt;
          &lt;/a&gt;
        &lt;/div&gt;
        &lt;div&gt;
          &lt;div&gt;
            &lt;a href="/hannyu" class="crayons-story__secondary fw-medium m:hidden"&gt;
              Yu Han
            &lt;/a&gt;
            &lt;div class="profile-preview-card relative mb-4 s:mb-0 fw-medium hidden m:inline-block"&gt;
              
                Yu Han
                
              
              &lt;div id="story-author-preview-content-3525686" class="profile-preview-card__content crayons-dropdown branded-7 p-4 pt-0"&gt;
                &lt;div class="gap-4 grid"&gt;
                  &lt;div class="-mt-4"&gt;
                    &lt;a href="/hannyu" class="flex"&gt;
                      &lt;span class="crayons-avatar crayons-avatar--xl mr-2 shrink-0"&gt;
                        &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3695478%2F1408961a-08f6-449c-ae0d-167d9795cb8f.jpg" class="crayons-avatar__image" alt=""&gt;
                      &lt;/span&gt;
                      &lt;span class="crayons-link crayons-subtitle-2 mt-5"&gt;Yu Han&lt;/span&gt;
                    &lt;/a&gt;
                  &lt;/div&gt;
                  &lt;div class="print-hidden"&gt;
                    
                      Follow
                    
                  &lt;/div&gt;
                  &lt;div class="author-preview-metadata-container"&gt;&lt;/div&gt;
                &lt;/div&gt;
              &lt;/div&gt;
            &lt;/div&gt;

          &lt;/div&gt;
          &lt;a href="https://dev.to/hannyu/generating-java-from-json-schema-6kf" class="crayons-story__tertiary fs-xs"&gt;&lt;time&gt;Apr 20&lt;/time&gt;&lt;span class="time-ago-indicator-initial-placeholder"&gt;&lt;/span&gt;&lt;/a&gt;
        &lt;/div&gt;
      &lt;/div&gt;

    &lt;/div&gt;

    &lt;div class="crayons-story__indention"&gt;
      &lt;h2 class="crayons-story__title crayons-story__title-full_post"&gt;
        &lt;a href="https://dev.to/hannyu/generating-java-from-json-schema-6kf" id="article-link-3525686"&gt;
          Generating Java from JSON Schema
        &lt;/a&gt;
      &lt;/h2&gt;
        &lt;div class="crayons-story__tags"&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/java"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;java&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/jsonschema"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;jsonschema&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/opensource"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;opensource&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/productivity"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;productivity&lt;/a&gt;
        &lt;/div&gt;
      &lt;div class="crayons-story__bottom"&gt;
        &lt;div class="crayons-story__details"&gt;
          &lt;a href="https://dev.to/hannyu/generating-java-from-json-schema-6kf" class="crayons-btn crayons-btn--s crayons-btn--ghost crayons-btn--icon-left"&gt;
            &lt;div class="multiple_reactions_aggregate"&gt;
              &lt;span class="multiple_reactions_icons_container"&gt;
                  &lt;span class="crayons_icon_container"&gt;
                    &lt;img src="https://assets.dev.to/assets/sparkle-heart-5f9bee3767e18deb1bb725290cb151c25234768a0e9a2bd39370c382d02920cf.svg" width="18" height="18"&gt;
                  &lt;/span&gt;
              &lt;/span&gt;
              &lt;span class="aggregate_reactions_counter"&gt;2&lt;span class="hidden s:inline"&gt;&amp;nbsp;reactions&lt;/span&gt;&lt;/span&gt;
            &lt;/div&gt;
          &lt;/a&gt;
            &lt;a href="https://dev.to/hannyu/generating-java-from-json-schema-6kf#comments" class="crayons-btn crayons-btn--s crayons-btn--ghost crayons-btn--icon-left flex items-center"&gt;
              

              &lt;span class="hidden s:inline"&gt;Add&amp;nbsp;Comment&lt;/span&gt;
            &lt;/a&gt;
        &lt;/div&gt;
        &lt;div class="crayons-story__save"&gt;
          &lt;small class="crayons-story__tertiary fs-xs mr-2"&gt;
            5 min read
          &lt;/small&gt;
            
              &lt;span class="bm-initial crayons-icon c-btn__icon"&gt;
                

              &lt;/span&gt;
              &lt;span class="bm-success crayons-icon c-btn__icon"&gt;
                

              &lt;/span&gt;
            
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;/div&gt;


</description>
    </item>
    <item>
      <title>[Boost]</title>
      <dc:creator>Yu Han</dc:creator>
      <pubDate>Tue, 21 Apr 2026 00:06:28 +0000</pubDate>
      <link>https://dev.to/hannyu/-2efp</link>
      <guid>https://dev.to/hannyu/-2efp</guid>
      <description>&lt;div class="ltag__link--embedded"&gt;
  &lt;div class="crayons-story "&gt;
  &lt;a href="https://dev.to/hannyu/generating-java-from-json-schema-6kf" class="crayons-story__hidden-navigation-link"&gt;Generating Java from JSON Schema&lt;/a&gt;


  &lt;div class="crayons-story__body crayons-story__body-full_post"&gt;
    &lt;div class="crayons-story__top"&gt;
      &lt;div class="crayons-story__meta"&gt;
        &lt;div class="crayons-story__author-pic"&gt;

          &lt;a href="/hannyu" class="crayons-avatar  crayons-avatar--l  "&gt;
            &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3695478%2F1408961a-08f6-449c-ae0d-167d9795cb8f.jpg" alt="hannyu profile" class="crayons-avatar__image"&gt;
          &lt;/a&gt;
        &lt;/div&gt;
        &lt;div&gt;
          &lt;div&gt;
            &lt;a href="/hannyu" class="crayons-story__secondary fw-medium m:hidden"&gt;
              Yu Han
            &lt;/a&gt;
            &lt;div class="profile-preview-card relative mb-4 s:mb-0 fw-medium hidden m:inline-block"&gt;
              
                Yu Han
                
              
              &lt;div id="story-author-preview-content-3525686" class="profile-preview-card__content crayons-dropdown branded-7 p-4 pt-0"&gt;
                &lt;div class="gap-4 grid"&gt;
                  &lt;div class="-mt-4"&gt;
                    &lt;a href="/hannyu" class="flex"&gt;
                      &lt;span class="crayons-avatar crayons-avatar--xl mr-2 shrink-0"&gt;
                        &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3695478%2F1408961a-08f6-449c-ae0d-167d9795cb8f.jpg" class="crayons-avatar__image" alt=""&gt;
                      &lt;/span&gt;
                      &lt;span class="crayons-link crayons-subtitle-2 mt-5"&gt;Yu Han&lt;/span&gt;
                    &lt;/a&gt;
                  &lt;/div&gt;
                  &lt;div class="print-hidden"&gt;
                    
                      Follow
                    
                  &lt;/div&gt;
                  &lt;div class="author-preview-metadata-container"&gt;&lt;/div&gt;
                &lt;/div&gt;
              &lt;/div&gt;
            &lt;/div&gt;

          &lt;/div&gt;
          &lt;a href="https://dev.to/hannyu/generating-java-from-json-schema-6kf" class="crayons-story__tertiary fs-xs"&gt;&lt;time&gt;Apr 20&lt;/time&gt;&lt;span class="time-ago-indicator-initial-placeholder"&gt;&lt;/span&gt;&lt;/a&gt;
        &lt;/div&gt;
      &lt;/div&gt;

    &lt;/div&gt;

    &lt;div class="crayons-story__indention"&gt;
      &lt;h2 class="crayons-story__title crayons-story__title-full_post"&gt;
        &lt;a href="https://dev.to/hannyu/generating-java-from-json-schema-6kf" id="article-link-3525686"&gt;
          Generating Java from JSON Schema
        &lt;/a&gt;
      &lt;/h2&gt;
        &lt;div class="crayons-story__tags"&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/java"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;java&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/jsonschema"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;jsonschema&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/opensource"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;opensource&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/productivity"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;productivity&lt;/a&gt;
        &lt;/div&gt;
      &lt;div class="crayons-story__bottom"&gt;
        &lt;div class="crayons-story__details"&gt;
          &lt;a href="https://dev.to/hannyu/generating-java-from-json-schema-6kf" class="crayons-btn crayons-btn--s crayons-btn--ghost crayons-btn--icon-left"&gt;
            &lt;div class="multiple_reactions_aggregate"&gt;
              &lt;span class="multiple_reactions_icons_container"&gt;
                  &lt;span class="crayons_icon_container"&gt;
                    &lt;img src="https://assets.dev.to/assets/sparkle-heart-5f9bee3767e18deb1bb725290cb151c25234768a0e9a2bd39370c382d02920cf.svg" width="18" height="18"&gt;
                  &lt;/span&gt;
              &lt;/span&gt;
              &lt;span class="aggregate_reactions_counter"&gt;2&lt;span class="hidden s:inline"&gt;&amp;nbsp;reactions&lt;/span&gt;&lt;/span&gt;
            &lt;/div&gt;
          &lt;/a&gt;
            &lt;a href="https://dev.to/hannyu/generating-java-from-json-schema-6kf#comments" class="crayons-btn crayons-btn--s crayons-btn--ghost crayons-btn--icon-left flex items-center"&gt;
              

              &lt;span class="hidden s:inline"&gt;Add&amp;nbsp;Comment&lt;/span&gt;
            &lt;/a&gt;
        &lt;/div&gt;
        &lt;div class="crayons-story__save"&gt;
          &lt;small class="crayons-story__tertiary fs-xs mr-2"&gt;
            5 min read
          &lt;/small&gt;
            
              &lt;span class="bm-initial crayons-icon c-btn__icon"&gt;
                

              &lt;/span&gt;
              &lt;span class="bm-success crayons-icon c-btn__icon"&gt;
                

              &lt;/span&gt;
            
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;/div&gt;


</description>
    </item>
    <item>
      <title>Generating Java from JSON Schema</title>
      <dc:creator>Yu Han</dc:creator>
      <pubDate>Mon, 20 Apr 2026 08:01:06 +0000</pubDate>
      <link>https://dev.to/hannyu/generating-java-from-json-schema-6kf</link>
      <guid>https://dev.to/hannyu/generating-java-from-json-schema-6kf</guid>
      <description>&lt;p&gt;A new browser-based tool on &lt;strong&gt;&lt;a href="https://sjf4j.org/generator" rel="noopener noreferrer"&gt;sjf4j.org&lt;/a&gt;&lt;/strong&gt; turns JSON Schema into Java scaffolding directly in the browser.&lt;/p&gt;

&lt;p&gt;Paste a schema, tune the generation strategy, and get Java output immediately.&lt;/p&gt;

&lt;p&gt;What makes it more interesting than a basic schema-to-POJO converter is that it exposes modeling decisions directly.&lt;br&gt;&lt;br&gt;
&lt;strong&gt;Schema-to-code is not only about mapping types. It is also about deciding what should become part of a stable Java API, and what should remain flexible.&lt;/strong&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Try it here
&lt;/h2&gt;

&lt;p&gt;👉 &lt;strong&gt;Tool:&lt;/strong&gt; &lt;a href="https://sjf4j.org/generator" rel="noopener noreferrer"&gt;https://sjf4j.org/generator&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhaz9uc2eqfcjffaeedoa.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhaz9uc2eqfcjffaeedoa.png" alt="Screenshot goes here" width="800" height="411"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  What the tool does
&lt;/h2&gt;

&lt;p&gt;The generator is a browser-based playground for turning JSON Schema into Java scaffolding.&lt;/p&gt;

&lt;p&gt;It currently supports:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;package and class name configuration&lt;/li&gt;
&lt;li&gt;primitive / number / date-time mapping choices&lt;/li&gt;
&lt;li&gt;string enum → Java enum generation&lt;/li&gt;
&lt;li&gt;nested object → inner class generation&lt;/li&gt;
&lt;li&gt;required-field-aware generation&lt;/li&gt;
&lt;li&gt;validation annotations such as &lt;code&gt;@NotNull&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;JavaDoc generation from schema metadata&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;allOf&lt;/code&gt; flattening for object schemas&lt;/li&gt;
&lt;li&gt;local &lt;code&gt;$ref&lt;/code&gt; expansion&lt;/li&gt;
&lt;li&gt;deterministic import and member ordering&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;One of the strongest parts of the tool is its customization model:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;global configuration&lt;/strong&gt; for overall generation behavior&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;property-by-property overrides&lt;/strong&gt; in the &lt;strong&gt;Parsed Properties&lt;/strong&gt; panel&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So the tool does not force one all-or-nothing rule across the whole schema. A project can start with a global baseline, then adjust selected members one by one.&lt;/p&gt;
&lt;h2&gt;
  
  
  A simple example
&lt;/h2&gt;

&lt;p&gt;Given a schema like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"$schema"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"https://json-schema.org/draft/2020-12/schema"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"title"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Order"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"description"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Checkout order created by the storefront."&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"object"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"required"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"id"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"amount"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"createdAt"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"customer"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"items"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"properties"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"string"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"description"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Business order identifier."&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"amount"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"number"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"description"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Total amount in the settlement currency."&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"createdAt"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"string"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"format"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"date-time"&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"paid"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"boolean"&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"customer"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"object"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"required"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"id"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"email"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"properties"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"string"&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"email"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"string"&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"items"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"array"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"items"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"object"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"required"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"sku"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"quantity"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"properties"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="nl"&gt;"sku"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"string"&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="nl"&gt;"quantity"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"integer"&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With the default JOJO-oriented settings, the generated Java can look like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nd"&gt;@Getter&lt;/span&gt; &lt;span class="nd"&gt;@Setter&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Order&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;JsonObject&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="cm"&gt;/**
     * JSON shape:
     * &amp;lt;pre&amp;gt;
     * {
     *   "id": "string",
     *   "amount": "number",
     *   "createdAt": "string(date-time)",
     *   "paid": "boolean",
     *   "customer": {
     *     "id": "string",
     *     "email": "string"
     *   },
     *   "items": [
     *     {
     *       "sku": "string",
     *       "quantity": "integer"
     *     }
     *   ]
     * }
     * &amp;lt;/pre&amp;gt;
     */&lt;/span&gt;
    &lt;span class="nd"&gt;@NotNull&lt;/span&gt; &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="nd"&gt;@NotNull&lt;/span&gt; &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kt"&gt;double&lt;/span&gt; &lt;span class="n"&gt;amount&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="nd"&gt;@NotNull&lt;/span&gt; &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;OffsetDateTime&lt;/span&gt; &lt;span class="n"&gt;createdAt&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kt"&gt;boolean&lt;/span&gt; &lt;span class="n"&gt;paid&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="nd"&gt;@NotNull&lt;/span&gt; &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;Customer&lt;/span&gt; &lt;span class="n"&gt;customer&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="nd"&gt;@NotNull&lt;/span&gt; &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;List&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;ItemsItem&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;items&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;JsonPath&lt;/span&gt; &lt;span class="no"&gt;PATH_CUSTOMER_EMAIL&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;JsonPath&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;compile&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"$.customer.email"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;

    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="nf"&gt;getCustomerEmail&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="no"&gt;PATH_CUSTOMER_EMAIL&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getString&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="nf"&gt;getItemsSku&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;itemsIndex&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;getStringByPath&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"$.items["&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;itemsIndex&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="s"&gt;"].sku"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="nd"&gt;@Getter&lt;/span&gt; &lt;span class="nd"&gt;@Setter&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Customer&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;JsonObject&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="nd"&gt;@NotNull&lt;/span&gt; &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
        &lt;span class="nd"&gt;@NotNull&lt;/span&gt; &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;email&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="nd"&gt;@Getter&lt;/span&gt; &lt;span class="nd"&gt;@Setter&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ItemsItem&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;JsonObject&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="nd"&gt;@NotNull&lt;/span&gt; &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;sku&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
        &lt;span class="nd"&gt;@NotNull&lt;/span&gt; &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;quantity&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is closer to a real API shape: nested objects, arrays, required members, generated inner classes, validation annotations, and root-level path accessors.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why modeling choices matter
&lt;/h2&gt;

&lt;p&gt;The generator is not designed as a “turn every JSON property into a field” machine.&lt;/p&gt;

&lt;p&gt;In real systems, the harder question is usually:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Which parts of this schema should become a stable Java contract, and which parts should stay flexible?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That is why the tool exposes decisions such as:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;JOJO vs POJO&lt;/strong&gt; modeling&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;field vs property&lt;/strong&gt; generation&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;path accessor&lt;/strong&gt; generation on the root model&lt;/li&gt;
&lt;li&gt;per-property type overrides&lt;/li&gt;
&lt;li&gt;global defaults plus property-by-property adjustments&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This matters when the input schema comes from:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;a third-party API that changes often&lt;/li&gt;
&lt;li&gt;an event payload with optional extension fields&lt;/li&gt;
&lt;li&gt;an internal contract that is stable in some places and fluid in others&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Why JOJO is interesting here
&lt;/h2&gt;

&lt;p&gt;This generator is part of the broader &lt;strong&gt;SJF4J&lt;/strong&gt; ecosystem, so it can generate models that fit naturally into SJF4J’s structural APIs.&lt;/p&gt;

&lt;p&gt;If an object is modeled as a &lt;strong&gt;JOJO&lt;/strong&gt;, it extends &lt;code&gt;org.sjf4j.JsonObject&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;That gives you an interesting hybrid:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;typed Java members where you want a stable contract&lt;/li&gt;
&lt;li&gt;dynamic JSON-style access where you still need flexibility&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For example, the generator can produce root-level descendant accessors such as:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="nf"&gt;getCustomerEmail&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="no"&gt;PATH_CUSTOMER_EMAIL&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getString&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="nf"&gt;getItemsSku&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;itemsIndex&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;getStringByPath&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"$.items["&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;itemsIndex&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="s"&gt;"].sku"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That is a different direction from classic schema-to-POJO generators. It is useful when the generated model is not just a DTO, but part of a larger JSON-processing workflow.&lt;/p&gt;

&lt;h2&gt;
  
  
  Global configuration and per-property tuning
&lt;/h2&gt;

&lt;p&gt;Customization happens at two levels.&lt;/p&gt;

&lt;p&gt;At the &lt;strong&gt;global&lt;/strong&gt; level, the generator can define the overall baseline for a file:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;package and class name&lt;/li&gt;
&lt;li&gt;JOJO or POJO preference&lt;/li&gt;
&lt;li&gt;field-generation strategy&lt;/li&gt;
&lt;li&gt;accessor strategy&lt;/li&gt;
&lt;li&gt;path-accessor strategy&lt;/li&gt;
&lt;li&gt;integer / number / boolean / enum / date-time mapping&lt;/li&gt;
&lt;li&gt;object-leaf mapping&lt;/li&gt;
&lt;li&gt;validation namespace and annotations&lt;/li&gt;
&lt;li&gt;JavaDoc generation&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;At the &lt;strong&gt;property&lt;/strong&gt; level, the Parsed Properties panel can refine specific members:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;switch between &lt;strong&gt;field&lt;/strong&gt; and &lt;strong&gt;property&lt;/strong&gt; generation&lt;/li&gt;
&lt;li&gt;override the generated &lt;strong&gt;Java type&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;enable or disable &lt;strong&gt;by-path getter/setter&lt;/strong&gt; generation for eligible paths&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That makes the tool flexible enough for mixed schemas, where most properties follow one rule but a few important members need a different Java contract.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where this fits in SJF4J
&lt;/h2&gt;

&lt;p&gt;If you have not seen &lt;strong&gt;SJF4J&lt;/strong&gt; before, it is a &lt;strong&gt;unified JSON-semantic processing layer for Java&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;It provides one structural model across:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;parsing&lt;/li&gt;
&lt;li&gt;modeling&lt;/li&gt;
&lt;li&gt;JSON Path navigation&lt;/li&gt;
&lt;li&gt;JSON Patch / Merge Patch&lt;/li&gt;
&lt;li&gt;JSON Schema validation&lt;/li&gt;
&lt;li&gt;mapping / transformation&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In practice, that means you can:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;start from a JSON Schema&lt;/li&gt;
&lt;li&gt;generate a Java model&lt;/li&gt;
&lt;li&gt;parse payloads into that model&lt;/li&gt;
&lt;li&gt;navigate it with JSON Path&lt;/li&gt;
&lt;li&gt;validate it with JSON Schema&lt;/li&gt;
&lt;li&gt;keep dynamic structure where needed&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;That end-to-end flow is why this generator fits naturally on the SJF4J site instead of being treated as an isolated utility.&lt;/p&gt;

&lt;h2&gt;
  
  
  A few implementation details worth keeping explicit
&lt;/h2&gt;

&lt;p&gt;Some current baseline behaviors:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;nested object schemas generate as &lt;code&gt;public static&lt;/code&gt; inner classes&lt;/li&gt;
&lt;li&gt;nested enums are generated inside the owning class&lt;/li&gt;
&lt;li&gt;imports are deduplicated and sorted&lt;/li&gt;
&lt;li&gt;object &lt;code&gt;allOf&lt;/code&gt; is flattened before rendering&lt;/li&gt;
&lt;li&gt;circular local &lt;code&gt;$ref&lt;/code&gt; chains are rejected&lt;/li&gt;
&lt;li&gt;unsupported non-local &lt;code&gt;$ref&lt;/code&gt; is ignored for now&lt;/li&gt;
&lt;li&gt;root path accessors are generated only when the root model is a JOJO&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In other words, the tool tries to be predictable first, and flexible second — but without hiding the rules.&lt;/p&gt;

&lt;p&gt;Another useful detail: &lt;strong&gt;the full generation rules are published on the page itself&lt;/strong&gt;. So the tool is not a black box. The page also works as a spec-like baseline and regression target: the rules are explicit enough to be reused as an AI prompt, allowing an LLM to reproduce a similar generator — or help design a more optimized one on top of the same contract.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why this is useful
&lt;/h2&gt;

&lt;p&gt;The practical value is simple: &lt;strong&gt;the first draft of a Java model should be fast to get, but not locked into the wrong abstraction too early.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;If you only need quick scaffolding, the generator already helps.&lt;/p&gt;

&lt;p&gt;If you care about long-term maintainability, the more useful part is that it makes the trade-offs visible:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;strict vs flexible object modeling&lt;/li&gt;
&lt;li&gt;field-backed vs dynamic property-backed members&lt;/li&gt;
&lt;li&gt;plain DTO generation vs JSON-semantic access patterns&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Try it and tell me what is missing
&lt;/h2&gt;

&lt;p&gt;If you want to try it:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Generator:&lt;/strong&gt; &lt;a href="https://sjf4j.org/generator" rel="noopener noreferrer"&gt;https://sjf4j.org/generator&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;SJF4J docs:&lt;/strong&gt; &lt;a href="https://sjf4j.org/docs/getting_started" rel="noopener noreferrer"&gt;https://sjf4j.org/docs/getting_started&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;GitHub:&lt;/strong&gt; &lt;a href="https://github.com/sjf4j-projects/sjf4j" rel="noopener noreferrer"&gt;https://github.com/sjf4j-projects/sjf4j&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you are already working with JSON Schema, Java DTO generation, or mixed typed/dynamic payloads, useful feedback would include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;nullable handling&lt;/li&gt;
&lt;li&gt;multi-file output layout&lt;/li&gt;
&lt;li&gt;more &lt;code&gt;$ref&lt;/code&gt; composition cases&lt;/li&gt;
&lt;li&gt;better defaults for boxed vs primitive types&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Schema-to-code is easy to automate.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Designing good Java boundaries is still the hard part.&lt;/strong&gt;&lt;/p&gt;

</description>
      <category>java</category>
      <category>jsonschema</category>
      <category>opensource</category>
      <category>productivity</category>
    </item>
  </channel>
</rss>
