在 Java 企業開發中,JSON 數據交換無處不在:REST API 回應、前後端數據傳輸、配置文件解析、日誌序列化。本文提供基於 json-lib 的通用工具類 JsonUtil,支援陣列、集合、Map、物件、XML 互轉,並解決循環引用、字段過濾、日期格式化等實戰痛點。
<dependency>
<groupId>net.sf.json-lib</groupId>
<artifactId>json-lib</artifactId>
<version>2.4</version>
<classifier>jdk15</classifier>
</dependency>
<!-- 必須依賴 -->
<dependency>
<groupId>commons-lang</groupId>
<artifactId>commons-lang</artifactId>
<version>2.6</version>
</dependency>
<dependency>
<groupId>commons-beanutils</groupId>
<artifactId>commons-beanutils</artifactId>
<version>1.9.4</version>
</dependency>
<dependency>
<groupId>commons-collections</groupId>
<artifactId>commons-collections</artifactId>
<version>3.2.2</version>
</dependency>
<dependency>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
<version>1.2</version>
</dependency>
<dependency>
<groupId>net.sf.ezmorph</groupId>
<artifactId>ezmorph</artifactId>
<version>1.0.6</version>
</dependency>
public class JsonUtil {
/** 將物件陣列轉為 JSON 字串 */
public static String array2json(Object[] objects) {
JSONArray jsonArray = JSONArray.fromObject(objects);
return jsonArray.toString();
}
/** 將 List 集合轉為 JSON 字串 */
public static String list2json(List> list) {
JSONArray jsonArray = JSONArray.fromObject(list);
return jsonArray.toString();
}
/** 將 Map 集合轉為 JSON 字串 */
public static String map2json(Map, ?> map) {
JSONObject jsonObject = JSONObject.fromObject(map);
return jsonObject.toString();
}
/** 將任意 Java 物件轉為 JSON 字串 */
public static String object2json(Object object) {
JSONObject jsonObject = JSONObject.fromObject(object);
return jsonObject.toString();
}
/** 將 XML 字串轉為 JSON 字串 */
public static String xml2json(String xml) {
JSONArray jsonArray = (JSONArray) new XMLSerializer().read(xml);
return jsonArray.toString();
}
/**
* 進階配置:字段過濾、循環引用處理、日期格式化
* @param excludes 要排除的字段名陣列(如關聯物件防止循環引用)
*/
public static JsonConfig configJson(String[] excludes) {
JsonConfig jsonConfig = new JsonConfig();
jsonConfig.setExcludes(excludes); // 排除字段
jsonConfig.setIgnoreDefaultExcludes(true); // 忽略默認排除
jsonConfig.setCycleDetectionStrategy(CycleDetectionStrategy.LENIENT); // 寬容模式處理循環引用
// 可選:註冊日期值處理器
// jsonConfig.registerJsonValueProcessor(Date.class, new DateJsonValueProcessor("yyyy-MM-dd HH:mm:ss"));
return jsonConfig;
}
/** 帶配置的物件轉 JSON */
public static String object2json(Object object, String[] excludes) {
return JSONObject.fromObject(object, configJson(excludes)).toString();
}
/** 帶配置的 List 轉 JSON */
public static String list2json(List> list, String[] excludes) {
return JSONArray.fromObject(list, configJson(excludes)).toString();
}
}
@RestController
public class UserController {
@GetMapping("/users/{id}")
public String getUser(@PathVariable Long id) {
User user = userService.findById(id);
// 排除敏感字段與循環引用關聯
return JsonUtil.object2json(user, new String[]{"password", "roles", "orders"});
}
@GetMapping("/users")
public String listUsers(Pageable pageable) {
Page page = userService.findAll(pageable);
// 列表場景同樣需要過濾
return JsonUtil.list2json(page.getContent(), new String[]{"password", "roles"});
}
}
@Entity
public class Order {
@Id Long id;
@ManyToOne User user; // 關聯用戶
List items; // 關聯明細
}
@Entity
public class User {
@Id Long id;
@OneToMany(mappedBy = "user") List orders; // 反向關聯 → 循環引用
}
// 序列化時排除反向引用
String json = JsonUtil.object2json(user, new String[]{"orders"});
// 或在 Order 中排除 user
String json = JsonUtil.object2json(order, new String[]{"user.orders"});
public class DateJsonValueProcessor implements JsonValueProcessor {
private final String format;
public DateJsonValueProcessor(String format) { this.format = format; }
@Override
public Object processArrayValue(Object value, JsonConfig jsonConfig) {
return processObjectValue(null, value, jsonConfig);
}
@Override
public Object processObjectValue(String key, Object value, JsonConfig jsonConfig) {
if (value == null) return "";
if (value instanceof java.util.Date) {
return new SimpleDateFormat(format).format((Date) value);
}
return value.toString();
}
}
// 使用方式
JsonConfig config = JsonUtil.configJson(new String[]{"password"});
config.registerJsonValueProcessor(Date.class, new DateJsonValueProcessor("yyyy-MM-dd HH:mm:ss"));
String json = JSONObject.fromObject(user, config).toString();
// 輸出: {"createTime":"2024-01-15 14:30:00", ...}
String xml = "1 張三 ";
String json = JsonUtil.xml2json(xml);
// 輸出: [{"user":{"id":"1","name":"張三"}}]
// 注意:XMLSerializer 將根元素轉為 JSONArray,單個元素也會包在陣列中
json-lib 已停止維護,新專案強烈建議使用 Jackson 或 Gson。Jackson 遷移對照:
| json-lib | Jackson |
|---|---|
JSONObject.fromObject(obj) | objectMapper.writeValueAsString(obj) |
JSONArray.fromObject(list) | objectMapper.writeValueAsString(list) |
JsonConfig.setExcludes() | @JsonIgnore 或 objectMapper.setSerializationInclusion(Include.NON_NULL) |
CycleDetectionStrategy.LENIENT | @JsonManagedReference/@JsonBackReference 或 @JsonIdentityInfo |
JsonValueProcessor | @JsonFormat(pattern="yyyy-MM-dd") 或自定義 JsonSerializer |
@Configuration
public class JacksonConfig {
@Bean
public ObjectMapper objectMapper() {
ObjectMapper mapper = new ObjectMapper();
mapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
mapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false);
mapper.setDateFormat(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"));
mapper.registerModule(new JavaTimeModule()); // Java 8 時間類型支援
return mapper;
}
}
ObjectMapper 線程安全,應作為單例重用HttpMessageConverter 統一序列化JsonGenerator 流式寫入,減少記憶體佔用jackson-module-afterburner 提升序列化速度 30%+無論選用哪個 JSON 庫,核心設計原則一致:統一配置、字段可控、循環安全、日期標準。封裝好通用工具類,讓業務代碼專注於核心邏輯,而非格式轉換細節。