首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 綜合教學

Struts2 JSON 序列化 StackOverflowError 根因分析與解決方案

     編輯:Java 綜合教學

問題現象

Struts2 使用 JSON 插件回傳資料時,若 Action 中的 Map<String, Object> 放入包含雙向關聯或循環引用的領域物件(如 Hibernate 實體),org.apache.struts2.json.JSONWriter 遞迴遍歷物件圖時導致 java.lang.StackOverflowError。

錯誤堆疊追蹤

java.lang.StackOverflowError
    at sun.reflect.misc.ReflectUtil.checkPackageAccess(ReflectUtil.java:177)
    at java.beans.Introspector.getBeanInfo(Introspector.java:154)
    at org.apache.struts2.json.JSONWriter.bean(JSONWriter.java:177)
    at org.apache.struts2.json.JSONWriter.process(JSONWriter.java:160)
    at org.apache.struts2.json.JSONWriter.value(JSONWriter.java:126)
    at org.apache.struts2.json.JSONWriter.add(JSONWriter.java:352)
    at org.apache.struts2.json.JSONWriter.bean(JSONWriter.java:215)
    ... (無限遞迴)

問題程式碼

public class LogAction extends ActionSupport {
    private Map<String, Object> dataMap = new HashMap<>();
    
    public String list() {
        dataMap.clear();
        PageParameter page = new PageParameter();
        // ... 查詢邏輯 ...
        List<UserSessionlog> sessionlogList = userService.findlog(...);
        
        dataMap.put("page", page);              // 包含集合引用
        dataMap.put("sessionlogList", sessionlogList); // 列表元素可能反向引用 page
        return "success";
    }
}

根因分析

  1. JSONWriter 使用 JavaBeans Introspector 內省物件屬性
  2. 若物件圖存在循環引用(A → B → A),遞迴序列化永不終止
  3. Struts2 JSON 插件預設無循環檢測機制

解決方案對比

方案優點缺點
移除循環引用物件(如範例移除 page)簡單直接損失資料完整性
使用 DTO/VO 替代領域物件解耦表現層與領域層,可控序列化內容需額外轉換程式碼
配置 JSON 插件排除屬性非侵入式Struts2 JSON 插件支援有限
改用 Jackson/Gson 並啟用循環檢測功能強大,@JsonIgnore、@JsonManagedReference/@JsonBackReference 完整支援需整合第三方庫

推薦最佳實務:DTO 模式

// 專用傳輸物件,無循環引用
public class LogPageDTO {
    private List<UserSessionlogVO> logs;
    private int totalCount, totalPage, currentPage;
    // Getter/Setter
}

// Action 中轉換
public String list() {
    LogPageDTO dto = new LogPageDTO();
    dto.setLogs(convertToVOList(sessionlogList));
    dto.setTotalCount(totalCount);
    // ...
    dataMap.put("dto", dto);
    return "success";
}

快速緩解方案(不引入 DTO)

若必須直接序列化領域物件,可嘗試在 struts.xml 配置 excludeProperties 排除導致循環的屬性,或實作自定義 JSONInterceptor 覆寫序列化邏輯。但長期來說,DTO 模式是架構正確的選擇。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved