You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用Gson转换实体时触发Java运行时异常的解决方案咨询

问题分析
  1. 核心异常原因:java.sql.Clob是接口类型,Gson默认无法实例化接口——它需要具体类的无参构造来创建对象,而接口没有构造方法,因此反序列化时抛出无法调用无参构造的异常。另外,Hibernate返回的Clob通常是代理对象,直接序列化会丢失有效数据,也无法通过Gson重建。
  2. 实体类低级错误:两个实体类都存在setter方法名错误,导致属性无法正确赋值:
    • TemplateData中,setTemplateData方法被错误命名为setTemplateId
    • TemplateAuditData中,setTemplateAuditId方法被错误命名为setTemplateId,且setTemplateData也被错误命名为setTemplateId
      这些错误会导致Gson在反序列化时无法正确注入属性值,即使解决了Clob的问题,对象属性也会赋值失败。
解决方案

步骤1:修正实体类的setter方法

先修复所有命名错误的setter,确保属性名和setter对应:

修复后的TemplateData

@Entity
@Table(name="Template")
public class TemplateData implements Serializable {
    @Column(name="template_id")
    public Integer templateId;
    
    @Lob
    @Column(name="template_Data")
    public Clob templateData;

    @Lob
    @Column(name="template_Total")
    public Clob templateTotal;
    
    public Integer getTemplateId(){
        return templateId;
    }
    
    public void setTemplateId(Integer templateId){
        this.templateId = templateId;
    }
    
    public Clob getTemplateData(){
        return templateData;
    }
    
    // 修正方法名
    public void setTemplateData(Clob templateData){
        this.templateData = templateData;
    }
    
    public Clob getTemplateTotal(){
        return templateTotal;
    }
    
    public void setTemplateTotal(Clob templateTotal){
        this.templateTotal = templateTotal;
    }
}

修复后的TemplateAuditData

@Entity
@Table(name="Template_Audit")
public class TemplateAuditData implements Serializable {

    @Column(name="template_Audit_id")
    public Integer templateAudtId;

    @Column(name="template_id")
    public Integer templateId;
    
    @Lob
    @Column(name="template_Data")
    public Clob templateData;

    @Lob
    @Column(name="template_Total")
    public Clob templateTotal;
    
    public Integer getTemplateAuditId(){
        return templateAudtId;
    }
    
    // 修正方法名
    public void setTemplateAuditId(Integer templateAudtId){
        this.templateAudtId = templateAudtId;
    }
    
    public Integer getTemplateId(){
        return templateId;
    }
    
    public void setTemplateId(Integer templateId){
        this.templateId = templateId;
    }
    
    public Clob getTemplateData(){
        return templateData;
    }
    
    // 修正方法名
    public void setTemplateData(Clob templateData){
        this.templateData = templateData;
    }
    
    public Clob getTemplateTotal(){
        return templateTotal;
    }
    
    public void setTemplateTotal(Clob templateTotal){
        this.templateTotal = templateTotal;
    }
}

步骤2:解决Clob的序列化/反序列化问题

推荐两种方案,根据场景选择:

方案A:将Clob替换为String(更简单)

Clob本质存储的是文本内容,直接在实体类中用String代替Clob,Hibernate依然可以将String映射到CLOB类型,只需修改字段注解:

// 替换TemplateData和TemplateAuditData中的Clob字段
@Lob
@Column(name="template_Data")
public String templateData;

@Lob
@Column(name="template_Total")
public String templateTotal;

// 对应的getter/setter也改成String类型
public String getTemplateData(){
    return templateData;
}

public void setTemplateData(String templateData){
    this.templateData = templateData;
}

这样Gson可以直接处理String类型,无需额外配置,序列化和反序列化都会正常工作。

方案B:给Gson注册Clob的TypeAdapter(保留Clob类型)

如果必须保留Clob类型,需要给Gson自定义TypeAdapter来处理Clob的序列化和反序列化:

// 自定义Clob类型适配器
public class ClobTypeAdapter extends TypeAdapter<Clob> {
    @Override
    public void write(JsonWriter out, Clob value) throws IOException {
        if (value == null) {
            out.nullValue();
            return;
        }
        try {
            // 将Clob转为字符串写入JSON
            Reader reader = value.getCharacterStream();
            out.value(new BufferedReader(reader).lines().collect(Collectors.joining("\n")));
            reader.close();
        } catch (SQLException e) {
            throw new IOException("Failed to read Clob", e);
        }
    }

    @Override
    public Clob read(JsonReader in) throws IOException {
        if (in.peek() == JsonToken.NULL) {
            in.nextNull();
            return null;
        }
        String content = in.nextString();
        try {
            // 创建SerialClob实例(Clob的一个具体实现)
            return new javax.sql.rowset.serial.SerialClob(content.toCharArray());
        } catch (SQLException e) {
            throw new IOException("Failed to create Clob", e);
        }
    }
}

然后创建Gson实例时注册这个适配器:

Gson gson = new GsonBuilder()
        .registerTypeAdapter(Clob.class, new ClobTypeAdapter())
        .create();

// 现在可以正常转换
TemplateAuditData tad = gson.fromJson(gson.toJson(td), new TypeToken<TemplateAuditData>(){}.getType());
注意事项
  • 若使用Hibernate,方案A的String映射CLOB完全兼容,无需额外配置;
  • 方案B中的SerialClob是JDK提供的Clob实现,确保项目依赖包含javax.sql.rowset相关包;
  • 避免直接序列化Hibernate代理对象,最好先调用一次getter触发懒加载,将代理对象转为普通对象再进行Gson转换。

内容的提问来源于stack exchange,提问作者kavya

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.09 23:01:37