문제 발견

이전 글에서 @ConfigurationProperties를 써서 yml 파일에서 환경 변수 값을 불러왔다.

간만에 백엔드 프로젝트를 만들면서 적용을 하니 아래와 같은 에러 메시지와 함께 애플리케이션을 실행할 수 없었다.


문제 해결

해결을 위해 검색을 해본 결과 인프런의 영한님이 답변을 남겨주신게 있었다. 

문제는 본인이 주로 쓰던 빌드 방식인 인텔리제이 IDEA 빌드 방식에 있었다.

스프링을 처음 공부하면서 이렇게 하면 속도 측면에서 이득을 볼 수 있다고 해서 쭉 써오던 방식이었다.

 

전에 썼던 버전은 스프링부트 2점대 버전이라서 문제 없이 동작했었다.

하지만 스프링부트 3.2버전부터는 매개변수 이름 추론 방식이 바껴서 설정을 변경해야 했다.

링크를 확인하면 몇 가지 방법이 있지만 가장 간단한건 아래처럼 빌드 방식을 gradle로 바꾸는것이다.

 

이렇게 바꾸고 실행해주면 문제 없이 동작한다.

 

출처)

 

현재 SpringBoot 3.2.1 부터 @ConfigurationProperties 를 사용한 설정값 바인딩에 이슈가 있는것 같습니다. -

안녕하세요! 질문 내용은 제목과 같습니다. 스프링부트 3.2.1 부터 @ConfigurationProperties 가 동작하지 않는것 같습니다. 확실하지 않지만 스텍오버플로우에도 비슷한 이슈가 올라온 상태인것 같습니

www.inflearn.com

 

문제 발

이전 글에서 @ConfigurationProperties 과 @ConstructorBinding 를 이용하여 yml 파일에서 환경변수를 불러왔었다.

동일한 방식으로 적용하려 하니 아래와 같이 빨간줄이 뜨면서 문제가 발생했다.


문제 해결

스프링부트 3.0 이상 버전으로 오면서 바뀐 부분 때문에 발생한 에러였다.

저 글을 쓸 당시 불변성을 보장하기 위해 생성자로 바인딩하기 위해 해당 애노테이션을 사용했었다.

하지만 스프링부트 3.0 이상에서는 @ConfigurationProperties 애노테이션을 사용할 때

생성자로 바인딩하기 위해 @ConstructorBinding 을 표기할 필요가 없어졌다.

따라서 Configuration 클래스에 여러 생성자가 있는 경우가 아니면 제거해야한다.

 

위 처럼 @ConstructorBinding 을 제거하고 실행해도 문제 없이 동작한다.

 

출처)

 

[SpringBoot 3.0] SpringBoot 3.0 버전 업그레이드 방법

SpringBoot 3.0 1년이 넘는 기간동안 151명의 개발자들이 5700자 이상의 코드 커밋을 통해 마침내 스프링부트 3.0이 릴리즈 되었습니다. 스프링부트 2.0이 릴리즈 된 이후 4년 반만에 릴리즈 된 스프링

mein-figur.tistory.com

 

문제 발견

아래와 같이 로그인/회원가입 구현 중 JWT를 발급하기 위해 시크릿 키를 만들던 도중 발생하였다.

@RequiredArgsConstructor
@ConfigurationProperties(prefix = "midcon")
public class AppConfig {

    private final String jwtKey;

    public SecretKey getSecretKey() {
        byte[] byteJwtKey = Decoders.BASE64.decode(this.jwtKey);
        return Keys.hmacShaKeyFor(byteJwtKey);
    }
}

 

분명 이 글을 쓰던 시점에서는 잘 됐으나 시크릿 키를 만드는 로직의 위치만 옮겼을 뿐인데 오류가 발생하였다.


문제 해결

결론부터 말하자면 예상 외로 라이브러리 버전 문제였다.

호돌맨님 인강을 보며 만들때는 문제가 없었지만 지금은 바뀐 조건이 많아서 뭐가 문제인지 확인하기 어렵다.

대충 생각 나는 원인은 아래 세 개 정도였다.

  • 로직 위치를 바꾼게 문제인지
  • 스프링부트 버전을 2.7대에서 3.2대로 올린게 문제인지
  • 자바 버전을 11에서 21로 올린게 문제인지

위 조건으로 로그를 찍어보면서 원인을 찾아봤지만 실패했다.

그래서 에러 메시지를 검색해보았고, 한 stackoverflow 글을 발견했다.

위 글을 참고하여 jwt 라이브러리를 0.12.1 버전으로 올리니 해결되었다.

검색을 잘 하자...

 

문제 발견

배포를 위해 AWS EC2 인스턴스를 생성하고 스프링부트를 띄우려고 로컬에서 EC2로 빌드 파일을 전송하려던 중

아래 사진과 같은 에러를 만났다.

사실 인텔리제이에서 애플리케이션을 실행할때도 봤던 문제긴 하지만 그때는 인텔리제이 설정으로 해결이 되었다.

하지만 이런 CLI에서는 인텔리제이 설정을 할 수 없어서 다른 방법을 찾아야했다.


문제 해결

에러 메시지를 읽어보면 자바 버전 문제라는것을 알 수 있었지만 해결 방법을 몰랐다.

결과부터 말하자면 시스템 환경 변수 설정에 classpath가 최신화 되지 않은 문제였다.

시도 해본 방법은 아래와 같다.

1. build.gradle 확인

에러 메시지에도 나오는 단어기도 하고 검색 해보면 sourceCompatibility를 확인 변경해주래서 확인해보았다.

하지만 build.gradle 파일에는 아래처럼 제대로 잘 적혀있었다.

2. 로컬의 자바 버전 확인

로컬에 깔린 자바 버전 문제일까 싶어서 확인해보니 자바 17버전으로 나왔다.

3. 시스템 환경 변수 확인

최종적으로  시스템 환경변수 설정 문제였다.

아득한 옛날 뭣도 모르고 인터넷 검색해서 자바 환경 변수 설정을 했던 적이 있었다.

당시엔 자바 11로 설치하고 환경 변수 설정을 했었다.

변경 전

변경 후

 

시스템 환경 변수 설정에서 JAVA_HOME을 원하는 자바 버전으로 변경한 후

CLI(본인은 Git Bash)를 다시 실행! 하고 빌드를 해보면 제대로 잘 동작한다.

문제 발견

호돌맨님의 강의 중 검증 파트에서 발생한 오류이다.

 

PostController

 

PostCreate

 

PostControllerTest

글 작성 요청 시 제목, 내용 모두 null 인 케이스 테스트이다.

 

 

이 테스트에서 실패하며 아래와 같은 로그가 출력된다.

 

 

응답 바디에도 아무것도 오지 않는다.

 

로그를 쫓아서 ErrorResponse 에 브레이크 포인트를 찍어보았다.

 

ErrorResponse

여기서 validation 이 null로 잡힌다.

 

 

PostControllerAdvice

처음 ExceptionHandler 에서 생성자에 validation 을 매개변수로 받지 않았을땐 오류가 발생하지 않았는데

validation 을 매개변수로 받고 나서 오류가 생겼다.

 

 

@Builder 를 이용한 생성자가 ErrorResponse 의 validation 초기화를 무시하고 null 값으로 넣어버리는 현상이라고 생각된다.

 

 

그래서 따로 빌더 안붙인 validation 을 받지 않는 생성자를 만드니 잘 돌아간다.

 

 


문제 해결

강의 따라서 코드 치는 사이에 잠깐 놓쳐서 발생했던 문제였다.

하지만 원인은 예상했던대로 @Builder 를 이용한 생성자가 validation 의 초기화를 무시하고 null 로 넣은것이었다.

기존 코드에서는 아래처럼 validation 을 초기화를 해줘도 빌더 생성 시 validation 이 null 이면 null 값이 들어가게된다.

변경 전

ErrorResponse

public class ErrorResponse {

    // ...
    private Map<String, String> validation = new HashMap<>();
}

 

따라서 아래처럼 validation 이 null 인지 확인하는 로직을 작성해야 한다.

 

변경 후

ErrorResponse

@Getter
public class ErrorResponse {

    private final String code;
    private final String message;
    private final Map<String, String> validation;

    @Builder
    public ErrorResponse(String code, String message, Map<String, String> validation) {
        this.code = code;
        this.message = message;
        this.validation = validation != null ? validation : new HashMap<>();
    }

    public void addValidation(String fieldName, String errorMessage) {
        this.validation.put(fieldName, errorMessage);
    }
}

 

위처럼 ErrorResponse 를 바꿔주면 정상적으로 동작한다.

문제 발견

기존 QueryDsl 없이 NativeQuery 로 작성한 리포지토리 메서드를 리팩토링 하다가 발생한 에러이다.

@SpringBootTest 는 스프링을 띄워서 의존성 주입을 다 받기 때문에 상관없지만

리포지토리 테스트는 대부분 @DataJpaTest 를 사용하기 때문에 QueryDsl 관련 빈을 주입받지 못해 발생한 에러였다.

 


문제 해결

아래 두가지를 순서대로 따라하니 문제가 해결되었다.

 

1. QueryDslConfig 작성

QueryDslConfig

@Configuration
public class QueryDslConfig {

    @PersistenceContext
    public EntityManager em;

    @Bean
    public JPAQueryFactory jpaQueryFactory() {
        return new JPAQueryFactory(em);
    }
}

 

2. Test 에 @Import 추가

Test

@DataJpaTest
@Import(QueryDslConfig.class)
class ProductRepositoryTest {
...
}

 

 

참고자료)

 

No qualifying bean of type 'com.querydsl.jpa.impl.JPAQueryFactory' available: expected at least 1 bean which qualifies as autowi

JPA Config 파일 추가test에 @Import 추가

velog.io

 

 

@DataJpaTest - 인프런 | 질문 & 답변

QueryDsl 강의 잘듣고 있습니다!QueryDsl을 사용하면 @DataJpaTest를 사용하지 못하나요?JPAQueryFactory에 대해서 NoSuchBeanDefinitionException이 발생하는데 따로 주입하는 방법을 모르겠습니다ㅠㅠ - 질문 & 답변

www.inflearn.com

 

문제 발견

이 글처럼 설정 후 Q클래스가 생성된건 확인했지만 아래 사진처럼 Q클래스를 import 할 수 없었다.

 

 

generated 폴더에 Q클래스 파일이 제대로 추가되지 않아 발생한 문제였다.

 


문제 해결

기존 generated 폴더를 삭제하고 애플리케이션을 재실행하면 generated 폴더가 재생성 되면서 Q클래스 파일이 추가된다.

 

 

끝 !

+ Recent posts