【问题标题】:Java JPA Hibernate - Error: Infinite recursionJava JPA Hibernate - 错误:无限递归
【发布时间】:2016-10-09 14:13:40
【问题描述】:

我有 3 个实体(产品、提供商和价格),其中价格与其他 2 个相关联。一个产品可以有多个价格,每个提供商一个价格:

产品类别:

@Entity
@Table(name = "products") 
public class Product implements java.io.Serializable {

@Id
@GeneratedValue(strategy = GenerationType.AUTO)
@Column(name = "product_id")
private int id;

@Column(name = "product_category")
private String productCategory;

@Column(name = "product_subcategory")
private String productSubcategory;

@Column(name = "product_name")
private String productName;

@Column(name = "product_description")
private String productDescription;

@OneToMany(fetch = FetchType.LAZY, mappedBy = "pk.product", cascade=CascadeType.ALL)
private Set<Prices_1> prices_1 = new HashSet<Prices_1>(0);


public Set<Prices_1> getPrices_1(){
    return prices_1;
}

public void setPrices_1(Set<Prices_1> prices_1){
    this.prices_1 = prices_1;
}

public int getId() {
    return id;
}

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

public String getProductCategory() {
    return productCategory;
}

public void setProductCategory(String productCategory) {
    this.productCategory = productCategory;
}

public String getProductSubcategory() {
    return productSubcategory;
}

public void setProductSubcategory(String productSubcategory) {
    this.productSubcategory = productSubcategory;
}

public String getProductName() {
    return productName;
}

public void setProductName(String productName) {
    this.productName = productName;
}

public String getProductDescription() {
    return productDescription;
}

public void setProductDescription(String productDescription) {
    this.productDescription = productDescription;
}

@Override
public String toString() {
    return "ProductController [id=" + id + ", productName=" + productName
            + ", productCategory=" + productCategory + ", productSubcategory=" + productSubcategory
            + ", productDescription=" + productDescription
            + "]";
}

}

提供者类:

@Entity
@Table(name="providers")
public class Provider implements java.io.Serializable {

@Id
@GeneratedValue(strategy = GenerationType.AUTO)
@Column(name="provider_id")
private int id;

@Column(name="provider_name")
private String providerName;

@Column(name="provider_address")
private String providerAddress;

@Column(name="provider_phone")
private String providerPhone;

@Column(name="provider_archived")
private int providerArchived = 0;

@OneToMany(fetch = FetchType.LAZY, mappedBy = "pk.provider")
private Set<Prices_1> prices_1 = new HashSet<Prices_1>(0);

public Set<Prices_1> getPrices_1() {
    return prices_1;
}

public void setPrices_1(Set<Prices_1> prices_1) {
    this.prices_1 = prices_1;
}

public int getId() {
    return id;
}

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

public String getProviderName() {
    return providerName;
}

public void setProviderName(String providerName) {
    this.providerName = providerName;
}

public String getProviderAddress() {
    return providerAddress;
}

public void setProviderAddress(String providerAddress) {
    this.providerAddress = providerAddress;
}

public String getProviderPhone() {
    return providerPhone;
}

public void setProviderPhone(String providerPhone) {
    this.providerPhone = providerPhone;
}

public int getProviderArchived() {
    return providerArchived;
}

public void setProviderArchived(int providerArchived) {
    this.providerArchived = providerArchived;
}

@Override
public String toString() {
    return "ProviderController [id=" + id + ", providerName=" + providerName
            + ", providerAddress=" + providerAddress + ", providerPhone="
            + providerPhone + "]";
}

}

Prices_1 类:

@Entity
@Table(name = "prices_1")
@AssociationOverrides({
    @AssociationOverride(name = "pk.product",
            joinColumns = @JoinColumn(name = "product_id")),
    @AssociationOverride(name = "pk.provider",
            joinColumns = @JoinColumn(name = "provider_id"))})
public class Prices_1 implements java.io.Serializable {

@EmbeddedId
private PricesId pk = new PricesId();

@Column(name = "price")
private float price;

public PricesId getPk() {
    return pk;
}

public void setPk(PricesId pk) {
    this.pk = pk;
}

public float getPrice() {
    return price;
}

public void setPrice(float price) {
    this.price = price;
}

@Transient
public Product getProduct() {
    return getPk().getProduct();
}

public void setProduct(Product product) {
    getPk().setProduct(product);
}

@Transient
public Provider getProvider() {
    return getPk().getProvider();
}

public void setProvider(Provider provider) {
    getPk().setProvider(provider);
}


public boolean equals(Object o) {
    if (this == o)
        return true;
    if (o == null || getClass() != o.getClass())
        return false;

    Prices_1 that = (Prices_1) o;

    if (getPk() != null ? !getPk().equals(that.getPk())
            : that.getPk() != null)
        return false;

    return true;
}

public int hashCode() {
    return (getPk() != null ? getPk().hashCode() : 0);
}

}

PricesID 类:

@Embeddable
public class PricesId implements java.io.Serializable {

@ManyToOne
private Product product;

@ManyToOne
private Provider provider;

public Product getProduct() {
    return product;
}

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

public Provider getProvider() {
    return provider;
}

public void setProvider(Provider provider) {
    this.provider = provider;
}

public boolean equals(Object o) {
    if (this == o) return true;
    if (o == null || getClass() != o.getClass()) return false;

    PricesId that = (PricesId) o;

    if (product != null ? !product.equals(that.product) : that.product != null) return false;
    if (provider != null ? !provider.equals(that.provider) : that.provider != null) return false;

    return true;
}

public int hashCode() {
    int result;
    result = (product != null ? product.hashCode() : 0);
    result = 31 * result + (provider != null ? provider.hashCode() : 0);
    return result;
}

}

ProductsRepository 类:

@Repository
public class ProductsRepository {

@PersistenceContext
EntityManager em;

public List<Product> findAllProducts(){
    Query query = em.createQuery("SELECT e FROM Product e");
    return (List<Product>) query.getResultList();
}

}

ProductsService 类:

@Service
public class ProductsService {

@Autowired
ProductsRepository productsRepository;

@Transactional(readOnly = true)
public List<Product> findAllProducts(){
    List<Product> pv = productsRepository.findAllProducts();
    return pv;
}

}

ProductsController 类:

@Controller
@RequestMapping("product")
public class ProductController {

@Autowired
private ProductsService productsService;

@ResponseBody
@ResponseStatus(HttpStatus.OK)
@RequestMapping(method = RequestMethod.GET)
public List<Product> getProducts(){
    List<Product> productList = productsService.findAllProducts();
    for (Product p : productList){
        System.out.println("Andres. Provider name: " + p.getProductName());
    }
    return productList;
}
}

控制器返回的ArrayList产品列表:

问题是 Products[0] 有 2 个价格_1。 Price_1[0] 关联了 Product 和 Provider,两者都关联了 Price_1 等。最终陷入无限循环

任何想法如何获得以下对象: 产品列表,每个产品都有一个价格列表,每个供应商一个价格。

谢谢!

编辑: 问题不在于创建的 ArrayList productList,当 productList 对象返回到浏览器时会触发错误:

【问题讨论】:

  • 您如何将其返回到浏览器? - 这可能是因为当它被转换为 json 时,调用了 toString() 方法,该方法试图序列化在 prices_1 中定义的产品和提供者。尝试在 priceid 类中将产品和提供者定义为瞬态。
  • 非常感谢您的快速回复@PushpendraPal。我并返回浏览器“return productList;” (ArrayList 产品列表)。我在 PriceId.java 中的 Product 和 Provider 对象中都添加了“@Transient”,但应用程序没有运行:“PricesId 没有持久的 id 属性:....model.Prices_1.pk”。自动序列化是我首先关心的问题,这就是我覆盖所有 toString() 方法(产品、提供者和价格_1)的原因。
  • hmm... 我认为在产品和提供者上覆盖 toString() 将不起作用,因为当您返回 productList 时,将在列表上调用 toString()(您的产品的 java.util.List )。它没有被覆盖,并且仍然会查找列表中所有对象的序列化......我还观察到 toString 没有被覆盖为 prices_1 .....
  • 嗨@PushpendraPal,我在 Price_1 类中添加了“@Override toString()”,但没有任何区别。
  • 您可以尝试创建产品的通用列表。我在答案下面给出的泛型.. 然后通过在 GenericClass 对象上使用 toString 从控制器返回字符串...您可以向此 GenericClass 添加其他未实现的方法,但无需为这些提供实现

标签: java hibernate jpa


【解决方案1】:
public class GenericClass<E> implements List<E> {

private List<E> list;
public GenericClass() {
    this.list = new ArrayList<>();
}


@Override
public String toString() {
    StringBuilder s = new StringBuilder();
    for (E e : list) {
        s.append(e.toString());
    }
    return s.toString();
}

@Override
public boolean add(E e) {

    return list.add(e);
}

@Override
public boolean addAll(Collection<? extends E> c) {

    return list.addAll(c);
}

}

【讨论】:

    【解决方案2】:

    我创建了 3 个数据传输对象来自定义和协调列表 productList:

    public class ProductsDTO {
    
    private List<ProductDTO> productDTOSet = new ArrayList<ProductDTO>(0);
    
    public ProductsDTO(List<ProductDTO> productDTOSet) {
        this.productDTOSet = productDTOSet;
    }
    
    public static ProductsDTO mapFromProductSetEntity(List<Product> products){
        List<ProductDTO> productDTOs = new ArrayList<ProductDTO>(0);
        for (Product p : products) {
            productDTOs.add(ProductDTO.mapFromProductEntity(p));
        }
        return new ProductsDTO(productDTOs);
    }
    
    public class ProductDTO {
    
    private int id;
    private String productCategory;
    private String productSubcategory;
    private String productName;
    private String productDescription;
    private Set<PriceDTO> prices = new HashSet<PriceDTO>(0);
    
    
    public ProductDTO(int id, String productCategory, String productSubcategory, String productName,
                      String productDescription, Set<PriceDTO> prices) {
        this.id = id;
        this.productCategory = productCategory;
        this.productSubcategory = productSubcategory;
        this.productName = productName;
        this.productDescription = productDescription;
        this.prices = prices;
    }
    
    public static ProductDTO mapFromProductEntity(Product product){
    
        Set<PriceDTO> priceDTOs = new HashSet<PriceDTO>(0);
        for (Prices_1 p1 : product.getPrices_1()){
            priceDTOs.add(PriceDTO.mapFromPrice_1Entity(p1));
        }
    
        return new ProductDTO(product.getId(), product.getProductCategory(), product.getProductSubcategory()
        , product.getProductName(), product.getProductDescription(), priceDTOs);
    }
    }
    
    public class PricesDTO {
    
    private Set<PriceDTO> pricesDTO = new HashSet<PriceDTO>(0);
    
    public Set<PriceDTO> getPricesDTO() {
        return pricesDTO;
    }
    
    public void setPricesDTO(Set<PriceDTO> pricesDTO) {
        this.pricesDTO = pricesDTO;
    }
    }
    

    然后将 List productList 映射到 DTO:

    @Controller
    @RequestMapping("product")
    public class ProductController {
    
    @Autowired
    private ProductsService productsService;
    
    @ResponseBody
    @ResponseStatus(HttpStatus.OK)
    @RequestMapping(method = RequestMethod.GET)
    public ProductsDTO getProducts(){
        List<Product> productList = productsService.findAllProducts();
        for (Product p : productList){
            System.out.println("Andres. Provider name: " + p.getProductName());
        }
    
        return ProductsDTO.mapFromProductSetEntity(productList);
    }
    }
    

    结果如下:

    【讨论】:

      猜你喜欢
      • 2018-10-02
      • 1970-01-01
      • 2020-06-25
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-03-20
      相关资源
      最近更新 更多