使用GSON将Java对象转换为JSON时出现了stackoverflow错误

3

我正在尝试使用GSON将一个Java对象(以列表格式)转换为JSON。我已经尝试了几种方法,但是都遇到了相同的错误。

第一次尝试

List<Techinv> techs = UserUtil.getTechModels(group, org);
Gson gson = new Gson();
String json = gson.toJson(techs); 

第二次尝试

List<Techinv> techs = UserUtil.getTechModels(group, org);
Type listType = new TypeToken<List<Techinv>>() {}.getType();
Gson gson = new Gson();
String json = gson.toJson(techs, listType);

第三次尝试

List<Techinv> techs = UserUtil.getTechModels(group, org);
GsonBuilder gsonBuilder = new GsonBuilder();

new GraphAdapterBuilder()
    .addType(Techinv.class)
    .registerOn(gsonBuilder);
Gson gson = gsonBuilder.create();
String json = gson.toJson(techs);

所有上述方法都失败了,要么是出现了stackoverflow错误,要么是将我的Techinv类中的一个成员变量(java int类型)转换为java向量时出错,这些问题都出现在GSON库中。
请告诉我在所有这些示例中我是否遗漏了一些简单的东西 :)
Techinv类(如果需要):
package org.cchit.inv.model;

import java.io.Serializable;
import java.util.Date;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.Lob;
import javax.persistence.ManyToOne;
import javax.persistence.NamedNativeQueries;
import javax.persistence.NamedNativeQuery;
import javax.persistence.NamedQueries;
import javax.persistence.NamedQuery;
import javax.persistence.Table;
import javax.persistence.Temporal;
import javax.persistence.TemporalType;


/**
 * The persistent class for the techinv database table.
 * 
 */
@Entity
@NamedNativeQueries ({
    @NamedNativeQuery(name="Techinv.deleteByOrgId",
            query="DELETE FROM techinv where org_id = ?")
})
@NamedQueries ({
    @NamedQuery(name="Techinv.removeUser",
            query="UPDATE Techinv t SET user_id = 0 where t.id = :techid"),
    @NamedQuery(name="Techinv.getAllByOrg",
            query="SELECT p FROM Techinv p where p.organization.liferayId = :orgid"),
    @NamedQuery(name="Techinv.getById",
            query="SELECT t FROM Techinv t where t.id = :id"),
    @NamedQuery(name="Techinv.getByProdOrg",
            query="SELECT p FROM Techinv p where p.organization.liferayId = :orgid and p.product.id = :prodid"),
    @NamedQuery(name="Techinv.delete",
            query="DELETE FROM Techinv t where t.id = :id")
    })
@Table(name="techinv")
public class Techinv implements Serializable {
    private static final long serialVersionUID = 1L;

    @Id @GeneratedValue(strategy=GenerationType.IDENTITY)
    private int id;

    @Column(name="mu_mask")
    private long muMask;

    @Column(name="mu_assigned_mask")
    private long muAssignedMask;

    @Column(name="mu_asked_assign_mask")
    private long muAskedAssignedMask;

    @Column(name="mu_cert_mask")
    private long muWillCertMask;

    @Column(name="mu_ask_will_cert_mask")
    private long muAskedWillCertMask;

    @Column(name="certType")
    private String certType;

    @Temporal(TemporalType.DATE)
    @Column(name="Apply_date")
    private Date applyDate;

    @Temporal(TemporalType.DATE)
    @Column(name="Cert_date")
    private Date certDate;

    @Lob()
    private String notes;

    //bi-directional many-to-one association to OrgUser
    @ManyToOne
    @JoinColumn(name="user_id")
    private OrgUser orgUser;

    //bi-directional many-to-one association to Organization
    @ManyToOne
    @JoinColumn(name="org_id")
    private Organization organization;

    //bi-directional many-to-one association to Product
    @ManyToOne
    @JoinColumn(name="prod_id")
    private Product product;

    //bi-directional many-to-one association to Certification
    @ManyToOne
    @JoinColumn(name="cert_id")
    private Certification certification;

    public void setCertification(Certification certification) {
        this.certification = certification;
    }

    public Product getProduct() {
        return product;
    }

    public void setProduct(Product product) {
        this.product = product;
    }

    public Techinv() {
    }

    public int getId() {
        return this.id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getNotes() {
        return this.notes;
    }

    public void setNotes(String notes) {
        this.notes = notes;
    }

    public OrgUser getOrgUser() {
        return this.orgUser;
    }

    public void setOrgUser(OrgUser orgUser) {
        this.orgUser = orgUser;
    }

    public Organization getOrganization() {
        return this.organization;
    }

    public void setOrganization(Organization organization) {
        this.organization = organization;
    }

    public long getMuMask() {
        return muMask;
    }

    public void setMuMask(long muMask) {
        this.muMask = muMask;
    }

    public long getMuAssignedMask() {
        return muAssignedMask;
    }

    public void setMuAssignedMask(long muAssigned) {
        this.muAssignedMask = muAssigned;
    }

    public Certification getCertification() {
        return certification;
    }

    public long getMuWillCertMask() {
        return muWillCertMask;
    }

    public void setMuWillCertMask(long muWillCertMask) {
        this.muWillCertMask = muWillCertMask;
    }

    public long getMuAskWillCertMask() {
        return muAskedWillCertMask;
    }

    public void setMuAskedWillCertMask(long muAskedWillCertMask) {
        this.muAskedWillCertMask = muAskedWillCertMask;
    }

    /**
     * This will set the question to true. Once asked and answered, this cannot be unset.
     * @param mu
     */
    public void setMuAskedAssignedMask(Mu mu) {
        this.muAskedAssignedMask |= mu.getMask();
    }

    public boolean isCertified(Mu mu) {
        return getCertification() != null && (getCertification().getMuMask() & mu.getMask()) > 0;
    }

    public boolean isAssigned(Mu mu) {
        return (getMuAssignedMask() & mu.getMask()) > 0;
    }

    public boolean hasAskedToCertify(Mu mu) {
        return isAssigned(mu) && !isCertified(mu) && (getMuAskWillCertMask() & mu.getMask()) > 0;
    }

    public boolean isWillCertify(Mu mu) {
        return hasAskedToCertify(mu) && (getMuWillCertMask() & mu.getMask()) > 0;
    }

    public boolean hasMu(Mu mu) {
        return (getMuMask() & mu.getMask()) > 0;
    }

    public boolean hasAskedToAssign(Mu mu) {
        return (muAskedAssignedMask & mu.getMask()) > 0;
    }

    public String getCertType() {
        return certType;
    }

    public void setCertType(String certType) {
        this.certType = certType;
    }

    public Date getApplyDate() {
        return applyDate;
    }

    public void setApplyDate(Date applyDate) {
        this.applyDate = applyDate;
    }

    public Date getCertDate() {
        return certDate;
    }

    public void setCertDate(Date certDate) {
        this.certDate = certDate;
    }
}

你的技术课程是什么样子的? - smk
3个回答

2
您应该检查序列化类中的循环引用,并将适当的属性标记为@Transient。如果需要帮助,请发布您的TechModel类。
编辑:如果您不能使用@Transient,可以使用Gson的@Expose。从GSON用户指南中可以看到:
此功能提供了一种方法,您可以标记对象的某些字段,以便在将其序列化和反序列化为JSON时排除考虑。要使用此注释,必须通过使用new GsonBuilder().excludeFieldsWithoutExposeAnnotation().create()来创建Gson。创建的Gson实例将排除未标记@Expose注释的类中的所有字段。

你的@ManyToOne映射不是双向的吗?例如,Organization类是否有TechInv列表? - user18428
是的,实际上它确实会。问题在于,如果我将其设置为瞬态,甚至在到达GSON代码之前就会失败。 - user1700945
我遇到了同样的问题,不使用Expose也没有帮助。我没有深入研究源代码,但我的猜测是GSON在检查对象是否标记为Expose之前调用了peek(),从而触发了相同的堆栈溢出。 - momo

0

您可以尝试使用Java API for JSON processing的标准实现,该实现是J2EE的一部分。

我无法访问您的bean OrgUserOrganizationProductCertification。因此,我假设它们每个都包含一个id和一个name

对于您的List<Techinv> techList

final SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");

List<Techinv> techList = new ArrayList<Techinv>();
for (int i = 1; i <= 3; i++) {
    Techinv tech = new Techinv(i, 1L, 2L, 3L, 4L, 5L, "cert",
            new Date(), new Date(), "notes", new OrgUser(i, "orguser"),
            new Organization(i, "organization"), new Product(i,
                    "product"), new Certification(i, "certification"));
    techList.add(tech);
}
Techinv[] techArr = techList.toArray(new Techinv[techList.size()]);

JsonArrayBuilder techArrBuilder = Json.createArrayBuilder();
for (Techinv tech : techArr) {
    JsonObjectBuilder jsonObject = Json.createObjectBuilder()
        .add("id", tech.getId())
        .add("muMask", tech.getMuMask())
        .add("muAssignedMask", tech.getMuAssignedMask())
        .add("muAskedAssignedMask", tech.getMuAskedAssignedMask())
        .add("muWillCertMask", tech.getMuWillCertMask())
        .add("muAskedWillCertMask", tech.getMuAskedWillCertMask())
        .add("certType", tech.getCertType())
        .add("applyDate", sdf.format(tech.getApplyDate()))
        .add("certDate", sdf.format(tech.getCertDate()))
        .add("notes", tech.getNotes())

        .add("OrgUser", Json.createObjectBuilder()
        .add("id", tech.getOrgUser().getId())
        .add("name", tech.getOrgUser().getName()))

        .add("Organization", Json.createObjectBuilder()
        .add("id", tech.getOrganization().getId())
        .add("name", tech.getOrganization().getName()))

        .add("Product", Json.createObjectBuilder()
        .add("id", tech.getProduct().getId())
        .add("name", tech.getProduct().getName()))

        .add("Certification", Json.createObjectBuilder()
        .add("id", tech.getCertification().getId())
        .add("name", tech.getCertification().getName()));
    techArrBuilder.add(jsonObject);
}
JsonArray jsonArray = techArrBuilder.build();

Map<String, Object> prop = new HashMap<String, Object>() {
    {
        put(JsonGenerator.PRETTY_PRINTING, true);
    }
};
JsonWriter jsonWriter = Json.createWriterFactory(prop).createWriter(System.out);
jsonWriter.writeArray(jsonArray);
jsonWriter.close();

输出应该是:

[
    {
        "id":1,
        "muMask":1,
        "muAssignedMask":2,
        "muAskedAssignedMask":3,
        "muWillCertMask":4,
        "muAskedWillCertMask":5,
        "certType":"cert",
        "applyDate":"2014-04-03",
        "certDate":"2014-04-03",
        "notes":"notes",
        "OrgUser":{
            "id":1,
            "name":"orguser"
        },
        "Organization":{
            "id":1,
            "name":"organization"
        },
        "Product":{
            "id":1,
            "name":"product"
        },
        "Certification":{
            "id":1,
            "name":"certification"
        }
    },
    {
        "id":2,
        "muMask":1,
        "muAssignedMask":2,
        "muAskedAssignedMask":3,
        "muWillCertMask":4,
        "muAskedWillCertMask":5,
        "certType":"cert",
        "applyDate":"2014-04-03",
        "certDate":"2014-04-03",
        "notes":"notes",
        "OrgUser":{
            "id":2,
            "name":"orguser"
        },
        "Organization":{
            "id":2,
            "name":"organization"
        },
        "Product":{
            "id":2,
            "name":"product"
        },
        "Certification":{
            "id":2,
            "name":"certification"
        }
    },
    {
        "id":3,
        "muMask":1,
        "muAssignedMask":2,
        "muAskedAssignedMask":3,
        "muWillCertMask":4,
        "muAskedWillCertMask":5,
        "certType":"cert",
        "applyDate":"2014-04-03",
        "certDate":"2014-04-03",
        "notes":"notes",
        "OrgUser":{
            "id":3,
            "name":"orguser"
        },
        "Organization":{
            "id":3,
            "name":"organization"
        },
        "Product":{
            "id":3,
            "name":"product"
        },
        "Certification":{
            "id":3,
            "name":"certification"
        }
    }
]

0
Type listType = new TypeToken<ArrayList<Techinv>>() {}.getType();

不行,这仍然会导致 java.lang.StackOverflowError 在 java.util.ArrayList.get(ArrayList.java:322) 在 com.google.gson.stream.JsonWriter.peek(JsonWriter.java:354) 在 com.google.gson.stream.JsonWriter.beforeName(JsonWriter.java:565) 在 com.google.gson.stream.JsonWriter.writeDeferredName(JsonWriter.java:386) 在 com.google.gson.stream.JsonWriter.value(JsonWriter.java:480) 在 com.google.gson.internal.bind.TypeAdapters$7.write(TypeAdapters.java:237) 在 com.google.gson.internal.bind.TypeAdapters$7.write(TypeAdapters.java:222) - user1700945

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接