728x90
메시지 체인?
레퍼런스를 따라 계속해서 메서드 호출이 이어지는 형태를 말한다.
코드로 보자면
product.getUser().getId()
와 같은 형태이다.
흔히 '냄새나는 코드' 라는 이름으로 리팩토링 대상이 되는 구문이다.
리팩토링 방법
주로 '캡슐화'를 통해 해결한다.
클래스 내부에 해당 메서드 체인을 숨겨서, 외부에서는 product 클래스만으로 해당 상품의 userId를 알 수 있도록 하는 것이다.
public class Product{
private User user;
//etc
public Long getUserId(){
return this.user.getId();
}
}
위와 같이 Product 내부에 user.getId()를 숨겨서, 외부에서는
product.getUserId() 라는 메서드로 product의 userId를 한번에 찾아올 수 있다.
JPA에서의 오류
해당 메서드 체인을 리팩토링 하는 과정에서,
getUserId 메서드를 작성한 이후 컴파일 에러가 발생했다.
Caused by: org.springframework.data.repository.query.QueryCreationException: Could not create query for public abstract java.util.List wanted.market.api.domain.orders.repository.OrderRepository.findAllByProductUserIdAndStatus(java.lang.Long,wanted.market.api.domain.orders.enums.OrderStatus); Reason: Failed to create query for method public abstract java.util.List wanted.market.api.domain.orders.repository.OrderRepository.findAllByProductUserIdAndStatus(java.lang.Long,wanted.market.api.domain.orders.enums.OrderStatus); Could not resolve attribute 'userId' of 'wanted.market.api.domain.product.entity.Product'
at org.springframework.data.repository.query.QueryCreationException.create(QueryCreationException.java:101) ~[spring-data-commons-3.3.0.jar:3.3.0]
at org.springframework.data.repository.core.support.QueryExecutorMethodInterceptor.lookupQuery(QueryExecutorMethodInterceptor.java:115) ~[spring-data-commons-3.3.0.jar:3.3.0]
at org.springframework.data.repository.core.support.QueryExecutorMethodInterceptor.mapMethodsToQuery(QueryExecutorMethodInterceptor.java:99) ~[spring-data-commons-3.3.0.jar:3.3.0]
at org.springframework.data.repository.core.support.QueryExecutorMethodInterceptor.lambda$new$0(QueryExecutorMethodInterceptor.java:88) ~[spring-data-commons-3.3.0.jar:3.3.0]
at java.base/java.util.Optional.map(Optional.java:260) ~[na:na]
at org.springframework.data.repository.core.support.QueryExecutorMethodInterceptor.<init>(QueryExecutorMethodInterceptor.java:88) ~[spring-data-commons-3.3.0.jar:3.3.0]
at org.springframework.data.repository.core.support.RepositoryFactorySupport.getRepository(RepositoryFactorySupport.java:357) ~[spring-data-commons-3.3.0.jar:3.3.0]
at org.springframework.data.repository.core.support.RepositoryFactoryBeanSupport.lambda$afterPropertiesSet$5(RepositoryFactoryBeanSupport.java:286) ~[spring-data-commons-3.3.0.jar:3.3.0]
at org.springframework.data.util.Lazy.getNullable(Lazy.java:135) ~[spring-data-commons-3.3.0.jar:3.3.0]
at org.springframework.data.util.Lazy.get(Lazy.java:113) ~[spring-data-commons-3.3.0.jar:3.3.0]
at org.springframework.data.repository.core.support.RepositoryFactoryBeanSupport.afterPropertiesSet(RepositoryFactoryBeanSupport.java:292) ~[spring-data-commons-3.3.0.jar:3.3.0]
at org.springframework.data.jpa.repository.support.JpaRepositoryFactoryBean.afterPropertiesSet(JpaRepositoryFactoryBean.java:132) ~[spring-data-jpa-3.3.0.jar:3.3.0]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1835) ~[spring-beans-6.1.8.jar:6.1.8]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1784) ~[spring-beans-6.1.8.jar:6.1.8]
... 44 common frames omitted
원인은 OrderRepository의 JPA구문 중 findBy~ProductUserId~ 에서 Product의 userId를 찾을 수 없기 때문이라고 한다.
JPA 구문을 내부적으로 변환하는 과정에서 기본 getter가 쓰이는데, getUserId를 custom으로 정의해서 발생하는 오류인 것으로 확인했다.
해결 방법
해당 캡슐화 메서드명을 get~이 아닌 다른 이름으로 설정하여 해결할 수 있다.
ex)
public class Product{
private User user;
//etc
public Long findUserId(){
return this.user.getId();
}
}
혹은 getUserId가 아닌
getProductUserId 등 내부적으로 사용하는 이름을 피해서 메서드명을 작성해주면 정상적으로 작동한다!
반응형