6

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

asked Apr 4, 2018 at 13:49

2 Answers 2

6

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;
 ...
}
answered Apr 4, 2018 at 14:04
Sign up to request clarification or add additional context in comments.

1 Comment

It finally works. Thank you so much David
1

Using @JsonManagedReference and @JsonBackReference annotations in the two entities can solve the problem ,as well. please refer to this article about Jackson bidirectional relationships.

answered Jul 9, 2019 at 8:51

Comments

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.