Я просто хочу отобразить простой объект, включающий отношение один ко многим, однако он всегда возвращает эту ошибку.
1) Error mapping com.example.ProductDTO to com.example.Product
1 error] with root cause
java.lang.StackOverflowError: null
Я упростил свои классы и запускаю снова и снова, но не могу найти решение. Ниже приведены файлы для весенней загрузки (репозиторий, служба, контроллер, сущности и DTO).
Когда я впервые отправляю запрос POST для создания продукта с функциями (сын внизу сообщения), он создает сущности и сохраняться в БД. Когда я отправляю тот же json для обновления (PUT), он возвращает ошибку StackOverflow.
Есть ли способ сопоставить класс Product с ProductFeatures связанной сущности?
Product.class
package com.example;
import com.fasterxml.jackson.annotation.JsonManagedReference;
import java.io.Serializable;
import java.util.HashSet;
import java.util.Set;
import java.util.UUID;
import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.Id;
import javax.persistence.OneToMany;
import javax.persistence.Table;
import javax.persistence.Version;
import lombok.Getter;
import lombok.Setter;
@Getter
@Setter
@Entity
@Table(name = "product")
public class Product implements Serializable {
@Id
@Column(name = "id", columnDefinition = "BINARY(16)")
private UUID id;
@Version
private Long version;
@Column(length = 64, nullable = false)
private String name;
@Column(length = 128)
private String description;
@OneToMany(mappedBy = "product", fetch = FetchType.EAGER, orphanRemoval = true, cascade = CascadeType.PERSIST)
@JsonManagedReference("product_features")
private Set<ProductFeature> features = new HashSet<>();
public Product() {
this.id = UUID.randomUUID();
}
@Override
public String toString() {
return id.toString();
}
@Override
public int hashCode() {
return id.hashCode();
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null) {
return false;
}
if (!(obj instanceof Product)) {
return false;
}
Product other = (Product) obj;
return getId().equals(other.getId());
}
public UUID getId() {
return id;
}
public void setId(UUID id) {
this.id = id;
}
}
ProductFeature.class
package com.example;
import com.fasterxml.jackson.annotation.JsonBackReference;
import java.io.Serializable;
import java.util.UUID;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.Table;
import javax.persistence.Version;
import lombok.Getter;
import lombok.Setter;
@Getter
@Setter
@Entity
@Table(name = "productfeatures")
public class ProductFeature implements Serializable {
@Id
@Column(name = "id", columnDefinition = "BINARY(16)")
private UUID id;
@Version
private Long version;
@Column
private int type;
@Column
private int intValue;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "product", nullable = false)
@JsonBackReference("product_features")
private Product product;
public ProductFeature() {
this.id = UUID.randomUUID();
}
@Override
public String toString() {
return id.toString();
}
@Override
public int hashCode() {
return id.hashCode();
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null) {
return false;
}
if (!(obj instanceof ProductFeature)) {
return false;
}
ProductFeature other = (ProductFeature) obj;
return getId().equals(other.getId());
}
public UUID getId() {
return id;
}
public void setId(UUID id) {
this.id = id;
}
}
ProductDTO.class
package com.example;
import com.fasterxml.jackson.annotation.JsonManagedReference;
import java.io.Serializable;
import java.util.HashSet;
import java.util.Set;
import java.util.UUID;
import lombok.Getter;
import lombok.Setter;
@Getter
@Setter
public class ProductDTO implements Serializable {
private UUID id;
private String name;
private String description;
@JsonManagedReference("product_features")
private Set<ProductFeatureDTO> features = new HashSet<>();
public ProductDTO() {
this.id = UUID.randomUUID();
}
@Override
public String toString() {
return id.toString();
}
@Override
public int hashCode() {
return id.hashCode();
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null) {
return false;
}
if (!(obj instanceof ProductDTO)) {
return false;
}
ProductDTO other = (ProductDTO) obj;
return getId().equals(other.getId());
}
public UUID getId() {
return id;
}
public void setId(UUID id) {
this.id = id;
}
}
ProductFeatureDTO.class
package com.example;
import com.fasterxml.jackson.annotation.JsonBackReference;
import java.io.Serializable;
import java.util.UUID;
import lombok.Getter;
import lombok.Setter;
@Getter
@Setter
public class ProductFeatureDTO implements Serializable {
private UUID id;
private int type;
private int intValue;
@JsonBackReference("product_features")
private ProductDTO product;
public ProductFeatureDTO() {
this.id = UUID.randomUUID();
}
@Override
public String toString() {
return id.toString();
}
@Override
public int hashCode() {
return id.hashCode();
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null) {
return false;
}
if (!(obj instanceof ProductFeatureDTO)) {
return false;
}
ProductFeatureDTO other = (ProductFeatureDTO) obj;
return getId().equals(other.getId());
}
public UUID getId() {
return id;
}
public void setId(UUID id) {
this.id = id;
}
}
ProductRepository.class
package com.example;
import java.util.UUID;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
@Repository
public interface ProductRepository extends JpaRepository<Product, UUID> {
}
ProductRestController.class
package com.example;
import java.security.Principal;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
import java.util.UUID;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
@RestController
public class ProductRestController {
@Autowired
private ProductService productService;
@GetMapping("/products")
public List<ProductDTO> getProducts(Principal principal) {
return productService.get();
}
@GetMapping("/products/{id}")
public ProductDTO getProduct(@PathVariable UUID id) {
return productService.get(id);
}
@PostMapping("/products")
public ResponseEntity<?> create(@RequestBody ProductDTO input) {
return productService.create(input);
}
@PutMapping("/products/{id}")
public ResponseEntity<?> update(@PathVariable UUID id, @RequestBody ProductDTO input) {
return productService.update(id, input);
}
}
ProductService.class
package com.example;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
import org.modelmapper.ModelMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
@Service
public class ProductService {
@Autowired
private ProductRepository productRepository;
@Autowired
private ModelMapper modelMapper;
public List<ProductDTO> get() {
List<Product> products = productRepository.findAll();
List<ProductDTO> productDTOs = new ArrayList<>();
for (Product product : products) {
ProductDTO productDTO = modelMapper.map(product, ProductDTO.class);
productDTOs.add(productDTO);
}
return productDTOs;
}
public ProductDTO get(UUID id) {
Product product = productRepository.findById(id).get();
ProductDTO productDTO = modelMapper.map(product, ProductDTO.class);
return productDTO;
}
public ResponseEntity<?> create(ProductDTO productDTO) {
Product product = modelMapper.map(productDTO, Product.class);
Product p = productRepository.save(product);
return new ResponseEntity<>(modelMapper.map(p, ProductDTO.class), HttpStatus.OK);
}
public ResponseEntity<?> update(UUID id, ProductDTO productDTO) {
Product foundproduct = productRepository.getOne(id);
modelMapper.map(productDTO, foundproduct);
Product p = productRepository.save(foundproduct);
return new ResponseEntity<>(modelMapper.map(p, ProductDTO.class), HttpStatus.OK);
}
}
JSON
{
"id" : "6d1ed14a-d464-415a-9181-a3396ee9cd3e",
"name" : "Test Product 11",
"features" : [ {
"id" : "5103e648-180a-4fb8-bc98-98efc5edf1c1",
"type" : 13,
"intValue" : 1
}, {
"id" : "e43fdb3e-ce80-4b7b-98db-00117cabf7e2",
"type" : 11,
"intValue" : 1
}, {
"id" : "4798849a-d849-4987-bfcc-da92adf9f813",
"type" : 12,
"intValue" : 1
}, {
"id" : "abc6883e-cbd9-4557-ad66-5b4ca6ef4084",
"type" : 10,
"intValue" : 1
}, {
"id" : "bb594179-80f2-4051-989e-280406a42775",
"type" : 14,
"intValue" : 1
} ]
}