Как реализовать API, возвращающий вложенный JSON с отношением OneToMany в Spring Boot?

Я разрабатываю простой API для практического проекта Online Shopping System. Я совершенно новичок в Spring Boot framework и создаю API.

Я хочу вернуть JSON примерно так:

[
{
    "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
                }]
}]

Вот мои классы @Entity:

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

Также существует класс с именем Order.java, похожий на 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);
}
}

Эта программа получает данные из базы данных MySql. Данные хранятся в таблицах.

Таблицы выглядят так:
Продукты:
- pcod
- pnam
- pdes
- цена

Подробности:
- ordid
- pcod
- кол-во

Вот мой 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>

Когда я запускаю приложение и проверяю API с помощью POSTMAN, я получаю такой результат:

{
"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"

}

Как я могу решить эту проблему?

Спасибо за ответ

Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
3
0
4 734
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ответ принят как подходящий

Когда ваша сущность Product преобразуется в Json, у продукта есть список Details, детали также преобразуются в Json, но они снова ссылаются на Product, и это запускает бесконечный цикл, и вы получаете ошибку.

Решением может быть добавление @JsonIgnore в одну сторону связи.

@Entity
public class Detail {
    ...
    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "pcod")
    @JsonIgnore
    private Product product;
    ...
}

Наконец-то это работает. Большое спасибо Дэйвид

Tillo 05.04.2018 08:44

Использование аннотаций @JsonManagedReference и @JsonBackReference в двух объектах также может решить проблему. пожалуйста, обратитесь к эта статья о двунаправленных отношениях Джексона.

Другие вопросы по теме