Language Injections

목표 IntelliJ의 Language injections 기능이 무엇인지 이해한다. Language injections 사용 방법을 이해한다. Language injections 코드 내에 일부분을 다른 언어로 코드 어시스턴트를 받을 수 있는 기능 사용법 임시로 language injection 사용 원하는 영역에서 ⌥(Opt) + ↩(Enter)를 누르고, “Inject language or reference"를 누른다. 영구적으로 language injection 사용 원하는 영역에 @Language 애노테이션을 붙이면 IntelliJ에서 자동으로 language injection을 해준다. 적용 전 적용 후 참고 자료 https://www.jetbrains.com/help/idea/using-language-injections.html#language_annotation

2024-09-15 · 1 min · 62 words

Kotlin에서 getClass()

배경 Java에서 Class<T> 타임을 파라미터로 받는 메서드를 코틀린에서 사용할 필요가 있었다. KClass 코틀린에서는 Class<T>와 비슷하게 KClass<T>를 제공하고 있다. 아래와 같은 방식으로 타입을 얻을 수 있지만 Class<T>와는 같지 않다. String::class 자바의 타입을 얻고 싶다면, 아래와 같이 kotlin.jvm에서 제공하고 있는 확장 프로퍼티를 이용할 수 있다. String::class.java

2024-09-15 · 1 min · 44 words

Kotlin과 함께 사용시 발생할 수 있는 문제

배경 Kotlin과 Java를 혼용해서 사용하고, Java에서 롬복을 사용하고 있으면 문제가 발생할 수 있다. @Getter를 사용했음에도, Error: Cannot access ’name’: it is ‘private’ in “Person” 같이 프로퍼티에 접근할 수 없는 것을 확인할 수 있다. 이는 Lombok이 코드를 생성하는 단계보다 Kotlin 컴파일러가 코드를 컴파일 하는 과정이 먼저 이루어지기 때문에 발생하는 문제다. 아래 사진에서 Lombok 코드 생성은 Annotation Processing 단계에서 처리된다. 해결 방법 1. 빌드 전처리 과정에서 Delombok 실행 Lombok에서 제공해주고 있는 기능으로 Lombok 코드를 직접 먼저 실행하게 한다....

2024-09-15 · 1 min · 104 words

Kotlin과 사용시 open 해야되는 문제

배경 스프링은 트랜잭션 등의 AOP를 지원하기 위해 CGLIB을 사용하여 프록시를 만들기 위해, 클래스들을 동적으로 상속한다. 따라서, final 클래스는 컴포넌트로 사용할 수 없다. Kotlin 클래스는 기본값이 final 이므로 매번 open 키워드를 붙여줘야되는 번거로움이 있다. kotlin-maven-allopen 이를 해결해주기 위해 kotlin에서는 kotlin-maven-allopen이라는 플러그인을 제공해준다. @Configuration이나 @Transactional, @Component 등 스프링 관련 어노테이션이 붙어있는 클래스나 메서드는 자동으로 open 시켜서 CGLIB에 사용할 수 있게 해준다. <plugin> <groupId>org.jetbrains.kotlin</groupId> <artifactId>kotlin-maven-plugin</artifactId> <configuration> <compilerPlugins> <plugin>spring</plugin> </compilerPlugins> <dependencies> <dependency> <groupId>org.jetbrains.kotlin</groupId> <artifactId>kotlin-maven-allopen</artifactId> <version>${kotlin....

2024-09-15 · 1 min · 79 words

Kotlin과 Java 혼용시 Checked Exception 알려주기

상황 코틀린에서는 Checked Exception을 따로 처리해주지 않는다. 자바에서 Checked Exception을 catch 해서 처리해주고 싶은데 이가 문제가 되었다. 해결 방법 코틀린에 @Throws 어노테이션을 사용하면 자바에서 checked exception 처리가 가능해진다. @Throws(IOException::class) fun foo() { throw IOException() } 참고 자료 https://kotlinlang.org/docs/java-to-kotlin-interop.html#checked-exceptions https://stackoverflow.com/questions/36528515/throws-exception-in-a-method-with-kotlin

2024-09-15 · 1 min · 39 words

Kotlin takeIf

목표 takeIf() 함수의 목적을 이해한다. takeIf inline fun <T> T.takeIf(predicate: (T) -> Boolean): T? predicate가 true면 this를 리턴하고, false면 null을 리턴한다. 참고 자료 https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/take-if.html

2024-09-15 · 1 min · 24 words

Kotlin Contracts

목표 Kotlin contracts가 무엇인지 이해한다. Kotlin contracts의 사용법을 이해한다. 배경 아래 사진과 같이 validate() 함수에서 request의 null 검사를 했음에도 불구하고, process는 다른 함수여서 스마트 캐스트가 이루어지지 않는다. Kotlin contracts를 사용하면 이 문제를 해결할 수 있다. Kotlin contracts는 컴파일러에게 함수의 동작을 알려준다. 스마트 캐스트 contract() 메서드를 호출되는 함수에 선언하고, 내부에 함수의 동작을 명시한다. returns(): 함수가 정상적으로 리턴되는 경우를 의미한다. implies(): 파라미터로 받은 booleanExpression이 항상 참임을 보장한다. 실험적인 단계의 contract API를 사용하는 함수에는 @OptIn(ExperimentalContracts:class)를 붙여주거나 컴파일 인자로 -opt-in=kotlin....

2024-09-15 · 1 min · 183 words

keyword의 최대 길이

배경 fields 매핑을 이용해 특정 text를 keyword로도 사용할 수 있도록 설정해둠 그러나 keyword 필드에 값이 존재하지 않음 원인 keyword 타입 매핑시에 처리 가능한 최대 길이를 설정할 수 있다. "ignore_above" : <자연수> 옵션이며, 다이나믹 매핑으로 keyword가 생성될 때는 기본값인 256으로 설정된다. 참고 자료 https://esbook.kimjmin.net/07-settings-and-mappings/7.2-mappings/7.2.1#keyword https://www.elastic.co/guide/en/elasticsearch/reference/current/ignore-above.html

2024-09-15 · 1 min · 44 words

KafkaProducer 기본 구성 요소

목표 client에서 KafkaProducer가 메시지지를 produce하는 과정을 이해한다. Spring 에서 KafkaTemplate 호출시 동작 KafkaTemplate.doSend() 메서드 호출시 KafkaProducer.send() 메서드를 내부에서 호출하고 있다. send() 메서드 호출 시 파라미터로 전송할 ProducerRecord와 Callback 파라미터를 넘겨준다. KafkaProducer의 기본 구성 요소 KafkaProducer: 사용자가 직접 사용하는 클래스. send() 메서드를 호출하면 Record를 전송한다. RecordAccumulator: 사용자가 KafkaProducer::send() 메서드를 호출하면 Record가 바로 전송되는 것이 아니라 RecordAccumulator에 저장된다. 그리고 실제로 Broker에 저장되는 것은 이후에 비동기적으로 이루어진다. Sender: KafkaProducer는 별도의 Sender Thread를 생성한다. Sender Thread는 RecordAccumulator에 저장된 Record들을 Broker로 전송하는 역할을 한다....

2024-09-15 · 1 min · 103 words

K6 시작하기

설치 https://k6.io/docs/getting-started/installation/ 위 링크를 참고하면 내가 원하는 환경의 설치 방법을 확인할 수 있다. 나 같은 경우는 도커 환경에서 성능 테스트를 진행할 예정이라 아래와 같은 명령어를 입력했다. $ docker pull loadimpact/k6 실행 하기 K6의 테스트 작성은 매우 간단했다. JavaScript 파일을 하나 만들어두고 아래와 같이 function 안에 시나리오를 작성하면 된다. import http from 'k6/http'; import { sleep } from 'k6'; export default function () { http.get('https://test.k6.io'); sleep(1); } 도커에서 실행해야되므로 아래와 같이 실행했다....

2024-09-15 · 1 min · 171 words

JUnit 5 Extensions

목표 @ExtendWith 애노테이션의 역할을 알아본다. JUnit 5 Extension JUnit 5에서는 테스트 클래스나 메소드의 동작을 확장하기 위해서 extension을 제공해주고 있다. extension points: 테스트 실행에서 발생할 수 있는 이벤트 지점. 이 지점에서 등록된 extension을 호출할 수 있따. extension point의 5가지 종류: 괄호 안은 구현해야되는 인터페이스 테스트 인스턴스 후처리(TestInstancePostProcessor): 일반적으로 의존성 주입할 때 사용한다. 조건부 테스트 실행( ExecutionCondition): 조건에 따라 테스트 실행 여부를 설정할 수 있다. 라이프사이클 콜백: 테스트 라이프사이클에 행동을 추가할 수 있다....

2024-09-15 · 1 min · 145 words

JSP에서 SpEL 사용 시 null 인 경우 예외 발생

배경 Spring Framework에서는 view가 JSP 인 경우에 대한 여러 가지 기능을 tag 기능으로 제공해주고 있다. 그 중 eval 태그를 사용하면 JSP에서 변수를 할당하거나 출력할 수 있다. <spring:eval expression="someVariable" /> 위 예시에서 someVariable이 null 인 경우에 SpelEvaluationException 가 발생한다. 해결 방법 이를 해결하기 위해서는 사용할 변수의 scope를 명확하게 명시해야 된다고 한다. <spring:eval expression="requestScope['someVariable']?.bytes"/> 참고 자료 https://github.com/spring-projects/spring-framework/issues/13211 https://stackoverflow.com/questions/16289341/how-to-pass-a-null-variable-into-a-spring-expression-in-jsp https://docs.spring.io/spring-framework/docs/4.2.x/spring-framework-reference/html/spring-tld.html#spring.tld.eval

2024-09-15 · 1 min · 57 words

Jsoup Java를 이용해서 크롤링 하기

특정 URL의 문서 가져오기 Document doc = Jsoup.connect("http://example.com/").get(); selector 문법으로 원하는 위치의 엘리먼트 가져오기 Elements links = doc.select("a[href]"); // a with href Elements 는 ArrayList 를 상속하고 있다. 엘리먼트의 속성값 가져오기 String relHref = link.attr("href"); 참고 자료 https://jsoup.org/cookbook/extracting-data/working-with-urls

2024-09-15 · 1 min · 38 words

JpaRepository에서 SQL 작성하기

@Query 어노테이션에 nativeQuery 필드를 true로 설정하면 JPQL이 아닌 SQL 문을 작성할 수 있다. @Query( value = "SELECT * FROM USERS u WHERE u.status = 1", nativeQuery = true) Collection<User> findAllActiveUsersNative(); 참고 자료 https://www.baeldung.com/spring-data-jpa-query

2024-09-15 · 1 min · 33 words

JobParameters

목표 JobParameters가 무엇인지 이해한다. JobParameters 배치 작업에서 런타임 매개변수를 던져주기 위한 VO다. 이를 사용하기 위해서는 Job이나 Step의 late binding이 가능하도록 설정해야된다. late binding으로 동작하고자 하는 Step은 아래와 같이 step scope를 지정하면 된다. 이는 Job을 실제로 실행하기 전까지 인스턴스화 하지 않는다. 또한 Step을 실행할 때 마다가 각자 다른 인스턴스가 실행되어서 병렬 처리시에 충돌이 발생하지 않는다. @StepScope @Bean public FlatFileItemReader flatFileItemReader(@Value("#{jobParameters['input.file.name']}") String name) { return new FlatFileItemReaderBuilder<Foo>() .name("flatFileItemReader") .resource(new FileSystemResource(name)) ... } 참고 자료 https://docs....

2024-09-15 · 1 min · 76 words

JDK 라이센스 문제

Java 애플리케이션을 컴파일하기 위한 JDK는 크게 Oracle JDK와 OpenJDK로 나뉜다. Oracle JDK의 경우 일반적인 목적(General Purpose Computing)이 아닌 경우 라이센스 비를 지불해야된다. 따라서, 여러 회사에서는 이 애매한 표현 때문에 대부분 오픈소스인 OpenJDK를 사용한다. Java SE7부터 모든 JDK는 OpenJDK 레퍼런스 코드를 기반으로 제작된다. Oracle JDK 또한 마찬가지다. OpenJDK 운영 주체 또한 Oracle이다. 오라클이 아닌 서드파티 업체가 OpenJDK를 기반으로 공인된 JDK를 제작하여 배포하려면 오라클의 유료 라이센스인 OCTLA에 가입해야 한다. 현재 전세계에 19개 업체가 가입되어 있다....

2024-09-15 · 1 min · 103 words

JDBC의 SQL Injection 대응

정확히는 JDBC 내부적으로 SQL Injection에 대응하고 있다. PreparedStatement 클래스를 예로 들면 setString() 메서드에 내부적으로 SQL Injection에 대응하고 있기 때문에 안전하게 사용할 수 있다. https://www.baeldung.com/sql-injection 따라서 아래와 같은 코드를 작성하지 않도록 조심하자. String sql = "select " + "customer_id,acc_number,branch_id,balance " + "from Accounts where customer_id = '" + customerId + "'"; Connection c = dataSource.getConnection(); ResultSet rs = c.createStatement().executeQuery(sql); select count(1) from user where id = ? and password = ?

2024-09-15 · 1 min · 70 words

JDBC에서 모든 테이블 이름 찾기

Rest Assured를 통한 E2E 테스트 진행시, 모든 테스트를 독립적으로 만들기 위해 각 테스트마다 모든 테이블을 TRUNCATE 할 필요가 있었다. 그래서 모든 테이블의 이름을 찾는 과정이 필요했다. DatabaseMetaData 를 통해 찾을 수 있다고 한다. DatabaseMetaData는 Connection을 통해 얻을 수 있다. 나같은 경우 Spring을 사용하고 있어서 JdbcTemplate를 통해서 구할 수 있었다. private void truncateAllTables() throws SQLException { JdbcTestUtils.deleteFromTables(jdbcTemplate, getAllTables().toArray(new String[0])); } private List<String> getAllTables() throws SQLException { DatabaseMetaData metaData = jdbcTemplate.getDataSource().getConnection().getMetaData(); List<String> tables = new ArrayList<>(); try (ResultSet resultSet = metaData....

2024-09-15 · 1 min · 104 words

JDBC에서 MySQL의 COUNT 함수 리턴 타입

배경 MyBatis를 이용해 특정 id별 COUNT 결과를 Pair<Long, Int> 로 리턴했더니, 타입 캐스팅 예외가 발생했다. java.lang.ClassCastException: java.lang.Long cannot be cast to java.lang.Integer 문제 상황 예시 코드 @Select("...") fun countByIds(ids: List<Long>): List<Pair<Long, Int>> 원인 MySQL의 COUNT 함수의 리턴 타입은 BIGINT 이다. MySQL JDBC Driver 에서 BIGINT는 기본적으로 Java의 Long 타입으로 변환되므로 타입 캐스팅 예외가 발생한다. 참고 자료 https://dev.mysql.com/doc/refman/8.0/en/aggregate-functions.html#function_count https://dev.mysql.com/doc/connector-j/en/connector-j-reference-type-conversions.html

2024-09-15 · 1 min · 58 words

JdbcTemplate와 템플릿 콜백 패턴

템플릿/콜백 패턴: 전략 패턴의 기본 구조에 익명 내부 클래스를 활용한 방식이다. 템플릿/콜백 패턴은 DI 방식의 전략 패턴 구조다. 클라이언트가 템플릿 메소드를 호출하면서 콜백 오브젝트를 전달하는 방식으로 메소드 레벨에서 일어나는 DI다. 템플릿: 어떤 목적을 위해 미리 만들어둔 모양이 있는 틀을 가리킨다. 템플릿 메소드 패턴은 고정된 틀의 로직을 가진 템플릿 메소드를 슈퍼클래스에 두고, 바뀌는 부분을 서브 클래스의 메소드에 두는 구조로 이루어진다. 콜백: 실행되는 것을 목적으로 다른 오브젝트의 메소드에 전달되는 오브젝트를 말한다. 자바에선 메소드 자체를 파라미터로 넘기지 못하기 때문에 메소드가 담긴 오브젝트를 넘긴다....

2024-09-15 · 1 min · 136 words