跳至內容

JSON 轉 Java

從 JSON 範例生成 Java POJO。

輸入

這個工具的用途

從 JSON 樣本產生帶 Jackson annotation 的 Java POJO。使用 package 選項設定產生的 package 宣告,檔案可直接落入你的原始碼 目錄。每個巢狀物件成為各自的 class。底層使用 quicktype,完全在你的瀏覽器內運作。

使用步驟

貼上 JSON(或載入範例),即可在右側讀到 Java POJO。在選項面板 設定 package name 對應你的原始碼目錄;預設輸出在 public 欄位上 使用 Jackson @JsonProperty annotation。

輸入: {"id":42,"name":"devsmiths","createdAt":"2024-03-11T08:24:00Z","stars":1280,"public":true,"contributors":[{"login":"ada","commits":51,"admin":true},{"login":"linus","commits":33,"admin":false}],"homepage":null}

輸出(Java):

package com.devsmiths;

import com.fasterxml.jackson.annotation.JsonProperty;
import java.util.List;

public class Root {
    @JsonProperty("id") public long id;
    @JsonProperty("name") public String name;
    @JsonProperty("createdAt") public String createdAt;
    @JsonProperty("stars") public long stars;
    @JsonProperty("public") public boolean isPublic;
    @JsonProperty("contributors") public List<Contributor> contributors;
    @JsonProperty("homepage") public Object homepage;
}

public class Contributor {
    @JsonProperty("login") public String login;
    @JsonProperty("commits") public long commits;
    @JsonProperty("admin") public boolean admin;
}

限制與邊界情況

  • 預設輸出採 Jackson annotation(public 欄位上的 @JsonProperty)。改用 Gson 時 find/replace:@JsonProperty@SerializedName 並調整 import——欄位形狀相容。
  • 欄位是 public,不是 private + getter/setter。這是刻意的——現代 Jackson 與 Gson 預設都會反射讀取 public 欄位,而每個 POJO 多寫 50 行 getter/setter 正是 Lombok 出現的理由。產生器不依賴 Lombok, 若你已有 Lombok 可手動加上 @lombok.Data 並改為 private。
  • Java 保留字(classpublic)作為 JSON 鍵時, 會被重新命名為 className / isPublic, 原名保留在 @JsonProperty 中。序列化依 tag 進行, 反向也能來回。
  • 整數一律 long,與大小無關。若 ID 能放進 int, 可手動收緊;Jackson 解碼時兩者皆容忍。
  • 日期字串保持為 String,不是 java.time.Instant。ISO 8601 字串無歧義, 若需要型別化日期可加上 @JsonDeserialize(using = InstantDeserializer.class)
  • 陣列輸出為 java.utilList<T>。 若原始型別效率比 .add() 操作更重要,可手動改為 T[]

常見問題

Jackson、Gson 還是 javax.json — 產生哪種 annotation?
Jackson(`@JsonProperty`)。它在 2026 是主流——Spring 預設用它、Quarkus 與 Micronaut 開箱即用都帶它。改 Gson:find/replace `@JsonProperty` → `@SerializedName` 並調整 import。javax.json(現為 jakarta.json)採用 streaming API,無法乾淨對應到 POJO 欄位 annotation;若需要 stream-based 解析請選別的函式庫。
為什麼是 public 欄位而不是 private + getter/setter?
為了避免樣板碼。public 欄位可直接被 Jackson 與 Gson(預設都反射讀取欄位)使用;private 欄位若沒有 accessor 就不行,而為每個 POJO 寫 50 行 getter/setter 正是 Lombok 出現的理由。產生器保持 Lombok-free 以免新增相依。若已有 Lombok,可手動加 `@lombok.Data` 並將欄位改為 private。
JSON 鍵與 Java 保留字(public、class)衝突時如何處理?
重新命名為前綴(`isPublic`、`className`),原名保留在 `@JsonProperty` 中。序列化器讀寫原始鍵;Java 程式使用重新命名後的識別字。布林欄位的重新命名慣例為 `is` 前綴——Jackson 與 Gson 都認得 `is` 布林 accessor 模式。
整數為什麼是 long 而不是 int?
因為 Java 的 int 是 32-bit,而 JSON 數字(經 JavaScript)是 64-bit double——2^31 以上的 JSON 整數會悄悄 overflow int。long 對 2^53 以下都安全;再大時的精度損失在資料到達 Java 解碼器之前就已發生。對你確定放得下 int 的欄位請手動收緊。
產生器可以輸出 immutable records(Java 14+ records)嗎?
預設不會。Java records 較簡潔,但要求 Jackson `@JsonCreator` 加上排序好的 constructor 參數才能來回——refactor 時容易出錯。產生器輸出 mutable POJO 因為零儀式即可來回。手動轉換:`public class Root` → `public record Root(@JsonProperty("id") long id, ...)` 並視情況加上 `@JsonCreator`。
如何用產生的 POJO 解析 JSON?
Jackson:`new ObjectMapper().readValue(jsonString, Root.class)`。Gson:`new Gson().fromJson(jsonString, Root.class)`。兩者都會正確讀取 public 欄位與 `@JsonProperty` / `@SerializedName` annotation。Spring Boot 中 `ObjectMapper` 已 autowire——注入而非每次 request 都新建。

內容審閱者: