【问题标题】:Servlet Gson().toJson infinite loopServlet Gson().toJson 无限循环
【发布时间】:2014-07-28 10:47:51
【问题描述】:

我在 servlet 中遇到了一些问题,每次我在下拉菜单中更改选项时, 一个不同的值将被传递给 servlet,然后它会导致无限循环。当我不更改下拉菜单中的选项(值不变)时,没有错误。

这是我的代码:

我的 Javascript:

<script>

function loadStaff(){
//dropdown
var positionDropDown = document.getElementById("positionsDropdown");
//value of the drop down
var positionID = positionDropDown.options[positionDropDown.selectedIndex].value;

    $.getJSON('loadStaff?positionID=' + positionID, function(data) {
            -- no populate code yet
});
}
</script>

我的 AjaxServlet:

protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

      String userPath = request.getServletPath();

    if (userPath.equals("/loadStaff")) {

        String positionID = request.getParameter("positionID");
        Position position = positionFacade.find(Integer.parseInt(positionID));
        Collection staffCollection = position.getStaffCollection();
        List<Staff> staffList = new ArrayList(staffCollection);

        String staffListJson = new Gson().toJson(staffList);
        response.setContentType("application/json");
        response.setCharacterEncoding("UTF-8");
        response.getWriter().write(staffListJson);

    }

}

在调试时。错误出现在以下行:

String staffListJson = new Gson().toJson(staffList);

输出错误:

> INFO:   WebModule[null] ServletContext.log(): The server side
> component of the HTTP Monitor has detected a
> java.lang.StackOverflowError. This happens when there is an infinite
> loop in the web module. Correct the cause of the infinite loop before
> running the web module again.
> 
> INFO:   The server side component of the HTTP Monitor has detected a
> java.lang.StackOverflowError. This happens when there is an infinite
> loop in the web module. Correct the cause of the infinite loop before
> running the web module again. WARNING:  
> StandardWrapperValve[AjaxServlet]: Servlet.service() for servlet
> AjaxServlet threw exception java.lang.StackOverflowError

> WARNING:   StandardWrapperValve[AjaxServlet]: Servlet.service() for
> servlet AjaxServlet threw exception java.lang.StackOverflowError  at
> sun.util.calendar.ZoneInfo.getOffsets(ZoneInfo.java:248)  at
> java.util.GregorianCalendar.computeFields(GregorianCalendar.java:2276)
>   at
> java.util.GregorianCalendar.computeFields(GregorianCalendar.java:2248)
>   at java.util.Calendar.setTimeInMillis(Calendar.java:1140)   at
> java.util.Calendar.setTime(Calendar.java:1106)    at
> java.text.SimpleDateFormat.format(SimpleDateFormat.java:955)  at
> java.text.SimpleDateFormat.format(SimpleDateFormat.java:948)  at
> java.text.DateFormat.format(DateFormat.java:336)  at
> com.google.gson.internal.bind.DateTypeAdapter.write(DateTypeAdapter.java:90)
>   at
> com.google.gson.internal.bind.DateTypeAdapter.write(DateTypeAdapter.java:41)
>   at
> com.google.gson.internal.bind.TypeAdapterRuntimeTypeWrapper.write(TypeAdapterRuntimeTypeWrapper.java:68)
>   at
> com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$1.write(ReflectiveTypeAdapterFactory.java:89)
>   at
> com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$Adapter.write(ReflectiveTypeAdapterFactory.java:195)
>   at com.google.gson.Gson$FutureTypeAdapter.write(Gson.java:892)  at
> com.google.gson.internal.bind.TypeAdapterRuntimeTypeWrapper.write(TypeAdapterRuntimeTypeWrapper.java:68)
>   at
> com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$1.write(ReflectiveTypeAdapterFactory.java:89)
>   at
> com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$Adapter.write(ReflectiveTypeAdapterFactory.java:195)
>   at
> com.google.gson.internal.bind.TypeAdapterRuntimeTypeWrapper.write(TypeAdapterRuntimeTypeWrapper.java:68)
>   at
> com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$1.write(ReflectiveTypeAdapterFactory.java:89)
>   at
> com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$Adapter.write(ReflectiveTypeAdapterFactory.java:195)
>   at com.google.gson.Gson$FutureTypeAdapter.write(Gson.java:892)  at
> com.google.gson.internal.bind.TypeAdapterRuntimeTypeWrapper.write(TypeAdapterRuntimeTypeWrapper.java:68)
>   at
> com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$1.write(ReflectiveTypeAdapterFactory.java:89)
>   at
> com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$Adapter.write(ReflectiveTypeAdapterFactory.java:195)
>   at
> com.google.gson.internal.bind.TypeAdapterRuntimeTypeWrapper.write(TypeAdapterRuntimeTypeWrapper.java:68)
>   at
> com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$1.write(ReflectiveTypeAdapterFactory.java:89)
>   at
> com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$Adapter.write(ReflectiveTypeAdapterFactory.java:195)
>   at com.google.gson.Gson$FutureTypeAdapter.write(Gson.java:892)

我还注意到这些跟踪只是重复堆栈跟踪的输出;

编辑: 员工班

@Entity
public class Staff implements Serializable {
    private static final long serialVersionUID = 1L;
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Basic(optional = false)
    @Column(name = "id")
    private Integer id;
    @Basic(optional = false)
    @NotNull
    @Size(min = 1, max = 45)
    @Column(name = "last_name")
    private String lastName;
    @Basic(optional = false)
    @NotNull
    @Size(min = 1, max = 45)
    @Column(name = "first_name")
    private String firstName;
    @Size(max = 45)
    @Column(name = "middle_name")
    private String middleName;
    @Basic(optional = false)
    @NotNull
    @Size(min = 1, max = 6)
    @Column(name = "gender")
    private String gender;
    @Basic(optional = false)
    @NotNull
    @Column(name = "date_of_birth")
    @Temporal(TemporalType.DATE)
    private Date dateOfBirth;
    @Basic(optional = false)
    @NotNull
    @Size(min = 1, max = 45)
    @Column(name = "nationality")
    private String nationality;
    @Basic(optional = false)
    @NotNull
    @Column(name = "date_hired")
    @Temporal(TemporalType.TIMESTAMP)
    private Date dateHired;
    @Size(max = 20)
    @Column(name = "status")
    private String status;
    @OneToMany(cascade = CascadeType.ALL, mappedBy = "staff")
    private Collection<StaffApointments> staffApointmentsCollection;
    @OneToOne(cascade = CascadeType.ALL, mappedBy = "staff")
    private StaffContact staffContact;
    @JoinColumn(name = "account_id", referencedColumnName = "id")
    @ManyToOne(optional = false)
    private Account accountId;
    @JoinColumn(name = "position_id", referencedColumnName = "id")
    @ManyToOne(optional = false)
    private Position positionId;

    public Staff() {
    }

    public Staff(Integer id) {
        this.id = id;
    }

    public Staff(Integer id, String lastName, String firstName, String gender, Date dateOfBirth, String nationality, Date dateHired) {
        this.id = id;
        this.lastName = lastName;
        this.firstName = firstName;
        this.gender = gender;
        this.dateOfBirth = dateOfBirth;
        this.nationality = nationality;
        this.dateHired = dateHired;
    }

    public Integer getId() {
        return id;
    }

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

    public String getLastName() {
        return lastName;
    }

    public void setLastName(String lastName) {
        this.lastName = lastName;
    }

    public String getFirstName() {
        return firstName;
    }

    public void setFirstName(String firstName) {
        this.firstName = firstName;
    }

    public String getMiddleName() {
        return middleName;
    }

    public void setMiddleName(String middleName) {
        this.middleName = middleName;
    }

    public String getGender() {
        return gender;
    }

    public void setGender(String gender) {
        this.gender = gender;
    }

    public Date getDateOfBirth() {
        return dateOfBirth;
    }

    public void setDateOfBirth(Date dateOfBirth) {
        this.dateOfBirth = dateOfBirth;
    }

    public String getNationality() {
        return nationality;
    }

    public void setNationality(String nationality) {
        this.nationality = nationality;
    }

    public Date getDateHired() {
        return dateHired;
    }

    public void setDateHired(Date dateHired) {
        this.dateHired = dateHired;
    }

    public String getStatus() {
        return status;
    }

    public void setStatus(String status) {
        this.status = status;
    }

    @XmlTransient
    public Collection<StaffApointments> getStaffApointmentsCollection() {
        return staffApointmentsCollection;
    }

    public void setStaffApointmentsCollection(Collection<StaffApointments> staffApointmentsCollection) {
        this.staffApointmentsCollection = staffApointmentsCollection;
    }

    public StaffContact getStaffContact() {
        return staffContact;
    }

    public void setStaffContact(StaffContact staffContact) {
        this.staffContact = staffContact;
    }

    public Account getAccountId() {
        return accountId;
    }

    public void setAccountId(Account accountId) {
        this.accountId = accountId;
    }

    public Position getPositionId() {
        return positionId;
    }

    public void setPositionId(Position positionId) {
        this.positionId = positionId;
    }

    @Override
    public int hashCode() {
        int hash = 0;
        hash += (id != null ? id.hashCode() : 0);
        return hash;
    }

    @Override
    public boolean equals(Object object) {
        // TODO: Warning - this method won't work in the case the id fields are not set
        if (!(object instanceof Staff)) {
            return false;
        }
        Staff other = (Staff) object;
        if ((this.id == null && other.id != null) || (this.id != null && !this.id.equals(other.id))) {
            return false;
        }
        return true;
    }

    @Override
    public String toString() {
        return "entity.Staff[ id=" + id + " ]";
    }

}

这也是 Position 类:

@Entity
public class Position implements Serializable {
    private static final long serialVersionUID = 1L;
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Basic(optional = false)
    @Column(name = "id")
    private Integer id;
    @Basic(optional = false)
    @NotNull
    @Size(min = 1, max = 45)
    @Column(name = "name")
    private String name;
    @OneToMany(cascade = CascadeType.ALL, mappedBy = "positionId")
    private Collection<Staff> staffCollection;

    public Position() {
    }

    public Position(Integer id) {
        this.id = id;
    }

    public Position(Integer id, String name) {
        this.id = id;
        this.name = name;
    }

    public Integer getId() {
        return id;
    }

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

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    @XmlTransient
    public Collection<Staff> getStaffCollection() {
        return staffCollection;
    }

    public void setStaffCollection(Collection<Staff> staffCollection) {
        this.staffCollection = staffCollection;
    }

    @Override
    public int hashCode() {
        int hash = 0;
        hash += (id != null ? id.hashCode() : 0);
        return hash;
    }

    @Override
    public boolean equals(Object object) {
        // TODO: Warning - this method won't work in the case the id fields are not set
        if (!(object instanceof Position)) {
            return false;
        }
        Position other = (Position) object;
        if ((this.id == null && other.id != null) || (this.id != null && !this.id.equals(other.id))) {
            return false;
        }
        return true;
    }

    @Override
    public String toString() {
        return "entity.Position[ id=" + id + " ]";
    }

}

编辑 2:

我将@expose 添加到我的员工类中的属性,但staffCollection 除外。但我还有 1 个问题。每次选择下拉列表中的第一个值(值 = 1)时,它仍然会给出无限循环错误。谁能帮帮我?

编辑 3:

修好了!我添加了最终的 GsonBuilder builder = new GsonBuilder(); builder.excludeFieldsWithoutExposeAnnotation();作为一个整体。现在可以使用了

【问题讨论】:

  • Servlet 对我来说听起来像 Java,你的错误可以验证这个想法......也许使用 java 标签会有所帮助?
  • 不要使用这里使用的原始类型Collection staffCollection,然后在没有任何检查的情况下将其转换为通用List如果你有一个循环引用,这可能会发生。在解析时导致无限循环。也分享PosiitonStaff 课程。
  • @Braj 我的类是作为实体类从数据库生成的。 “Staff”表从“Position”表中引用其 position_id。如果我不能清楚地理解你,请原谅我,在你提到工作人员集合的集合时,你会建议我做什么?
  • @JeremyMiller 现在由 Braj 编辑。很抱歉无法标记 java。您对如何解决此问题有任何想法吗?
  • 你能显示 Staff 类中有哪些字段吗?

标签: java javascript servlets gson


【解决方案1】:

问题是每个Staff对象都包含一个Position对象,该对象包含Staff对象的Collection,每个对象又包含Staff对象的Collection,等等。GSON将继续遍历这棵树永远,因为它永远不会停止。

要解决它,您可以查看this 问题的答案。

【讨论】:

  • 感谢您重定向我。我很难理解要公开的内容。我应该在员工类中公开职位 positionID 吗?它仍然给我错误。你能澄清一下吗?
  • 不,你应该在 JSON 中公开所有元素,除了你不想要的元素
  • 这会影响我的 CRUD 操作吗?
  • 不,它只会用于解析 JSON
  • 谢谢@MaxMeijer!我已经在这里迷路了好几个小时了。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2011-07-06
  • 1970-01-01
  • 2011-08-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多