java - 将对象列表转换为 Json 字符串时出现 Stackoverflow 错误

标签 java json rest

我有一个 Java RESTapi,我想在其中将自定义 Pet 对象的列表转换为 Json,并将其显示在端点中。

这是我目前所拥有的:

@Path("/allPets")
@GET
@Produces(MediaType.APPLICATION_JSON)
public Response getPetsfromCollection() {
    List<Pet> petList = new ArrayList<>();
    petList.addAll(facade.returnAllPets());

    String json = gson.toJson(petList);

    //TODO return proper representation object
     return Response.ok().entity(json).build();
}

我正在使用外观模式,其中我有一种将 Java 实体添加到列表中的方法:

EntityManagerFactory emf = Persistence.createEntityManagerFactory("PetHospitaljpa");


public Collection<Pet> returnAllPets (){

    EntityManager  em = emf.createEntityManager();
    //vi laver en typed query for at specificere hvilken datatype, 
    // det er vi leder efter, i dette tilfælde er det en Pet
    TypedQuery<Pet> query = em.createNamedQuery("Pet.findAll", Pet.class);
    return query.getResultList();
}

我正在返回一个集合,以防我以后想将 ArrayList 的数据结构更改为其他内容。

我已经尝试了几种解决方法,但我总是收到堆栈溢出错误。

我知道我需要改用 DTO,并且我创建了一个自定义方法来将实体更改为 DTO:

public static DTOPet converttoDTO(Pet entity){

   DTOPet dto = new DTOPet();
   dto.setId(entity.getId());
   dto.setName(entity.getName());
   dto.setBirth(entity.getBirth());
   dto.setDeath(entity.getDeath());
   dto.setSpecies(entity.getSpecies());

   return dto;
}

如果我可以做其他事情来将实体集合转换为 DTO,我不确定这是否是良好的代码实践?

正如指出的那样。出现这个问题是因为我有一个循环引用。

在我的宠物实体类中:

@ManyToOne
private Owner ownerId;

在我的所有者实体类中:

@OneToMany(mappedBy = "ownerId")
private Collection<Pet> petCollection;

我的宠物类:

    /*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */
package Entities;

import java.io.Serializable;
import java.util.Collection;
import java.util.Date;
import javax.persistence.Basic;
import javax.persistence.CascadeType;
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.ManyToOne;
import javax.persistence.NamedQueries;
import javax.persistence.NamedQuery;
import javax.persistence.OneToMany;
import javax.persistence.Table;
import javax.persistence.Temporal;
import javax.persistence.TemporalType;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Size;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.XmlTransient;

/**
 *
 * @author kristoffer
 */
@Entity
@Table(name = "pet")
@XmlRootElement
@NamedQueries({
    @NamedQuery(name = "Pet.findAll", query = "SELECT p FROM Pet p")
    , @NamedQuery(name = "Pet.findById", query = "SELECT p FROM Pet p WHERE p.id = :id")
    , @NamedQuery(name = "Pet.findByName", query = "SELECT p FROM Pet p WHERE p.name = :name")
    , @NamedQuery(name = "Pet.findByBirth", query = "SELECT p FROM Pet p WHERE p.birth = :birth")
    , @NamedQuery(name = "Pet.findBySpecies", query = "SELECT p FROM Pet p WHERE p.species = :species")
    , @NamedQuery(name = "Pet.findByDeath", query = "SELECT p FROM Pet p WHERE p.death = :death")})
public class Pet 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;
    @Basic(optional = false)
    @NotNull
    @Column(name = "birth")
    @Temporal(TemporalType.DATE)
    private Date birth;
    @Basic(optional = false)
    @NotNull
    @Size(min = 1, max = 45)
    @Column(name = "species")
    private String species;
    @Column(name = "death")
    @Temporal(TemporalType.DATE)
    private Date death;
    @OneToMany(cascade = CascadeType.ALL, mappedBy = "petId")
    private Collection<Event> eventCollection;
    @JoinColumn(name = "owner_id", referencedColumnName = "id")
    @ManyToOne
    private Owner ownerId;

    public Pet() {
    }

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

    public Pet(Integer id, String name, Date birth, String species) {
        this.id = id;
        this.name = name;
        this.birth = birth;
        this.species = species;
    }

    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;
    }

    public Date getBirth() {
        return birth;
    }

    public void setBirth(Date birth) {
        this.birth = birth;
    }

    public String getSpecies() {
        return species;
    }

    public void setSpecies(String species) {
        this.species = species;
    }

    public Date getDeath() {
        return death;
    }

    public void setDeath(Date death) {
        this.death = death;
    }

    @XmlTransient
    public Collection<Event> getEventCollection() {
        return eventCollection;
    }

    public void setEventCollection(Collection<Event> eventCollection) {
        this.eventCollection = eventCollection;
    }

    public Owner getOwnerId() {
        return ownerId;
    }

    public void setOwnerId(Owner ownerId) {
        this.ownerId = ownerId;
    }

    @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 Pet)) {
            return false;
        }
        Pet other = (Pet) 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 "Pet{" + "id=" + id + ", name=" + name + ", birth=" + birth + ", species=" + species + ", death=" + death + ", eventCollection=" + eventCollection + ", ownerId=" + ownerId + '}';
    }   
}

编辑: 我尝试创建一个方法,将所有对象转换为 DTO,但显示时字符串仍然为空:

 @Path("/allPets")
@GET
@Produces(MediaType.APPLICATION_JSON)
public Response getPetsfromCollection() { 

    //med denne metode skal vi bruge et DTO(data transfer object til at formatere til Json)

    List<Pet> petList = new ArrayList<>();
    List<DTOPet> DTOPetList = new ArrayList<>();

    petList.addAll(facade.returnAllPets());
    for(Pet pet: petList){
        DTOPet dtopet = EntitytoDTO.converttoDTO(pet);
        DTOPetList.add(dtopet);
    }

    String json = gson2.toJson(DTOPetList);
     return Response.ok().entity(json).build();
}

当我使用调试器时,使用正确的参数成功创建了新列表,但字符串 JSON 只是像这样创建的 [{},{},{},{}] ,即使我使用 GSON

最佳答案

你需要检测错误的地方。我建议添加调试信息,比如

@Path("/allPets")
@GET
@Produces(MediaType.APPLICATION_JSON)
public Response getPetsfromCollection() {
    log.debug("getPetsfromCollection start");
    List<Pet> petList = new ArrayList<>(facade.returnAllPets());
    log.debug("petList" + petList.length());

    String json = gson.toJson(petList);
    log.debug("json " + json);

    //TODO return proper representation object
     return Response.ok().entity(json).build();
}


EntityManagerFactory emf = Persistence.createEntityManagerFactory("PetHospitaljpa");
public Collection<Pet> returnAllPets (){
    log.debug("returnAllPets start"); 
    EntityManager  em = emf.createEntityManager();
    log.debug("createNamedQuery start"); 
    TypedQuery<Pet> query = em.createNamedQuery("Pet.findAll", Pet.class);
    log.debug("single result" + query.getSingleResult() ); 

    TypedQuery<Pet> query = em.createNamedQuery("Pet.findAll", Pet.class);
    log.debug("list result" + query.getResultList()); 

    TypedQuery<Pet> query = em.createNamedQuery("Pet.findAll", Pet.class);
    return query.getResultList();
}

P.S. 另外,请展示 Pet 类,这个类可能有问题。

更新:我也建议尝试临时删除:

@OneToMany(cascade = CascadeType.ALL, mappedBy = "petId")
private Collection<Event> eventCollection;

和/或

@JoinColumn(name = "owner_id", referencedColumnName = "id")
@ManyToOne
private Owner ownerId;

并检查您是否有此类 SO 异常。看起来 Event 或 Owner 表太大或具有循环依赖性。

关于java - 将对象列表转换为 Json 字符串时出现 Stackoverflow 错误,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52438546/

相关文章:

java - 如何在java中构建RESTful请求

rest - 错误 : Nonce is too small - Bitfinex api

java - 如何让嵌入式mongodb在应用程序关闭时保留数据?

java - 如何确定一个列表是否以相同的顺序包含在另一个列表中(在 Java 中)?

java - jackson 与 JSON : private attributes instead of public

php - 处理来自 php 和 jQuery 的 json 变量,改为给出文本变量

java - SOAP 。代码忽略断开连接的客户端( java.net.SocketException : Broken pipe )

java - 为什么线程间通信需要notify()

android - 将数据从 listView 传递到 Activity

rest - REST Web 服务中的 GET 与 POST