$.idrequired
string
JSON Schema Input
Schema Libraries
Add extra schema documents below the main schema.
Add a supporting schema such as common.json.
Parsed Properties
string
number
string (date-time)
boolean
object
string
string
array
object
string
integer
Java Output
package org.example.generated;
import jakarta.validation.constraints.NotNull;
import java.time.OffsetDateTime;
import java.util.List;
import lombok.Getter;
import lombok.Setter;
import org.sjf4j.JsonObject;
import org.sjf4j.path.JsonPath;
/**
* Checkout order created by the storefront.
*
* JSON shape:
* <pre>
* {
* "id": "string",
* "amount": "number",
* "createdAt": "string(date-time)",
* "paid": "boolean",
* "customer": {
* "id": "string",
* "email": "string"
* },
* "items": [
* {
* "sku": "string",
* "quantity": "integer"
* }
* ]
* }
* </pre>
*/
@Getter @Setter
public class Order extends JsonObject {
/** Business order identifier. */
@NotNull
private String id;
/** Total amount in the settlement currency. */
@NotNull
private double amount;
@NotNull
private OffsetDateTime createdAt;
private boolean paid;
@NotNull
private Customer customer;
@NotNull
private List<ItemsItem> items;
private static final JsonPath PATH_CUSTOMER_ID = JsonPath.parse("$.customer.id");
private static final JsonPath PATH_CUSTOMER_EMAIL = JsonPath.parse("$.customer.email");
public String getCustomerId() {
return PATH_CUSTOMER_ID.getString(this);
}
public void setCustomerId(String value) {
PATH_CUSTOMER_ID.ensurePut(this, value);
}
public String getCustomerEmail() {
return PATH_CUSTOMER_EMAIL.getString(this);
}
public void setCustomerEmail(String value) {
PATH_CUSTOMER_EMAIL.ensurePut(this, value);
}
public String getItemsSku(int itemsIndex) {
return getStringByPath("$.items[" + itemsIndex + "].sku");
}
public void setItemsSku(int itemsIndex, String value) {
ensurePutByPath("$.items[" + itemsIndex + "].sku", value);
}
public int getItemsQuantity(int itemsIndex) {
return getIntByPath("$.items[" + itemsIndex + "].quantity", 0);
}
public void setItemsQuantity(int itemsIndex, int value) {
ensurePutByPath("$.items[" + itemsIndex + "].quantity", value);
}
@Getter @Setter
public static class Customer extends JsonObject {
@NotNull
private String id;
@NotNull
private String email;
}
@Getter @Setter
public static class ItemsItem extends JsonObject {
@NotNull
private String sku;
@NotNull
private int quantity;
}
}
Draft v2026-04-20. These rules define the current baseline and regression target, and should be sufficient for an AI to reproduce an equivalent generation tool.
$id values.$ref targets are resolved against the current document $id when that $id is a URI-like base.className is empty, the generator uses schema.title; otherwise it uses the explicit override.GeneratedType.| JSON Schema shape | Java type baseline |
|---|---|
string | String |
string + format: date | LocalDate |
string + format: date-time | OffsetDateTime, LocalDateTime, Instant, String |
integer | int, Integer, long, Long, BigInteger |
number | double, Double, BigDecimal, int, long |
boolean | boolean, Boolean |
enum | Java enum, String |
object leaf | JsonObject, Map<String, Object>, JOJO |
object nested | JOJO, POJO |
array<T> | List<T> |
| unsupported / unknown | Object |
properties are rendered in schema declaration order. Whether a property becomes a Java field or a JsonObject-backed property depends on field-generation rules and per-property overrides.public static inner classes inside the containing class unless modelingStrategy = pathOnly; no separate Java files are generated for nested objects.packageName is emitted only when non-empty.@NotNull from required@Size from minLength / maxLength and minItems / maxItems@Pattern from pattern@Min / @Max from integral minimum / maximumdescription or title, depending on the selected option.accessorMode = lombok: JOJO classes use @Getter and @SetterPOJO classes use @DataJSON shape block in JavaDoc.required, allOf, $ref, and other schema-level metadata.JSON shape block in the current baseline.additionalProperties defaults to true when omitted.modelingStrategy supports three modes: jojopojopathOnly (UI label: Path only (JsonObject preferred))jojo mode, every generated object class is a JOJO, meaning the class extends org.sjf4j.JsonObject.pojo mode: additionalProperties: true (or omits the keyword), it is generated as a JOJOadditionalProperties: false, it is generated as a plain POJO and does not extend JsonObjectjojo mode, if an object has additionalProperties: false, it is still generated as a JOJO, but with @NodeBinding(readDynamic = false) to disable dynamic reads of undeclared properties.pathOnly mode: JOJOproperties default to JsonObjectList<JsonObject>JsonObject for path accessor typingjojo and pojo rules apply to all generated object classes, including nested objects; pathOnly suppresses descendant object-class generation entirely.All: all properties default to field.Required Only: required properties default to field; non-required properties default to property.None: all properties default to property.property generation is only valid for JOJO classes because property access is backed by JsonObject APIs.property has no backing field. It is rendered as explicit getter/setter methods that read and write through JsonObject methods such as getXxx(key) and put(key, value).boolean getters use JavaBean-style isXxx() naming; boxed Boolean getters continue to use getXxx().JsonObject APIs when available (for example getString(key), getInt(key), getJsonObject(key)); otherwise it falls back to typed access such as get(key, LocalDateTime.class).List<T> properties, getter generation prefers getList(key, T.class) when T is a concrete non-generic item type; for complex generic item types it falls back to getList(key).property generation always emits explicit getter/setter methods, even when accessorMode = lombok or accessorMode = none.modelingStrategy = pathOnly, field-generation rules apply only to root direct properties.pathOnly mode, every non-root property is fixed to property: it never generates a field, it is exposed only through root-level path accessors, and it may still expose type and path configuration in Parsed Properties but not field/property switching.properties, the parsed-property type selector defaults to JOJO or POJO according to the effective modeling strategy, except under pathOnly where root direct object properties default to JsonObject.JsonObject, the nested class is not generated and descendant members no longer expose field/property configuration; only eligible root-level by-path getter/setter configuration remains.static final JsonPath constants via JsonPath.parse(...) on the root class.JsonObject *ByPath APIs and ensurePutByPath(path, value) directly.boolean path getters use JavaBean-style isXxx() naming; boxed Boolean path getters continue to use getXxx().*ByPath APIs when available; otherwise it falls back to typed access such as getByPath(path, LocalDateTime.class).JsonPath, generation uses default-value overloads such as getInt(this, 0), getLong(this, 0L), getDouble(this, 0d), and getBoolean(this, false) instead of manual null checks.ensurePut semantics so missing intermediate containers are created when needed.List<T> path accessors, getter generation prefers getListByPath(path, T.class) when T is a concrete non-generic item type; for complex generic item types it falls back to getListByPath(path).getCustomerEmail() and setCustomerEmail(String value).int index parameter is generated for each array segment, in path order, for example getItemsSku(int itemsIndex) or getGroupsUsersName(int groupsIndex, int usersIndex).JOJO; if the root class is generated as a POJO, no path accessors are emitted.modelingStrategy = pathOnly, root-level path accessors are the only generated access surface for non-root properties.pathOnly mode, object-valued descendant paths may also generate path accessors, using JsonObject.pathOnly mode, descendant property JavaDoc is attached to the generated path getter method.javaEnum generation for string enums only.modelingStrategy = pathOnly removes that owning nested class; no separate Java files are generated for enums.UPPER_SNAKE_CASE names.get(key, StatusEnum.class) and getByPath(path, StatusEnum.class).modelingStrategy = pathOnly removes the owning nested class for an enum property, the enum is hoisted to the root class.pathOnly mode, hoisted enum names are derived from the flattened property path, for example CustomerStatusEnum.allOf flattening for object schemas only.allOf is normalized before type mapping and rendering.$ref values of the form #/... are resolved during normalization.$ref values such as common.json#/$defs/Type are resolved against the current document $id, then matched to a supplied schema-library document $id.$ref chains are rejected with an error.$ref document ids are rejected with an error.properties: merged by property name allOf, allowing later branches to narrow an earlier type: object declaration with nested properties, required, or additionalPropertiesrequired: union of all entriestitle: prefer the outer schema, otherwise the first non-empty branch titledescription: prefer the outer schema, otherwise the first non-empty branch descriptionadditionalProperties: false wins; otherwise compatible schema values are preserved, or true when explicitly enabledallOf; they are rendered as inner classes after normalization unless modelingStrategy = pathOnly suppresses descendant class generation.allOf composition is not supported in the current baseline.required values merged from allOf are emitted in first-seen order._2, _3, and so on.allOf are hard errors.$ref chains are hard errors.$id values are hard errors.$ref document ids are hard errors.allOf composition is a hard error.The first regression suite locks down these behaviors:
simple-order)pathOnly generation without nested inner classespathOnly enum hoisting and typed path access$ref expansion and schema-library $id-based external $ref resolutionThese are intentionally not frozen yet and will be revised before full implementation:
$ref-based allOf compositionJOJO is selected