스프링 프로젝트를 점진적으로 코틀린으로 마이그레이션 해보자.
일반적으로 원하는 파일을 선택 후 우클릭 -> conver java file to kotlin 하면 된다.
뭔가 잔뜩 물어보는데 전부 네네네 하고 모듈 선택만 잘하면 문제가 없다.
근데 이러면 코틀린 버전 중 가장 최신 걸로 된다. 하지만 우리의 스프링부트는 그렇지 않으니 스프링부트가 지원하는 코틀린 버전 보고 맞게 고치자
코틀린에는 static이 없다. 하지만 java main은 static으로 시작한다.
그래서 이렇게 @jvm 같이 java의 잔재(?)가 남아 있다.
바꿔버려
근데 이러면 빨간줄이 생긴다.
사유: 코틀린은 기본 final인데 그러면 상속이 안됨.
open 달아서 상속 허가하자.
@SpringBootApplication
@EnableJpaAuditing
open class BackendApplication
fun main(args: Array<String>) {
runApplication<BackendApplication>(*args)
}
아이 좋아
상속 해주는 모든 클래스에 open을 붙일 생각하니 머리 아프다... 이런 노가다를 피할 수 있음.
kotlin("plugin.spring") version "1.9.25"
kotlin{
compilerOptions{
freeCompilerArgs = listOf("-Xjsr305=strict")
}
}
build.gradle에 이 2개를 추가한다. 그럼 알아서 open 붙여줌
kotlin("plugin.spring") version "1.9.25"
kotlin{
compilerOptions{
freeCompilerArgs = listOf("-Xjsr305=strict")
}
}
이러면 아까 2에서 붙인 open 없이도 잘된다.
+) 원래 있던 implementation(kotlin("stdlib-jdk8"))는 kotlin("jvm") version "1.9.25"에서 이미 가져오고 있어서 삭제해도 된다.
그럼 이제 잘쓰는 의존성들을 추가해보자.
kotlin("plugin.jpa") version "1.9.25"
implementation("com.fasterxml.jackson.module:jackson-module-kotlin")
implementation("org.jetbrains.kotlin:kotlin-reflect")
allOpen {
annotation("jakarta.persistence.Entity")
annotation("jakarta.persistence.MappedSuperclass")
annotation("jakarta.persistence.Embeddable")
}
근데 사실 최신 버전부터는 플러그인 안에 allOpen이 내장 되어 있다... 내가 최신 쓴다 하면 안 넣어도 ok
그럼 이제 컨트롤러를 바꿔보자.
conver java file to kotlin!!
음. 역시 딸깍의 한계가 있다. 고치자...
<p>Server IP Address: ${localhost.hostAddress}</p>
return session.attributeNames.toList().associateWith {session.getAttribute(it)}
이런 건 근데 자바스러운 코드를 코틀린스럽게 바꾸는 거라 하나씩 해주는 수 밖에 없긴 하다
불변성을 위해 record로 되어 있다.
이건 data class로 바꾸는 게 좋다.
conver java file to kotlin!!
굿
참고로 코틀린스럽게 하려고 getter(.getId() -> .id로)는 뺐다.
그리고 이건 Entity도 마찬가지로 @Getter 빼고 직접 만들었다.
그리고 만약을 위해 @JvmRecord는 남겨두자. 마이그레이션이 완벽히 끝나고 지우는 편이 안전하니께
그리고 private constructor를 뒤에 붙이면 주 생성자 대신 부생성자만 쓰게 강제할 수 있다.
전 record가 아니라 class로 되어 있는데요! 하면 data class가 아니라 그냥 class로 바뀔 것이다. 이때는 다음 형태로 수동 변환하자.
class DTO명 접근제어자 @JvmOverloads constructor( //주 생성자 생성용
필드들 //이 필드들로 주 생성자 만듦
) {
보조 생성자
}
근데 사실 data class로 하는 게 훨씬 좋다. data class 쓰면 equals() / hashCode() / toString() / copy() / componentN() 이런거 자동으로 쓸 수 있다.
+)@JvmOverloads은 val data: T? = null 이런 식으로 기본 값이 있는 필드가 있을 때 java에서도 인지 할 수 있게 해주는 어노테이션이다. 사실 완전 코틀린이면 필요 없는데, 마이그레이션 중이라 붙인다.
+) 우리의 @JsonIgnore... 코틀린에서는 이게 어떤 상황에 무시되는지 적어야한다. @get:JsonIgnore 이렇게
근데 뻘하게 벨로그에도 토글 버튼 있으면 좋을 것 같지 않냐 왜 없는 거지
암튼 보자
일반적으로 자바의 함수는 (){} 형태다. 하지만 코틀린은 ()=한줄 표현식 할 수 있다.
이때 쓰는 게 체이닝
fun getCookieValue(name: String, defaultValue: String): String =
request
.cookies
?.firstOrNull { it.name == name }
?.value
?.takeIf { it.isNotEmpty() }
?: defaultValue
이건 Rq에서 쿠키가 있을 때 이름이 있고, 같으면 가져오고 아니면 기본값 가져오는 함수다.
이렇게 간단하게(?) 쓸 수 있다.
딱 보면 겁내 많다.
스프링 공식 문서로 가서 kotlin Config 찾기 ㄱㄱ
사실 그냥 지피띠니야 해줘 해도 되긴함
글타칸다
맞춰서 적자
@Bean
fun filterChain(http: HttpSecurity): SecurityFilterChain {
http {
authorizeHttpRequests {
authorize("/favicon.ico", permitAll)
authorize("/h2-console/**", permitAll)
authorize(HttpMethod.GET, "/api/*/posts", permitAll)
}
csrf { disable() }
headers {
frameOptions { sameOrigin = true }
}
addFilterBefore<UsernamePasswordAuthenticationFilter>(customAuthenticationFilter)
sessionManagement {
sessionCreationPolicy = SessionCreationPolicy.STATELESS
}
return http.build()
}
굿
여기에 정책 따라 추가나 삭제 하면 된다. 로그인 예외처리 같은 거 하면 좋겠쥬
변환 버튼 딸깍 -> 자바스러운 거 코틀린스럽게 수정 -> 테스트 잘 되나 확인
이거 반복하면 됩니더