I am developing simple API for practice project Online Shopping System. I am totally new in Spring Boot framework and creating API.
I want to return JSON similar to this:
[
{
"id": 1,
"name": "pname_46",
"description": "pdesc_793_793_793_79",
"price": 519.95,
"details": [{"orderId": 10,
"productId": 1,
"quantity": 4
}
{"orderId": 12,
"productId": 1,
"quantity": 5
}]
},
{
"id": 2,
"name": "pname_608",
"description": "pdesc_874_874_874",
"price": 221.7,
"details": [{"orderId": 20,
"productId": 2,
"quantity": 2
}
{"orderId": 3,
"productId": 2,
"quantity": 67
}]
}]
Here is my @Entity
classes:
Product.java
@Entity
@Table(name = "Products")
public class Product implements Serializable {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
@Column(name = "pcod")
private int id;
@Column(name = "pnam")
private String name;
@Column(name = "pdes")
private String description;
@Column(name = "price")
private Double price;
@OneToMany(mappedBy = "product", cascade = CascadeType.ALL, orphanRemoval = true)
private List<Detail> details = new ArrayList<>();
//Constructor, setter, and getter ..
}
Detail.java
@Entity
@Table(name = "Details")
public class Detail {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private int id;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "ordid")
private Order order;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "pcod")
private Product product;
@Column(name = "qty")
private int quantity;
//constructor, setters, and getters ..
}
There is also class named Order.java similar to Product.java
ProductRepository.java
@Repository
public interface ProductRepository extends JpaRepository<Product, Integer> {
}
OnlineShoppingApiController.java
@RestController
public class OnlineShoppingApiController {
@Autowired
ProductRepository productRepository;
@GetMapping("/products")
public List<Product> getAllProducts(){
return productRepository.findAll();
}
@GetMapping("/products/id={id}")
public Optional<Product> getOneProduct(@PathVariable String id){
int pid = Integer.parseInt(id);
return productRepository.findById(pid);
}
}
ProjectApplication.java
@SpringBootApplication
public class ProjectApplication {
public static void main(String[] args) {
SpringApplication.run(ProjectApplication.class, args);
}
}
This program gets data from MySql database. There are stored data in tables.
Tables look like this:
Products:
- pcod
- pnam
- pdes
- price
Details:
- ordid
- pcod
- qty
Here is my pom.xml:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.example</groupId>
<artifactId>project</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>
<name>project</name>
<description>Demo project for Spring Boot</description>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.0.0.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
When I run the application and check the API using POSTMAN, I am getting this result:
{
"timestamp": "2018-04-04T13:39:44.021+0000",
"status": 500,
"error": "Internal Server Error",
"message": "Could not write JSON: could not extract ResultSet; nested exception is com.fasterxml.jackson.databind.JsonMappingException: could not extract ResultSet (through reference chain: java.util.ArrayList[0]->com.example.project.pojo.Product[\"details\"])",
"path": "/products"
}
How can I solve this problem?
Thanks for the answer
When your Product
entity is being converted to Json, the product have a List of Details
, the details are converted to Json as well but they are referencing the Product
again and this starts and endless loop and you get the error.
A solution could be to add a @JsonIgnore
in one side of the relationship
@Entity
public class Detail {
...
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "pcod")
@JsonIgnore
private Product product;
...
}
Using @JsonManagedReference and @JsonBackReference annotations in the two entities can solve the problem ,as well. please refer to this article about Jackson bidirectional relationships.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With