본문 바로가기
  • 개발하는 곰돌이

java38

[Gradle] 순수 자바/코틀린 Gradle 프로젝트를 실행 가능한 jar 파일로 빌드하기 목차 들어가기 전에 종종 스프링부트를 사용하지 않은 간단한 순수 자바/코틀린 프로젝트를 빌드해서 실행할 일이 있다. 스프링부트를 사용하지 않는 경우에는 bootJar 명령이 없어서 jar 명령으로 빌드할 수밖에 없는데 이렇게 생성된 jar 파일은 java -jar 명령어로 실행해도 제대로 실행되지 않는다. 이러한 현상이 발생하는 이유와 해결법을 정리해두고자 한다. 왜 gradle jar로 생성한 jar 파일은 실행되지 않을까? 기본적으로 Gradle의 jar 명령은 프로젝트의 소스 파일들을 컴파일한 후 jar 파일의 형태로 압축한다. 그리고 이 과정에서 MANIFEST.MF 파일이 생성되어 jar 파일에 추가된다. 터미널에 jar tf {jar 파일명}을 입력하면 jar 파일의 내부 구조를 확인해볼 수 .. 2023. 11. 28.
[Java] UnmodifiableList는 진짜 불변 리스트가 아니다 목차 들어가기 전에 불변성이 강조되는 객체지향 프로그래밍의 특성상 자바에서도 UnmodifiableList라는 클래스가 존재한다(물론 List 뿐만 아니라 Map과 Set도 존재한다). UnmodifiableList라는 이름에 걸맞게 add(), set(), remove() 등 리스트의 내부가 변경되는 메소드를 사용하면 바로 예외가 터져버린다. 그런데 이 UnmodifiableList는 불변성을 보장하는 진짜 불변 리스트가 아니다. 이에 대해 알아보자. 이하의 모든 내용은 Map과 Set에도 동일하게 적용된다. UnmodifiableList 객체 선언 UnmodifiableList 객체는 다음과 같이 Collection.unmodifiableList()를 사용하여 선언할 수 있다. List unmodif.. 2023. 8. 15.
[JWT] Access Token의 한계와 Refresh Token의 필요성 [수정사항] 2023-08-20 : 자바 코드의 TokenProvider 클래스에서 리프레시 토큰이 일치하는지 검사하는 메소드가 누락된 부분 수정 목차 들어가기 전에 이전에 스프링 시큐리티와 JWT를 이용한 사용자 인증을 구현한 프로젝트에 대한 글에서 리프레시 토큰을 언급한 적이 있다. 그래서 리프레시 토큰에 대해 다뤄보면서 기존에 JWT로 사용자를 검증하던 프로젝트에 리프레시 토큰을 적용해보려고 한다. 다만 리프레시 토큰의 구현 방법에 대해 깊게 이해하고 있는 것이 아니기 때문에 틀린 내용이 있을 수 있다. Access Token? Refresh Token? 액세스 토큰은 사용자에 대한 정보를 담고 있어서 서비스에 접근(Access)할 수 있는 토큰을 의미한다. 이전 예제 프로젝트에서 사용자 검증을 위.. 2023. 7. 19.
[Spring] WebClient로 외부 API를 호출하여 받은 JSON을 객체로 역직렬화할 때 대문자 필드가 바인딩되지 않는 문제 문제의 배경 기존에 WebClient로 외부 API를 호출하여 받은 JSON을 Gson 라이브러리를 통해 JsonObject로 받아서 사용하고 있던 것을 좀 더 객체지향스럽게(?) 변경하기 위해 자바 객체로 받아서 처리하도록 리팩토링하는 작업을 하고 있었다. 아래는 API의 응답으로 받는 JSON과 기존에 JSON을 JsonObject로 받아서 사용하던 코드의 일부이다. { "status": "success", "error": null, "listData": [ { "CLIENT_CODE": "123456", "DATE": "2023-06-01", "AMOUNT": 12345 }, ... ] } public Mono apiResponse(Map params) { MultiValueMap formData .. 2023. 6. 29.
[Java] Java 14부터 추가된 Record 타입과 Kotlin의 Data Class 비교 목차 들어가기 전에 자바 14부터 코틀린의 Data 클래스와 유사한 Record라는 클래스가 추가되어 자바 16에서 정식으로 지원되기 시작했다. 그동안 자바에서 DTO 등의 클래스를 만들 때는 Lombok의 도움을 받아 @Data 어노테이션을 붙이는 경우가 많았지만 Record 클래스가 추가되어 이러한 필요성이 줄어들게 되었다. 하지만 자바의 Record 클래스와 코틀린의 Data 클래스는 비슷하지만 다른 점이 있다. 이에 대해 정리해본다. Record 클래스의 기본 구조와 사용법 Record 클래스는 아래와 같은 구조로 선언된다. public record Member( String account, String name, int age ) { ... } 클래스 명 뒤에 소괄호로 메소드의 파라미터를 지정하.. 2023. 6. 14.
[OOP] Getter와 Setter는 지양하는게 좋다 목차 들어가기 전에 얼마 전 사내에서 Getter와 Setter를 함부로 사용하면 안되는 이유에 대한 세미나가 있었다. Setter에 대한 이야기는 워낙 많이 알려져있었지만 Getter에 대한 이야기는 잘 하지 않다보니 꽤 흥미로운 주제였다. 그렇다면 왜 Getter와 Setter를 함부로 사용하면 안될까? 이 이유를 한 번 알아보자. Getter와 Setter를 사용하는 이유 객체 지향의 원칙 중 하나는 정보 은닉(Information Hiding)이다. 객체의 구체적인 정보를 외부에 노출하지 말라는 것이다. 이러한 이유 때문에 자바에서는 클래스를 작성할 때 모든 필드를 private으로 숨기고 public 메소드를 통해 간접적으로 필드를 다루게 된다. 코틀린의 경우에는 프로퍼티를 private으로 숨.. 2023. 6. 7.
[WebClient] Mono에 담긴 List를 하나로 합치기 문제 상황 Spring WebClient를 통해 외부 API를 호출하는 과정에서 파라미터만 바꿔서 동일한 API를 여러 번 호출할 일이 있었다. 이 과정에서 각 API 호출 응답으로 받은 JSON을 DB에 저장하기 위해 엔티티 형태에 맞게 변경하여 엔티티의 리스트로 만들었다. 문제는 모든 API 호출을 비동기로 진행했기 때문에 실제 반환값은 엔티티의 리스트가 담긴 Mono 객체였다. 평범한 리스트였다면 그냥 List.addAll()을 통해 합칠 수 있겠지만 Mono 객체라서 불가능했다. 해결 방법 그렇게 방법을 찾던 중에 Stack Overflow에서 방법을 찾았다. Mono의 flatMapMany()와 Flux의 fromIterable()을 사용하면 Mono 객체를 Flux 객체로 변환할 수 있다. M.. 2023. 5. 14.
[Java/Kotlin] 필드(Field)와 프로퍼티(Property)는 무슨 차이가 있을까? 목차 들어가기 전에 처음 코틀린에 대해 공부하기 시작하면서 프로퍼티에 대한 내용을 다룰 때 좀 혼란스러운 느낌이 있었다. 자바 클래스의 필드를 이야기하는 것 같다가도 조금 다른듯한 느낌이었기 때문이다. 그래서 당시에는 그냥 어차피 비슷한 개념이고, 언어마다 명칭이 다른가보다 하면서 코틀린 클래스의 프로퍼티 = 자바 클래스의 필드의 느낌으로 인식하고 사용했다. 그러다가 최근에 객체지향의 사실과 오해(조용호 저)에 대한 스터디를 진행하면서 프로퍼티라는 단어가 나와서 이야기를 조금 했었는데, 비슷한 개념인 것은 맞지만 다른 점이 있다는 이야기를 들어서 확실하게 정리해야겠다는 생각이 들었다. 필드(Field)와 프로퍼티(Property) 결론부터 말하자면 프로퍼티는 객체가 갖는 상태와 같은 속성이고, 필드는 프.. 2023. 5. 2.