Everyday Dev System

스프링 오류 : Error creating bean with name 해결 본문

내배캠 주요 학습/TIL : Today I Learned

스프링 오류 : Error creating bean with name 해결

chaeyoung- 2023. 6. 15. 12:40

20230614 6:00pm - 20230615 4:00am

20230615 9:00am - 20230615 1:00pm


# 문제점 : 

Error creating bean with name 'postController' defined in file [D:\camp\springBasic\week1\myBlog\build\classes\java\main\com\sparta\myblog\controller\PostController.class]: Unsatisfied dependency expressed through constructor parameter 0: Error creating bean with name 'postService' defined in file [D:\camp\springBasic\week1\myBlog\build\classes\java\main\com\sparta\myblog\service\PostService.class]: Unsatisfied dependency expressed through constructor parameter 0: Error creating bean with name 'postRepository' defined in com.sparta.myblog.repository.PostRepository defined in @EnableJpaRepositories declared on JpaRepositoriesRegistrar.EnableJpaRepositoriesConfiguration: Could not create query for public abstract java.util.List co m.sparta.myblog.repository.PostRepository.findAllByOrderByCreate_dateDesc(); Reason: Failed to create query for method public abstract java.util.List co m.sparta.myblog.repository.PostRepository.findAllByOrderByCreate_dateDesc(); No property 'create' found for type 'Post'

 

 

# 시도 : 

 

1. PostService.java & PostController.java 멤버 변수 접근 제어자 변경

 ( public -> private )

@Service
public class PostService {

    public final PostRepository postRepository;

    public PostService(PostRepository postRepository) {
        this.postRepository = postRepository;
    }
}
@RequestMapping("/api")
@RestController
public class PostController {
    public final PostService postService;

    public PostController(PostService postService){
        this.postService = postService;
    }
}

Bean 등록을 위한 콩모양 아이콘은 보였으나, 해당 객체에 경고가 뜨며 활성화가 되지 않아서 접근제어자를 변경해주었다. 그러나 이렇게 해도 같은 오류가 발생했다. 생성자를 통해 주입해주기 때문에 접근제어자는 문제가 되지 않는 것으로 보인다. 다시 private으로 변경하고 다른 방법을 모색했다. 

 

 

 

 

2. application.properties 확인

- 스프링 부트 환경에서는 아래와 같이 정보를 추가하면 
이를 바탕으로 EntityManagerFactory, EntityManager를 자동 생성해줍니다.

server.port=8082

spring.datasource.url=jdbc:mysql://localhost:3307/post
spring.datasource.username=root
spring.datasource.password=1234
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver

spring.jpa.hibernate.ddl-auto=update

spring.jpa.properties.hibernate.show_sql=true
spring.jpa.properties.hibernate.format_sql=true
spring.jpa.properties.hibernate.use_sql_comments=true

 

spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver

위 코드 부분에서 Driver를 driver로 하면 오류가 생긴다고 해서 확인했으나 내 프로젝트에는 잘 설정되어 있다.

hibernate 설정도 잘 되어 있다.

 

 

** 참고 사항

spring.jpa.hibernate.ddl-auto=update 코드 옵션으로 아래 5개가 있다.

 -> create , create-drop , update , validate(entity와 table이 정상 맵핑 여부 확인) , none

 

 

참고로 아래 3줄은 아래 사진과 같이 콘솔창에서 SQL문을 보기 좋게 해주는 코드이다.

spring.jpa.properties.hibernate.show_sql=true
spring.jpa.properties.hibernate.format_sql=true
spring.jpa.properties.hibernate.use_sql_comments=true

 

 

 

 

 

 

3. build.gradle에 의존성 확인 및 재빌드

-jpa와 mysql 의존성이 잘 추가가 되어 있었다. 오류도 없었다.

 dependencies {
     implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
     implementation 'mysql:mysql-connector-java:8.0.28'

     implementation 'org.springframework.boot:spring-boot-starter-thymeleaf'
     implementation 'org.springframework.boot:spring-boot-starter-web'
     compileOnly 'org.projectlombok:lombok'
     annotationProcessor 'org.projectlombok:lombok'
     testImplementation 'org.springframework.boot:spring-boot-starter-test'
 }

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

unsatisfieddependencyexception at constructorresolver.java:800 외 12개의 오류 있음.

 

 

해당 오류는 무슨 오류인지 검색해보고 많이 시도해봤지만 해결 되지 않았다.

어노테이션도 잘 기재가 되어 있었으며, DB 칼럼도 잘 설정이 되어 있었고, @Id도 잘 설정해두었다.

알게 된 사실은 이것도 Bean 등록이 원활히 되지 않아서 build시에 생기는 오류라고 한다.

 

 

 

 

 

 

4. 어노테이션 기재 확인

@Service , @Controller  , @Repository 등 기재 확인

Service 클래스의 생성자 메서드 앞에 @Autowired도 기재하였다.

 

여기서 알아둬야 할 점은, 

생성자에 선언되어있는 @Autowried 어노테이션은 생성자가 한개만 있을 경우 생략이 가능하다.

PostService는 생성자 메서드가 1개만 있으므로, 생략해도 무관하다는 의미이다. 이 부분이 문제는 아니였다.

package com.sparta.myblog.repository;

import com.sparta.myblog.entity.Post;
import org.springframework.data.jpa.repository.JpaRepository;

import java.util.List;

public interface PostRepository extends JpaRepository<Post,Long> {
	-- 중략 --
}

PostRepository 인터페이스는 JpaRepository를 상속받아서 만들어졌다.

그런 후에 SimpleJpaRepository 구현체를 스프링부트에서 자체적으로 자동 생성해준다.

이때 SimpleJpaRepository 구현체 내에 @Repository 어노테이션이 기재되어 있으므로, 해당 인터페이스에 @Repository 어노테이션을 기재하지 않아도 되는 것이다.

 

 

 

 

 

5. Repository Query Method 수정

 

현재 문제점을 다시 생각해보았다..

Error creating bean with name 'postController' defined in file [D:\camp\springBasic\week1\myBlog\build\classes\java\main\com\sparta\myblog\controller\PostController.class]: Unsatisfied dependency expressed through constructor parameter 0: Error creating bean with name 'postService' defined in file [D:\camp\springBasic\week1\myBlog\build\classes\java\main\com\sparta\myblog\service\PostService.class]: Unsatisfied dependency expressed through constructor parameter 0: Error creating bean with name 'postRepository' defined in com.sparta.myblog.repository.PostRepository defined in @EnableJpaRepositories declared on JpaRepositoriesRegistrar.EnableJpaRepositoriesConfiguration: Could not create query for public abstract java.util.List co m.sparta.myblog.repository.PostRepository.findAllByOrderByCreate_dateDesc(); Reason: Failed to create query for method public abstract java.util.List co m.sparta.myblog.repository.PostRepository.findAllByOrderByCreate_dateDesc(); No property 'create' found for type 'Post'

 

 

오류를 잘 살펴보면 postController, postService, postRepository 모두 생성자 부분의 파라미터 전달에 오류가 있어서 생성이 안된다는 의미이다.

그렇다면 postController를 만들기 위해 postService Bean 등록이 필요하고,

postService Bean 등록을 위해 postRepository Bean 등록이 필요한 것인데

애초에 postRepository가 생성시 오류가 있어서 모두 생성이 안되는 것이 아닐까?

 

 

원인은 JpaRepository에서 빈을 등록해주는 과정에서 문제가 있는 것으로 보인다.

postRepository 인터페이스의 코드에 문제가 있어서.. 그렇지 않을까 다시 살펴보았다.

 

사실은 이 오류를 다시 생각해보기 이전에 postController, postService 코드, 메서드들 모두 하나하나 주석 처리를 하며 어느 부분이 오류인지 찾아보았지만 찾지 못했기 때문에 오류의 원인을
postRepository로 바라보게 된 이유가 크다.

 

 

package com.sparta.myblog.repository;

import com.sparta.myblog.entity.Post;
import org.springframework.data.jpa.repository.JpaRepository;

import java.util.List;

public interface PostRepository extends JpaRepository<Post,Long> {
    List<Post> findAllByOrderByCreate_dateDesc();
}

위 코드에 문제가 있는 것이 아닐까?

이전 프로젝트를 살펴보니 메모 프로젝트에서 Repository 내에 메서드엔 _(언더바)가 안들어갔다.

 

해당 메서드를 바꾸기 위해 아래와 같이 칼럼명을 변경했다.

create_date -> createAt
modify_date -> modifiedAt

 

PostResponseDto.java에서 멤버변수 명을 위와 같이 변경

Timestamped.java에서도 변경한 후에 Table을 drop했다.

 

 

그 후에  

List<Post> findAllByOrderByCreate_dateDesc(); 

위 코드를 아래와 같이 변경하고 실행해보았다.

List<Post> findAllByOrderByCreateAtDesc();

 

 

해결 완료!!!!!!!!

 

내게 너무 고된 시련을 준 오류가 해결됐다..

오류에게 감사하다.. 새벽을 갈아넣었지만 원인을 알게 됐으니 다시는 이런 실수를 하지 않을 것 같다.

다음과 같은 오류가 나면 정말 많은 방법을 하면서 외웠기 때문에 해결할 수 있을 것 같다.

이제 그 원인을 살펴보자.

 

 

 

 

 

#문제 해결 :

더보기
package com.sparta.myblog.entity;

import jakarta.persistence.*;
import lombok.Getter;
import org.springframework.data.annotation.CreatedDate;
import org.springframework.data.annotation.LastModifiedDate;
import org.springframework.data.jpa.domain.support.AuditingEntityListener;

import java.time.LocalDateTime;

@Getter
@MappedSuperclass
@EntityListeners(AuditingEntityListener.class)
public abstract class Timestamped {

    @CreatedDate
    @Column(updatable = false)
    @Temporal(TemporalType.TIMESTAMP)
    private LocalDateTime create_date;

    @LastModifiedDate
    @Column
    @Temporal(TemporalType.TIMESTAMP)
    private LocalDateTime modify_date;
}

위 코드를 아래와 같이 수정하면 된다.

package com.sparta.myblog.entity;

import jakarta.persistence.*;
import lombok.Getter;
import org.springframework.data.annotation.CreatedDate;
import org.springframework.data.annotation.LastModifiedDate;
import org.springframework.data.jpa.domain.support.AuditingEntityListener;

import java.time.LocalDateTime;

@Getter
@MappedSuperclass
@EntityListeners(AuditingEntityListener.class)
public abstract class Timestamped {

    @CreatedDate
    @Column(updatable = false)
    @Temporal(TemporalType.TIMESTAMP)
    private LocalDateTime createAt;

    @LastModifiedDate
    @Column
    @Temporal(TemporalType.TIMESTAMP)
    private LocalDateTime modifiedAt;
}

Repository Query Method 에 문제가 있었다. 

 

    private LocalDateTime created_date;
    private LocalDateTime modifie_date;

 

다음과 같이 칼럼명에 _(언더바)를 붙히면

Repository에서 findBy~로 매소드 이름을 지어도 인식이 안 되어 오류가 난다고 한다.

 

 

나는 create_date, modify_date로 명명하고 계속 Bean을 생성하려고 하니 오류로 인해 되지 않았던 것이였다.

package com.sparta.myblog.dto;

import com.sparta.myblog.entity.Post;
import lombok.Getter;

import java.time.LocalDateTime;

@Getter
public class PostResponseDto {

    private Long id;
    private String title;
    private String name;
    private String contents;
    private String password;
    private LocalDateTime created_date;
    private LocalDateTime modifie_date;
}

 

 

또한, hibernate 에서 제공하는 ImprovedNamingStrategy를 사용하면 CamelCase 표기법을 Underscore 표기법으로 변환한다. 테이블 이름의 언더바 자동 변경방지를 위해 Naming Strategy를 아래와 같이 변경해주면 된다.

 

application.properties

spring.jpa.hibernate.naming.implicit-strategy=org.hibernate.boot.model.naming.ImplicitNamingStrategyLegacyJpaImpl
spring.jpa.hibernate.naming.physical-strategy=org.hibernate.boot.model.naming.PhysicalNamingStrategyStandardImpl

 

 

쿼리 메서드를 사용시 변수명을 기준으로 작성이 되는데,

첫 글자 대문자는 불가능

중간에 "_" 언더바 같은 기호도 인식이 불가능

 

 

DB 테이블에 칼럼명을 이런 규칙을 어기면서 생성해야 하는 경우에는

아래와 같이 @Column(name = "First_Name") 어노테이션을 활용한다.

 

 

 

정리하자면, 칼럼명에 _가 들어갈 경우 Query Method에서 예약어로 인식하여 처리가 불가능하다.
그렇기 때문에 _를 제거하여 만드는 것이 해당 규칙을 준수하여 생성하는 것이다.

 

 

 

공식 문서를 살펴보며 자세한 설명은 아래 글에서 말씀드리겠습니다.

2023.06.15 - [내일배움캠프 공부/Spring 입문] - JPA 활용시 _(언더바)의 예약어 역할

 

JPA 활용시 _(언더바)의 예약어 역할

Spring Data JPA - Reference Documentation Spring Data JPA - Reference Documentation Example 121. Using @Transactional at query methods @Transactional(readOnly = true) interface UserRepository extends JpaRepository { List findByLastname(String lastname); @M

cdev.tistory.com

 

 

 


References

JPA Property Expressions 쿼리 생성시 참조타입 탐색 경로 지정하기 | 기록하기 (hongsii.github.io)

 

JPA Property Expressions 쿼리 생성시 참조타입 탐색 경로 지정하기

JPA Property Expressions으로 쿼리 생성시 참조타입 탐색 경로 지정하기

hongsii.github.io

Spring Data JPA repository methods don't recognize property names with underscores - Stack Overflow

 

Spring Data JPA repository methods don't recognize property names with underscores

I have underscores in the entity property names, and when Spring tries to create the JPA repository implementation, it results in an exception trying to resolve the name of the property. Entity: @

stackoverflow.com

언더바(_)가 있는 컬럼명 인식 불가 문제 (tistory.com)

 

언더바(_)가 있는 컬럼명 인식 불가 문제

언더바(_)가 있는 컬럼명 인식 불가 문제 @Entity @Data @Table(name= "service_info") @Accessors(chain = true) public class ServiceInfoVO { @Id int n_service_index; String service_name; String service_code; String service_detail; String level; }

sunpil.tistory.com

 

[SpringBoot] JPA 카멜케이스 컬럼명 적용법 — Back world (tistory.com)

 

[SpringBoot] JPA 카멜케이스 컬럼명 적용법

JPA 와 MySQL 을 연동하여 사용하는 경우, 카멜표기법으로 컬럼 이름을 지정할 시에 컬럼명이 helloData -> hello_data 와 같은 형태로 자동 변경되어 버리는 문제가 발생한다. (카멜 표기법이란 각 단어

pgmjun.tistory.com