인프런 커뮤니티 질문&답변

yul9910님의 프로필 이미지
yul9910

작성한 질문수

자바와 스프링 부트로 생애 최초 서버 만들기, 누구나 쉽게 개발부터 배포까지! [서버 개발 올인원 패키지]

31강. 대출 기능 개발하기

31강 오류 질문있습니다!ㅠㅠ

작성

·

552

1

2023-07-12 01:18:17.448 ERROR 27420 --- [nio-8080-exec-2] o.a.c.c.C.[.[.[/].[dispatcherServlet]    : Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed; nested exception is java.lang.IllegalArgumentException] with root cause

java.lang.IllegalArgumentException: null
	at java.base/java.util.Optional.orElseThrow(Optional.java:408) ~[na:na]
	at com.group.libraryapp.service.book.BookService.loanBook(BookService.java:38) ~[main/:na]
	at com.group.libraryapp.service.book.BookService$$FastClassBySpringCGLIB$$9fdbff4c.invoke(<generated>) ~[main/:na]
	at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:218) ~[spring-core-5.3.24.jar:5.3.24]
	at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:793) ~[spring-aop-5.3.24.jar:5.3.24]
	at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:163) ~[spring-aop-5.3.24.jar:5.3.24]
	at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:763) ~[spring-aop-5.3.24.jar:5.3.24]
	at org.springframework.transaction.interceptor.TransactionInterceptor$1.proceedWithInvocation(TransactionInterceptor.java:123) ~[spring-tx-5.3.24.jar:5.3.24]
	at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:388) ~[spring-tx-5.3.24.jar:5.3.24]
	at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:119) ~[spring-tx-5.3.24.jar:5.3.24]
	at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) ~[spring-aop-5.3.24.jar:5.3.24]
	at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:763) ~[spring-aop-5.3.24.jar:5.3.24]
	at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:708) ~[spring-aop-5.3.24.jar:5.3.24]
	at com.group.libraryapp.service.book.BookService$$EnhancerBySpringCGLIB$$5e9f8aa4.loanBook(<generated>) ~[main/:na]
	at com.group.libraryapp.controller.book.BookController.loanBook(BookController.java:27) ~[main/:na]
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:na]
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:na]
	at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:na]
	at java.base/java.lang.reflect.Method.invoke(Method.java:566) ~[na:na]
	at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:205) ~[spring-web-5.3.24.jar:5.3.24]
	at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:150) ~[spring-web-5.3.24.jar:5.3.24]
	at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:117) ~[spring-webmvc-5.3.24.jar:5.3.24]
	at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:895) ~[spring-webmvc-5.3.24.jar:5.3.24]
	at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:808) ~[spring-webmvc-5.3.24.jar:5.3.24]
	at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87) ~[spring-webmvc-5.3.24.jar:5.3.24]
	at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1071) ~[spring-webmvc-5.3.24.jar:5.3.24]
	at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:964) ~[spring-webmvc-5.3.24.jar:5.3.24]
	at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1006) ~[spring-webmvc-5.3.24.jar:5.3.24]
	at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:909) ~[spring-webmvc-5.3.24.jar:5.3.24]
	at javax.servlet.http.HttpServlet.service(HttpServlet.java:696) ~[tomcat-embed-core-9.0.69.jar:4.0.FR]
	at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:883) ~[spring-webmvc-5.3.24.jar:5.3.24]
	at javax.servlet.http.HttpServlet.service(HttpServlet.java:779) ~[tomcat-embed-core-9.0.69.jar:4.0.FR]
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:227) ~[tomcat-embed-core-9.0.69.jar:9.0.69]
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162) ~[tomcat-embed-core-9.0.69.jar:9.0.69]
	at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53) ~[tomcat-embed-websocket-9.0.69.jar:9.0.69]
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189) ~[tomcat-embed-core-9.0.69.jar:9.0.69]
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162) ~[tomcat-embed-core-9.0.69.jar:9.0.69]
	at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:100) ~[spring-web-5.3.24.jar:5.3.24]
	at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:117) ~[spring-web-5.3.24.jar:5.3.24]
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189) ~[tomcat-embed-core-9.0.69.jar:9.0.69]
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162) ~[tomcat-embed-core-9.0.69.jar:9.0.69]
	at org.springframework.web.filter.FormContentFilter.doFilterInternal(FormContentFilter.java:93) ~[spring-web-5.3.24.jar:5.3.24]
	at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:117) ~[spring-web-5.3.24.jar:5.3.24]
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189) ~[tomcat-embed-core-9.0.69.jar:9.0.69]
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162) ~[tomcat-embed-core-9.0.69.jar:9.0.69]
	at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:201) ~[spring-web-5.3.24.jar:5.3.24]
	at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:117) ~[spring-web-5.3.24.jar:5.3.24]
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189) ~[tomcat-embed-core-9.0.69.jar:9.0.69]
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162) ~[tomcat-embed-core-9.0.69.jar:9.0.69]
	at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:177) ~[tomcat-embed-core-9.0.69.jar:9.0.69]
	at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:97) ~[tomcat-embed-core-9.0.69.jar:9.0.69]
	at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:541) ~[tomcat-embed-core-9.0.69.jar:9.0.69]
	at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:135) ~[tomcat-embed-core-9.0.69.jar:9.0.69]
	at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:92) ~[tomcat-embed-core-9.0.69.jar:9.0.69]
	at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:78) ~[tomcat-embed-core-9.0.69.jar:9.0.69]
	at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:360) ~[tomcat-embed-core-9.0.69.jar:9.0.69]
	at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:399) ~[tomcat-embed-core-9.0.69.jar:9.0.69]
	at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:65) ~[tomcat-embed-core-9.0.69.jar:9.0.69]
	at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:891) ~[tomcat-embed-core-9.0.69.jar:9.0.69]
	at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1784) ~[tomcat-embed-core-9.0.69.jar:9.0.69]
	at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49) ~[tomcat-embed-core-9.0.69.jar:9.0.69]
	at org.apache.tomcat.util.threads.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1191) ~[tomcat-embed-core-9.0.69.jar:9.0.69]
	at org.apache.tomcat.util.threads.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:659) ~[tomcat-embed-core-9.0.69.jar:9.0.69]
	at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61) ~[tomcat-embed-core-9.0.69.jar:9.0.69]
	at java.base/java.lang.Thread.run(Thread.java:829) ~[na:na]

안녕하세요! 강의 항상 잘 듣고있습니다! 다름이 아니라 31강수업을 듣다가 오류가 발생했는데 도저히 대출기능이 구현이 안되어서 여쭤봅니다! 살펴보니까 null 때문에 이 오류가 뜨는 것 같은데 DB에 맞는 데이터가 있는 상태에도 계속 뜹니다!ㅠ어디가 잘못 된 것 일까요?ㅠㅠ 코드는 깃허브에 올려놨습니다!(yul9910)

 

답변 1

1

최태현님의 프로필 이미지
최태현
지식공유자

안녕하세요, yul9910님!! 질문 올려주셔서 감사드립니다~~!! 😊

github의 코드까지 확인해본 결과 코드상 문제는 없는 것 같습니다!!

 

때문에, 보내주신 에러가 왜 발생했는지, 어떻게 디버깅할 수 있는지 설명드려보겠습니다!

java.lang.IllegalArgumentException: null
	at java.base/java.util.Optional.orElseThrow(Optional.java:408) ~[na:na]
	at com.group.libraryapp.service.book.BookService.loanBook(BookService.java:38) ~[main/:na]
	at com.group.libraryapp.service.book.BookService$$FastClassBySpringCGLIB$$9fdbff4c.invoke(<generated>) ~[main/:na]
	at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:218) ~[spring-core-5.3.24.jar:5.3.24]

보내주신 에러의 앞 부분만 가져왔습니다!

 

에러가 발생하게 되면, 가장 위에 어디에서 어떤 에러가 발생했는지 나오고, 아래로 갈수록 보다 근본적인 원인을 확인할 수 있는데요! 이 경우는 윗 부분으로도 충분히 상황 파악이 가능합니다.

 

위의 에러를 가장 위에서부터 읽어가다 보시면, 3번째 줄

at com.group.libraryapp.service.book.BookService.loanBook(BookService.java:38) ~[main/:na]

을 확인할 수 있는데요! 현재 에러는 BookService.java 코드의 38번째 줄에서 발생했다는 의미이고,

 

1~2번째 줄의 의미는 우리가 사용한 orElseThrow 에서 IllegalArgumentException 에러가 발생했다는 의미입니다.

java.lang.IllegalArgumentException: null
	at java.base/java.util.Optional.orElseThrow(Optional.java:408) ~[na:na]

 

우리가 작성한 38번째 줄 코드는

Book book = bookRepository.findByName(request.getBookName())
    .orElseThrow(IllegalArgumentException::new);

위와 같이 생겼고, 따라서 주어진 이름으로 책을 찾으려 했으나 책이 없어 에러가 발생하게 되었다고 생각할 수 있겠네요!!

 

하지만 분명 겉보기에는 library.book 데이터베이스에 "클린 코드"가 잘 들어 있고, 책 이름 역시 "클린 코드"로 대출 요청이 잘 이루어지고 있습니다.

 

이럴 때는 디버깅 도구 (https://www.youtube.com/watch?v=OHrLRg150As) 를 활용하셔서 BookLoanRequest의 bookName 필드에 어떤 값이 있는지, 혹시나 "클린 코드"가 아니라 " 클린 코드" 라거나 "클린 코드 " 같이 미세하게 다른 부분이 있는건 아닌지 확인해보는 것이 제일 좋습니다.

 

디버깅 도구가 어려우시다면, 아래 코드와 같이 직접 출력해보시는 것도 괜찮습니다.

@Transactional
public void loanBook(BookLoanRequest request) {
  System.out.println(request.getBookName()); // 출력 추가!

  // 1. 책 정보 가져오기
  Book book = bookRepository.findByName(request.getBookName())
      .orElseThrow(IllegalArgumentException::new);

 

또한, 들어오는 bookName의 이름도 확인했다면, 서버에서 Book을 정말 잘 찾고 있는지 확인해보는 것도 좋습니다. 예를 들어,

@Transactional
public void loanBook(BookLoanRequest request) {
  System.out.println(request.getBookName()); // 출력 추가!
  // 잠시 디버깅용
  List<Book> books = bookRepository.findAll();
  // Book을 하나씩 출력해서 확인해보기!

  // 1. 책 정보 가져오기
  Book book = bookRepository.findByName(request.getBookName())
      .orElseThrow(IllegalArgumentException::new);

위의 코드처럼 Book을 가져와 이름이나 정보들을 출력해보며 매치되지 않은 원인을 파악해보는 것이죠. 이 역시 디버거 툴을 활용하실 수도 있습니다.

 

한 줄 요약 드려보면, 1) 데이터도 있고~ 2) 코드도 틀린 부분이 없어~ 실제 로그를 찍어보며 엄밀하게 비교해보아야 알 수 있을 것 같습니다!

답변이 도움이 되어 꼭 해결하셨으면 좋겠습니다!!!

감사합니다!!! 🙏🙏

yul9910님의 프로필 이미지
yul9910

작성한 질문수

질문하기