자바는 에러가 발생하면 메소드 콜 스택 트레이스와 함께 Exception이 던진 메시지를 출력해 줍니다. 이런 장치를 활용해서 자바 기반의 여러 라이브러리나 프레임워크도 꽤나 유용한 정보를 제공하고 있죠.

Error starting ApplicationContext. To display the conditions report re-run your application with 'debug' enabled.

2020-08-14 22:06:13.208 ERROR 10285 --- [           main] o.s.boot.SpringApplication               : Application run failed

org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'accountRepository': FactoryBean threw exception on object creation; nested exception is java.lang.IllegalArgumentException: Failed to create query for method public abstract java.util.Optional me.g1moon.springbootsecurity2.account.AccountRepository.findByUserName(java.lang.String)! No property userName found for type Account! Did you mean 'username'?

 at org.springframework.beans.factory.support.FactoryBeanRegistrySupport.doGetObjectFromFactoryBean(FactoryBeanRegistrySupport.java:176) ~[spring-beans-5.2.8.RELEASE.jar:5.2.8.RELEASE]

 at org.springframework.beans.factory.support.FactoryBeanRegistrySupport.getObjectFromFactoryBean(FactoryBeanRegistrySupport.java:101) ~[spring-beans-5.2.8.RELEASE.jar:5.2.8.RELEASE]

 at org.springframework.beans.factory.support.AbstractBeanFactory.getObjectForBeanInstance(AbstractBeanFactory.java:1827) ~[spring-beans-5.2.8.RELEASE.jar:5.2.8.RELEASE]

 at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.getObjectForBeanInstance(AbstractAutowireCapableBeanFactory.java:1265) ~[spring-beans-5.2.8.RELEASE.jar:5.2.8.RELEASE]

... (중략) ...

 at org.springframework.data.repository.query.parser.PartTree.<init>(PartTree.java:97) ~[spring-data-commons-2.3.3.RELEASE.jar:2.3.3.RELEASE]

 at org.springframework.data.jpa.repository.query.PartTreeJpaQuery.<init>(PartTreeJpaQuery.java:89) ~[spring-data-jpa-2.3.3.RELEASE.jar:2.3.3.RELEASE]

 ... 49 common frames omitted

Process finished with exit code 1

스프링 부트 개념과 활용 강좌 수강생 중 한분께서 위와 같은 에러가 발생했는데 이유를 모르겠다고 질문을 보내왔습니다.

스프링 부트 개념과 활용 - 인프런
스프링 부트의 원리 및 여러 기능을 코딩을 통해 쉽게 이해하고 보다 적극적으로 사용할 수 있는 방법을 학습합니다.

초보적인 개발자는 이런 기다란 에러 메시지를 만나면 당황하고 에러 메시지를 읽지도 않고  '아 이거 왜 안돼지?'라고 상상속으로 빠져들며 에러 원인을 추측하기 시작합니다.

단서는 에러 메시지에 있습니다.

우선 저런 메시지를 읽을 때는 덩어리 중에서 일부를 거르고 진짜 필요한 부분만 찾아보면 됩니다. 일단 메소드 콜 스택 즉 어디서 어떤 메소드를 호출하고 또 거기서는 어떤 메소드를 호출했는지 쭉~~ 나와있습니다. at 으로 시작하고 있죠. 가량 A.a() 메소드에서 B.b()를 호출하다 에러가 났다면 보통 이런식으로 쌓여있습니다.

at B.b()
at A.a()

스택에서 제일 위에있는 메소드에서 에러를 던진거죠. 그 아래있는 메소드들은 최상단에 있는 메소드를 실행하기까지 거쳐온 메소드들 목록이구요.  그리고 그 최상단 스택 바로 위에 어떤 Exception이 발생했으며 그당시 발생한 에러메시지가 있습니다.

org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'accountRepository': FactoryBean threw exception on object creation; nested exception is java.lang.IllegalArgumentException: Failed to create query for method public abstract java.util.Optional me.g1moon.springbootsecurity2.account.AccountRepository.findByUserName(java.lang.String)! No property userName found for type Account! Did you mean 'username'?

지금 보고 있는 에러 로그에서는 BeanCreationException이 발생했고 즉 빈을 만들다가 에러가 발생했고, 빈을 만들다 에러가 발생한 이유는 IllegalArgumentException이 발생했기 때문인데, 이 에러는 다시 public abstract Optional findByUserName(String)이라는 메소드에 대한 쿼리를 만들다가 실패했기 때문이라 적혀있습니다. 마지막에 보면 AccountuserName이라는 프로퍼티는 없는데 혹시 username을 사용하려던건 아니냐고 까지 적혀있네요.

findByUsername으로 메소드 이름만 교체하면 해당 메소드 이름으로 쿼리가 잘 생성되고 문제는 해결되겠죠. 하지만, 제가 그렇게 답을 알려드린다 한들 에러 메시지를 읽지 않는 나쁜 습관을 고치지 않는다면 장기적으로 무슨 소용이 있을까요?

에러 메시지는 읽으라고 있는 겁니다. 제발 읽으세요.