[Trouble Shooting] Jackson์ ์ง๋ ฌํ ๊ด๋ จ ํธ๋ฌ๋ธ ์ํ
๋ฒ์จ ๋ค์ฏ ๋ฒ์งธ ๊ฐ์ธ๊ณผ์ ๋ฅผ ์งํ ์ค์ด๋ค.
์ด๋ฒ ๊ณผ์ ๋ [์ํ ํ์ ]์ ์ฃผ์ ๋ก ๊ณผ์ ๋ฅผ ํ๋ฉด์ Jackson์ ์ง๋ ฌํ ๊ด๋ จํ์ฌ ํธ๋ฌ๋ธ ์ํ ์ ๋ค๋ฃจ๋ ค๊ณ ํ๋ค.
1. ๋ฐฐ๊ฒฝ
1) ๋ฌธ์ ์ํฉ
๐ ์์ฒญ URL : PUT localhost:8080/exhange/1/cancel
๐ ํ์
→ IntelliJ ๋ฐ์ดํฐ๋ฒ ์ด์ค: exchange_request ํ ์ด๋ธ์ ์ํ๊ฐ NORMAL์์ CANCELED๋ก ์ ์์ ์ผ๋ก ๋ฐ์๋๋ ๊ฒ์ ํ์ธ
→ POSTMAN ์๋ต : 500 Internal Server Error ๋ฐ์
<์ ์ ์๋ต ๋ด์ฉ>
{
"createdAt": "2024-11-28T23:09:31.424224",
"modifiedAt": "2024-11-28T23:11:50.460609",
"id": 1,
"amountInKrw": 10000,
"amountAfterExchange": 6.99,
"status": "CANCELED"
}
<๋ฌธ์ ์ ์ค๋ฅ ๋ฉ์ธ์ง>

2) ์์ธ ๋ถ์
1๏ธโฃ ExchangeRequest ์ํฐํฐ๋ User์ Currency ์ํฐํฐ์ ManyToOne ๊ด๊ณ๋ฅผ ๊ฐ์ง
2๏ธโฃ User์ Currency ์ํฐํฐ๋ ๊ฐ๊ฐ ExchangeRequest๋ฅผ ์ฐธ์กฐ - ์๋ฐฉํฅ ์ฐ๊ด๊ด๊ณ
3๏ธโฃ Jackson ๋ผ์ด๋ธ๋ฌ๋ฆฌ์์ Entity์ getter๋ฅผ ํธ์ถํ๊ณ , ์ง๋ ฌํ๋ฅผ ์ด์ฉํด json์ผ๋ก ๋ณํํ๊ฒ ์ ์ก๊ฐ๋ฅํ ํํ๋ก ๋ฐ๊พธ์ด์ค๋ค.
Entity์ getter๋ฅผ ํธ์ถํ๋ ๊ณผ์ ์์ ์ฐ๊ด๋ ์ํฐํฐ๋ฅผ ๊ณ์ํด์ ๋ถ๋ฌ์ค๋ค ๋ณด๋ฉด ์ํ์ฐธ์กฐ๊ฐ ๋ฐ์ํ์ฌ Error๊ฐ ๋ฐ์ํ๊ฒ ๋ ๊ฒ์ด๋ค.
์ฆ, JPA์์ ์ฐ๊ด๊ด๊ณ์์ ์๋ฐฉํฅ ๊ด๊ณ๋ฅผ ๊ฐ์ง ๋ ์ํฐํฐ ๊ฐ์ ์๋ก๋ฅผ ์ฐธ์กฐํ๋ ๊ตฌ์กฐ์์ ์ง๋ ฌํ/์ญ์ง๋ ฌํ ์ JSON ๋ณํ ๊ณผ์ ์์ ์ํ์ฐธ์กฐ๊ฐ ๋ฐ์ํ๋ค.
-> ์ด๋ฅผ ์ ์ ํ ์ฒ๋ฆฌํ์ง ์์ผ๋ฉด ๋ฌดํ ๋ฃจํ๊ฐ ๋ฐ์ํ๊ฑฐ๋ ์ฑ๋ฅ ์ ํ ๋๋ ๋ฉ๋ชจ๋ฆฌ ๋ฌธ์ ๋ฅผ ์ด๋ํ ์ ์๋ค. ์ฐธ๊ณ ๋ธ๋ก๊ทธ(1)
2. ์ ์
โถ ์์ ์ ๋ก์ง
@ManyToOne(fetch = FetchType.LAZY) // ๋ฐ์ดํฐ๋ฅผ ์ค์ ๋ก ์ฌ์ฉํ ๋ ์กฐํ(์ง์ฐ๋ก๋ฉ ๋ฐฉ์)
@JoinColumn(name = "user_id", nullable = false)
@JsonBackReference // ์ํ ์ฐธ์กฐ ํด๊ฒฐ
private User user; // ๊ณ ๊ฐ ID -> user์ N:1 ๊ด๊ณ ์ค์
@ManyToOne(fetch = FetchType.LAZY) // ๋ฐ์ดํฐ๋ฅผ ์ค์ ๋ก ์ฌ์ฉํ ๋ ์กฐํ(์ง์ฐ๋ก๋ฉ ๋ฐฉ์)
@JoinColumn(name = "to_currency_id", nullable = false)
private Currency currency; // ํ์ ๋์ ํตํ ID -> currency์ N:1 ๊ด๊ณ ์ค์
- Currency ํ๋์๋ ์ํ ์ฐธ์กฐ๋ฅผ ๋ฐฉ์งํ๋ ์ด๋ ธํ ์ด์ ์ด ์์ด Jackson์ด JSON ์ง๋ ฌํ ๊ณผ์ ์์ ๋ฌธ์ ๊ฐ ๋ฐ์
โถ ์์ ๋ก์ง(๋ฐฉ๋ฒ 1)
@OneToMany(mappedBy = "currency", cascade = CascadeType.ALL, orphanRemoval = true)
@JsonManagedReference // ๋ถ๋ชจ ๊ด๊ณ๋ก ์ค์
private List<ExchangeRequest> exchangeRequests = new ArrayList<>();
@OneToMany(mappedBy = "user",cascade = CascadeType.ALL, orphanRemoval = true)
@JsonManagedReference //๋ถ๋ชจ ๊ด๊ณ๋ก ์ค์
private List<ExchangeRequest> exchangeRequests = new ArrayList<>();
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "user_id", nullable = false)
@JsonBackReference // ์์ ๊ด๊ณ๋ก ์ค์
private User user;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "to_currency_id", nullable = false)
@JsonBackReference // ์์ ๊ด๊ณ๋ก ์ค์
private Currency currency;
โก๏ธ @JsonManagedReference์ @JsonBackReference: ๋ถ๋ชจ-์์ ๊ด๊ณ๋ฅผ ๋ช ์์ ์ผ๋ก ์ค์ ํ์ฌ ์ง๋ ฌํ ๋ฐฉํฅ ์ ์ด ํ๋ ๋ฐฉ๋ฒ ์ ํ ์ฐธ๊ณ ๋ธ๋ก๊ทธ(2)
โถ ์์ ๋ก์ง(๋ฐฉ๋ฒ 2)
@ManyToOne(fetch = FetchType.LAZY) // ๋ฐ์ดํฐ๋ฅผ ์ค์ ๋ก ์ฌ์ฉํ ๋ ์กฐํ(์ง์ฐ๋ก๋ฉ ๋ฐฉ์)
@JoinColumn(name = "user_id", nullable = false)
@JsonIgnore// ์ํ ์ฐธ์กฐ ์๋ฌ ํด๊ฒฐ
private User user; // ๊ณ ๊ฐ ID -> user์ N:1 ๊ด๊ณ ์ค์
@ManyToOne(fetch = FetchType.LAZY) // ๋ฐ์ดํฐ๋ฅผ ์ค์ ๋ก ์ฌ์ฉํ ๋ ์กฐํ(์ง์ฐ๋ก๋ฉ ๋ฐฉ์)
@JoinColumn(name = "to_currency_id", nullable = false)
@JsonIgnore // ์ํ ์ฐธ์กฐ ์๋ฌ ํด๊ฒฐ
private Currency currency;
โก๏ธ @JsonBackReference๋ฅผ @JsonIgnore๋ก ๋ณ๊ฒฝ
โก๏ธ Currency ํ๋์๋ @JsonIgnore ์ด๋ ธํ ์ด์ ์ถ๊ฐ
โก๏ธ @JsonIgnore๋ฅผ ์ฌ์ฉํ์ฌ User์ Currency ํ๋๋ฅผ JSON ์ง๋ ฌํ ๊ณผ์ ํด์ ์์ ํ ๋ฌด์ํ๋๋ก ์ค์
โก๏ธ ์ํ ์ฐธ์กฐ ๋ฌธ์ ์ ์ง๋ ฌํ ์ค๋ฅ๋ฅผ ๋ชจ๋ ํด๊ฒฐํ ์ ์์ ๊ฒ
3. ๊ฒฐ๊ณผ
โก๏ธ IntelliJ ๋ฐ์ดํฐ๋ฒ ์ด์ค : exchange_request ํ ์ด๋ธ์ ์ํ๊ฐ NORMAL์์ CANCELED๋ก ์ ์์ ์ผ๋ก ๋ณ๊ฒฝ๋๋ ๊ฒ์ ํ์ธ
โก๏ธ POSTMAN ์๋ต : Error ์๋ฌ ๋ฐ์ ์์ด ์ ์ ํธ์ถ ํ์ธ

4. ๊ฒฐ๋ก
โญ๏ธ @JsonBackReference VS @JsonIgnore
1. @JsonBackReference, @JsonManagedReference ์ฌ์ฉ :
- @JsonBackReference๋ ์ง๋ ฌํ ๊ณผ์ ์์ ํด๋น ํ๋๋ฅผ ์ ์ธํ์ง๋ง, ๋ฐ๋์ชฝ ํ๋์ @JsonManagedReference์ด ์ง๊ฟ์ผ๋ก ํจ๊ป ํ์ํ๋ค!
-> @JsonManagedReference์ @JsonBackReference๋ ๋ถ๋ชจ-์์ ๊ด๊ณ๋ฅผ ๋ช ์์ ์ผ๋ก ์ค์ ํ์ฌ ์ง๋ ฌํ ๋ฐฉํฅ ์ ์ด ํ๋ ๋ฐฉ๋ฒ
-> @JsonManagedReference๋ ์ญ์ฐธ์กฐ๋ฅผ ๊ด๋ฆฌํ๋ ๊ฐ์ฒด์์ ์ฌ์ฉ, @JsonBackReference๋ ์ญ์ฐธ์กฐ๋ฅผ ํ์ง ์๋ ๊ฐ์ฒด์์ ์ฌ์ฉ
-> ์ด ๋ฐฉ๋ฒ์ ์์ ์ํฐํฐ๋ฅผ ์ง๋ ฌํํ์ง ์๊ธฐ ๋๋ฌธ์ ๋ฌดํ ์ํ ์ฐธ์กฐ ๋ฌธ์ ๋ฅผ ๋ฐฉ์งํ ์ ์๋ค.
2. @JsonIgnore ์ฌ์ฉ:
- JSON ์ง๋ ฌํ์ ์ญ์ง๋ ฌํ ๊ณผ์ ์์ ํ๋๋ฅผ ์์ ํ ๋ฌด์ํ๋ค.
-> ๊ฐ๋จํ๊ฒ ์ ์ฉํ ์ ์๋ ๋ฐฉ๋ฒ์ด์ง๋ง @JsonIgnore ์ด๋ ธํ ์ด์ ์ ์ฌ์ฉํ๋ฉด ํด๋น ํ๋๋ฅผ ์์ ํ ๋ฌด์ํ๊ฒ ๋๋ฏ๋ก ํ์ํ ๊ฒฝ์ฐ์๋ ๋ถ์ ํฉํ ๋ฐฉ๋ฒ์ด๋ผ๊ณ ํ๋ค.
