Search code examples
javajsonspringhibernate

Looping problem when serializing objects to JSON in Spring Boot


I'm using Spring Boot 3.2 version with MySQL database. I have two objects

@Getter
@Setter
@Entity
@Table(name = "shops")
public class Shop{

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    private String address;
    @OneToMany(mappedBy = "shop", cascade = CascadeType.ALL, fetch = FetchType.LAZY)
    private List<Book> books;
}

and

@Getter
@Setter
@Entity
@Table(name = "books")
public class Book{

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    private String description;

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "shop_id")
    private Shop shop;
}

So I have some lopping problem when I'm trying to get all Shops with all books. I have object Shop with all Books object inside each book has his own shop object inside with all book etc. And it looks like

[
    {
        "id": 4,
        "address": "Street",
        "books": [
                {
                "id": 3,
                "description": "Book1",
                "shop" : {
                       "id": 4,
                       "address": "Street"
                       "books": [
                               {
                                "id": 3,
                                "description": "Book1",
                                "shop" : { ...
                               }
                       ]
                }
        ]
     }
]

So the problem is that I want to use one class for saving shops/books and geting from database. Then I need that shop have all books as objects with all data but books have only shopId. So getting all shops should look like this

[
    {
        "id": 4,
        "address": "Street",
        "books": [
                {
                "id": 3,
                "description": "Book1",
                "shop" : 4
                }
         ]
     }
]

and geeting all books should look like this

[
    {
        "id": 3,
        "description": "Book1",
        "shop": 4
    },
    {
        "id": 4,
        "description": "Book2",
        "shop": 5
    },
    {
        "id": 5,
        "description": "Book4",
        "shop": 5
    },
]

As I said I want to use same class for saving shop/books and same class for getting. I faced with couple problems.

  1. I dont want to create additional ShopDTO/BookDTO objects for getting because if it will be 1M books then I need to created 1M objects each time while getting.
  2. I can't add just one more variable such as Long shopId; because it will be hibernate error Table [books] contains physical column name [shop_id] referred to by multiple logical column names: [shop_id], [shopId]
  3. I can't change
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "shop_id")
private Shop shop; 

on

@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "shop_id")
private Long shop;

or remove @ManyToOne at all.


Solution

  • So I found the solution. I have added @JsonIdentityInfo to my shop

    @JsonIdentityInfo(generator = ObjectIdGenerators.PropertyGenerator.class, property = "id")
    public class Shop{...
    

    and added same for Book and added one more annotation to my Shop

    @JsonIdentityInfo(generator = ObjectIdGenerators.PropertyGenerator.class, property = "id")
    public class Book{...
       @JsonIdentityReference(alwaysAsId = true)
       private Shop shop;
    }