diff --git a/README.md b/README.md index d41cf41..0d94ffd 100644 --- a/README.md +++ b/README.md @@ -56,6 +56,194 @@ ## โœ… ERD ![ERD](https://github.com/so2zy/so2zy_BE/assets/139187207/3c2bdb39-d128-4568-a0f7-f61d746e6897) + ## ๐Ÿ’ฏ ์—๋Ÿฌ ํ•ด๊ฒฐ ๋ฐฉ์•ˆ +
+์—๋Ÿฌ ๋‚ด์šฉ ๋ฐ ํ•ด๊ฒฐ + +### 1. StackOverFlow Error ๋ฌธ์ œ + +**1 - 1. ์›์ธ** + +```bash +Infinite recursion (StackOverflowError) +(through reference chain: com.aroom.domain.room.model.Room["accommodation"] +->com.aroom.domain.accommodation.model.Accommodation["roomList"] +->org.hibernate.collection.spi.PersistentBag[0] +->com.aroom.domain.room.model.Room["accommodation"] +->com.aroom.domain.accommodation.model.Accommodation["roomList"]- +``` + +ํ˜„์žฌ ์–‘๋ฐฉํ–ฅ ์—ฐ๊ด€๊ด€๊ณ„์— ๋†“์—ฌ์ง„ Accommodation๊ณผ Room์—์„œ ๋ฌดํ•œ์ˆœํ™˜์ฐธ์กฐ๊ฐ€ ๋ฐœ์ƒํ–ˆ๋‹ค. +
+**1 - 2. ํ•ด๊ฒฐ** + +- `@OneToMany`ย `@manytoone`๋กœ ์ธํ•ด ์ˆœํ™˜์ฐธ์กฐ ์›์ธ +- `@JsonManagedReference` & `@JsonBackReference` ์ถ”๊ฐ€ + +```java +@JsonManagedReference +@OneToMany(mappedBy = "accommodation", fetch = FetchType.LAZY) +private List roomList = new ArrayList<>(); +``` + +- `@JsonManagedReference` : ๋ถ€๋ชจ `Entity` โ†’ ์ž์‹ `Entity` + - ์ •์ƒ์ ์œผ๋กœ ์ง๋ ฌํ™”๋ฅผ ์ˆ˜ํ–‰ + +```java +@JsonBackReference +@ManyToOne(fetch = FetchType.LAZY) +@JoinColumn(name = "accommodation_id") +private Accommodation accommodation; +``` + +- `@JsonBackReference` : ์ž์‹`Entity` โ†’ ๋ถ€๋ชจ `Entity` + - ์ง๋ ฌํ™” ์ˆ˜ํ–‰ x + + โ‡’ ๋ฌดํ•œ ์ˆœํ™˜ ์ฐธ์กฐ ํ•ด๊ฒฐ + +
+ +### 2. Jackson ์ง๋ ฌํ™” ์ œํ•œ์ž ๋ฌธ์ œ + +**2 - 1. ๋ฐœ์ƒ ๊ณผ์ •** + +```java +public RoomCartResponseDTO postRoomCart(Long member_id, Long room_id){ + Room room = roomRepository.findById(room_id).get(); + Cart cart = cartRepository.findByMemberId(member_id).get(); + RoomCart roomCart = roomCartRepository.save(new RoomCart(cart,room)); + cart.postRoomCarts(roomCart); + return new RoomCartResponseDTO(cart); +} +``` + +```java +@OneToMany(mappedBy = "cart", fetch = FetchType.LAZY) +private List roomCartList = new ArrayList<>(); + +public void postRoomCarts(RoomCart roomCart){ + roomCartList.add(roomCart); +} +``` + +๊ฐ์‹ค์„ ์žฅ๋ฐ”๊ตฌ๋‹ˆ์— ๋‹ด์„ ๋•Œ RoomCart๋ฅผ ์ƒ์„ฑํ•˜์—ฌ Cart์˜ List roomCartList์— post ์‹œ๋„ +
+ +**2 - 2. ์›์ธ** + +```bash +Type definition error: [simple type, class com.aroom.domain.roomCart.dto.response.RoomCartResponseDTO] +``` + +```bash +org.springframework.http.converter.HttpMessageConversionException: Type definition error: [simple type, class com.aroom.domain.roomCart.dto.response.RoomCartResponseDTO] +at org.springframework.http.converter.json.AbstractJackson2HttpMessageConverter.writeInternal(AbstractJackson2HttpMessageConverter.java:489) ~[spring-web-6.0.13.jar:6.0.13] +at org.springframework.http.converter.AbstractGenericHttpMessageConverter.write(AbstractGenericHttpMessageConverter.java:103) ~[spring-web-6.0.13.jar:6.0.13] +at +``` + +```bash +caused by: com.fasterxml.jackson.databind.exc.invaliddefinitionexception: +no serializer found for class com.aroom.domain.roomcart.dto.response.roomcartresponsedto +and no properties discovered to create beanserializer +(to avoid exception, disable serializationfeature.fail_on_empty_beans) +(through reference chain: com.aroom.global.response.apiresponse["data"]) +``` + +- Jackson ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๊ฐ€ `RoomCartResponseDTO`ย &ย `RoomCartInfoDTO`๋ฅผ ์ง๋ ฌํ™”ํ•  ๋•Œ ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒ +- Jackson์€ ๊ธฐ๋ณธ์ ์œผ๋กœ ํด๋ž˜์Šค๋ฅผ ์ง๋ ฌํ™”ํ•  ๋•Œ ํ•ด๋‹น ํด๋ž˜์Šค์— ๋Œ€ํ•œ ์ง๋ ฌํ™” ๋ฉ”์†Œ๋“œ๋ฅผ ์ฐพ์•„์•ผ ํ•˜๋Š”๋ฐ, ์—ฌ๊ธฐ์„œ๋Š” ํ•ด๋‹น ๋ฉ”์†Œ๋“œ๋ฅผ ์ฐพ์ง€ ๋ชปํ–ˆ๋‹ค๊ณ  ๋‚˜์˜จ๋‹ค. +- ๋˜ํ•œ, Jackson์€ ์ง๋ ฌํ™” ํ•˜๋Š” ๊ณผ์ •์—์„œ ๊ธฐ๋ณธ์œผ๋กœ ์ ‘๊ทผ ์ œํ•œ์ž๊ฐ€ public์ด๊ฑฐ๋‚˜, getter/setter๋ฅผ ์ด์šฉํ•˜๊ธฐ ๋•Œ๋ฌธ์— ์ธ์Šคํ„ด์Šค ํ•„๋“œ๋ฅผ private๋“ฑ์œผ๋กœ ์„ ์–ธ์‹œ, json์œผ๋กœ ๋ณ€ํ™˜ ๊ณผ์ •์—์„œ ์—๋Ÿฌ๊ฐ€ ๋ฐœ์ƒํ•œ๋‹ค. +
+ +**2 - 3. ํ•ด๊ฒฐ** + +```java +@JsonAutoDetect(fieldVisibility = JsonAutoDetect.Visibility.ANY) +public class RoomCartResponseDTO { + + private long cart_id; + private List roomCartList; + + public RoomCartResponseDTO(Cart cart) { + this.cart_id = cart.getId(); + List roomCartInfoDTOList = new ArrayList<>(); + for(RoomCart roomCart : cart.getRoomCartList()){ + RoomCartInfoDTO roomCartInfoDTO = new RoomCartInfoDTO(roomCart); + roomCartInfoDTOList.add(roomCartInfoDTO); + } + System.out.println(roomCartInfoDTOList.size()); // ์ •ํ™•ํžˆ ๋‚˜์˜ด + this.roomCartList = roomCartInfoDTOList; + } +} +``` + +```java +@JsonAutoDetect(fieldVisibility = JsonAutoDetect.Visibility.ANY) +public class RoomCartInfoDTO { + + private long room_id; + private long cart_id; + + @Builder + public RoomCartInfoDTO(long room_id, long cart_id) { + this.room_id = room_id; + this.cart_id = cart_id; + } + + public RoomCartInfoDTO(RoomCart roomCart) { + this.room_id = roomCart.getRoom().getId(); + this.cart_id = roomCart.getCart().getId(); + } +} +``` + +- JsonAutoDetect ์„ค์ • ์ œ๊ฑฐ + + `@JsonAutoDetect(fieldVisibility = JsonAutoDetect.Visibility.ANY)` + + - private ํ•„๋“œ์— ์ ‘๊ทผ ๊ฐ€๋Šฅํ•˜์—ฌ json์œผ๋กœ ๋ณ€ํ™˜ ๊ฐ€๋Šฅํ•˜๋‹ค. +- Fetch.Type์„ EAGER๋กœ ๋ฐ”๊พธ๋Š” ๊ฒƒ์€ ๋ณด์•ˆ์˜ ๋ฌธ์ œ๊ฐ€ ์žˆ์œผ๋ฏ€๋กœ ๊ณ ๋ คํ•˜์ง€ ์•Š์•˜์Šต๋‹ˆ๋‹ค. +- ๋˜ํ•œ, Entity Class์— @JsonProperty ๋˜๋Š” @JsonAutoDetect๋ฅผ ์ง์ ‘ ์„ ์–ธํ•  ์ˆ˜ ์žˆ์œผ๋‚˜, Entity๋ฅผ ์ตœ๋Œ€ํ•œ ๋ณ€๊ฒฝํ•˜์ง€ ์•Š๊ณ ์ž DTO์— ์„ ์–ธํ–ˆ์Šต๋‹ˆ๋‹ค. +
+ +### 3. JPAQueryFactory ์ „์—ญ ์„ค์ •๊ณผ DataJpaTest + +**3 - 1. ์›์ธ** + +```java +Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'com.querydsl.jpa.impl.JPAQueryFactory' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {} + at org.springframework.beans.factory.support.DefaultListableBeanFactory.raiseNoMatchingBeanFound(DefaultListableBeanFactory.java:1824) + at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1383) + at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1337) + at org.springframework.beans.factory.support.ConstructorResolver.resolveAutowiredArgument(ConstructorResolver.java:910) + at org.springframework.beans.factory.support.ConstructorResolver.createArgumentArray(ConstructorResolver.java:788) + ... 108 more +``` + +ํ•ด๋‹น ์„ค์ •์€ ์ „์—ญ์ ์œผ๋กœ ๋นˆ์„ ์ปจํ…Œ์ด๋„ˆ์— ์ƒ์„ฑํ•˜๋Š” ๊ฒƒ์ด๊ธฐ ๋•Œ๋ฌธ์— `Entity`์™€ `Respository` ๋นˆ๋งŒ ์ƒ์„ฑํ•˜๋Š” `@DataJpaTest์˜` ๊ฒฝ์šฐ์—๋Š” `JpaQueryFactory` ๋นˆ์„ ์ƒ์„ฑํ•˜์ง€ ๋ชปํ•˜๋Š” ๋ฌธ์ œ๊ฐ€ ์ƒ๊ธฐ๊ฒŒ ๋ฉ๋‹ˆ๋‹ค. +
+ +**3 - 2. ํ•ด๊ฒฐ** + +```java +@Configuration +@EnableJpaAuditing +@EnableJpaRepositories(basePackages = "com.aroom") +public class JpaConfig { + + @PersistenceContext + private EntityManager entityManager; + + @Bean + public JPAQueryFactory queryFactory() { + return new JPAQueryFactory(entityManager); + } + +} +``` + +ํ•ด๋‹น ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•˜๊ธฐ ์œ„ํ•ด์„œ๋Š” ์‹ค์ œย `JPAQueryFactory`๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ณณ์—์„œ๋งŒ ํ•ด๋‹น ๋นˆ์„ ์ƒ์„ฑํ•˜๋ฉด ๋ฉ๋‹ˆ๋‹ค. +
## ๐Ÿค– ๊ฐœ์ธ ์—ญ๋Ÿ‰ ํšŒ๊ณ