돌맹이떼굴떼굴 2025. 2. 17. 20:59

1. 문제

2025-02-17T20:33:21.451+09:00  WARN 2680 --- [demo] [main] ConfigServletWebServerApplicationContext : 
Exception encountered during context initialization - cancelling refresh attempt: 
org.springframework.beans.factory.UnsatisfiedDependencyException: 
Error creating bean with name 'todoController': 
Unsatisfied dependency expressed through field 'service': 
Error creating bean with name 'todoService': 
Unsatisfied dependency expressed through field 'repository': 
Error creating bean with name 'todoRepository' defined in com.example.demo.repository.TodoRepository 
defined in @EnableJpaRepositories declared on JpaRepositoriesRegistrar.EnableJpaRepositoriesConfiguration: 

Could not create query for public abstract java.util.List com.example.demo.repository.TodoRepository.findByUserId(java.lang.String); 

Reason: Line 1:7 extraneous input '*' expecting {'(', '[', ':', '{', '?', ID, VERSION, ...}

spring을 실행시킨 후 해당 에러를 내뱉었는데, 위에서 가장 핵심이 되는 곳은

'Could not create query for public abstract java.util.List com.example.demo.repository.TodoRepository.findByUserId(java.lang.String);'

위 에러이다. findByUserId(String userId) 메서드가 잘못된 문법을 포함하고 있다는 것인데 책이라 그냥 써놓고 실행하니까 될 줄 알았는데 에러가 발생해서 당황했다.

 

TodoRepository -> TodoService -> TodoController 까지 연속적으로 에러가 엮이다 보니까 파악하기 힘들어서 chat gpt에게 부탁해서 아래에 써놓았다. 그리고 이클립스가 생각보다 Console에 출력되는 에러가 읽기 더 힘든 것 같다.

더보기

1. 오류 원인 분석

해당 에러 메시지를 단계별로 분석하면 다음과 같다.

  1. Spring Boot 애플리케이션 실행 중 ConfigServletWebServerApplicationContext가 초기화 실패
    • Exception encountered during context initialization - cancelling refresh attempt
    • 애플리케이션이 시작하는 과정에서 Bean을 제대로 생성하지 못해 실행이 중단됨.
  2. UnsatisfiedDependencyException (의존성 주입 실패)
    • Error creating bean with name 'todoController': Unsatisfied dependency expressed through field 'service'
    • TodoController의 todoService 필드에서 의존성을 주입하지 못함.
    즉, todoService가 제대로 생성되지 않음.
  3. 의존성 전달 문제 (todoService → todoRepository)
    • Error creating bean with name 'todoService': Unsatisfied dependency expressed through field 'repository'
    • todoService의 todoRepository 필드에서 의존성을 주입하지 못함.
    즉, todoRepository가 제대로 생성되지 않음.
  4. JPA Repository (todoRepository) 생성 실패
    • Error creating bean with name 'todoRepository'
    • Spring Data JPA에서 todoRepository를 인식하지 못함.
    즉, todoRepository가 정상적으로 등록되지 않음.
  5. 쿼리 메서드 오류 (findByUserId의 문법 문제)
    • Could not create query for public abstract java.util.List com.example.demo.repository.TodoRepository.findByUserId(java.lang.String);
    • findByUserId(String userId) 메서드가 잘못된 문법을 포함하고 있음.
    주된 문제는 findByUserId 쿼리 메서드의 문법 오류로 인해 todoRepository가 정상적으로 생성되지 않은 것
    → 결과적으로 todoService, todoController까지 연쇄적으로 영향을 받아 실행이 중단됨.
@Repository
public interface TodoRepository extends JpaRepository<TodoEntity, String> {
	// ?1은 메서드의 매개변수의 순서 위치이다.
	@Query("SELECT * FROM TODO t WHERE t.userID = ?1")
	List<TodoEntity> findByUserId(String userId);
}

내 스프링 부트 버전은 3.4.2이고 책이 쓰여진 스프링 버전은 2.5.0이다. chat gpt가 말하길 Spring 2.5.1은 2007년에 출시된 매우 오래된 버전으로 JPA 기능을 기본 제공하지 않아 위 코드가 동작하지 않았을 것이라는데,,, 우선 에러는 해결하고 나중에 책 한 번 더 돌릴 때 다시 봐야 겠다.

 

2. 문제 원인

@Query("SELECT * FROM TODO t WHERE t.userID = ?1")

위 JPQL(Query) 문법이 잘못되었기 때문에 발생했다.

1. JPQL 문법 오류

  • SELECT * FROM 구문은 JPQL에서 허용되지 않는다.
  • JPQL에서는 엔티티를 직접 선택해야 하며, 테이블 이름이 아니라 엔티티 클래스명을 사용해야 한다.

2. 엔티티 클래스명 사용

  • JPQL에서는 SQL과 다르게 테이블이 아니라 엔티티 이름을 사용해야 한다.
  • 엔티티 이름은 @Entity가 선언된 클래스명이며, 일반적으로 TodoEntity처럼 CamelCase 형태로 사용된다.

3. 필드명 문제

  • userID 필드가 TodoEntity에서 userId로 선언되어 있을 가능성이 높다.
  • JPQL에서는 엔티티 클래스의 필드명을 사용해야 한다. (DB 컬럼명이 아니라 필드명)

즉, * (wild card) 기호도 잘못되었고, TODO가 테이블 명이고 TodoEntity가 엔티티 명인데 이 부분도 잘못되었고 아무튼 위에 잘못된 부분이 한 가지가 아니다.

 

3. 문제 해결

@Repository
public interface TodoRepository extends JpaRepository<TodoEntity, String> {
    @Query("SELECT t FROM TodoEntity t WHERE t.userId = ?1")
    List<TodoEntity> findByUserId(String userId);
}

위와 같이 바꿔주니 잘 동작한다.