Kotlinはじめましたが、微妙なところではまります。
動きはしたのですが謎なところが多かったです。
とりあえず、軽く説明をします。
Apiを叩くとredisに保存、読み取りするだけのapiを作ります。
ソースはこちら
GitHub spring boot 2.0
GitHub spring boot 1.5
実装
gradle
buildscript {
ext {
kotlinVersion = '1.2.20'
springBootVersion = '2.0.0.RELEASE'
}
repositories {
mavenCentral()
}
dependencies {
classpath("org.springframework.boot:spring-boot-gradle-plugin:${springBootVersion}")
classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:${kotlinVersion}")
classpath("org.jetbrains.kotlin:kotlin-allopen:${kotlinVersion}")
}
}
apply plugin: 'kotlin'
apply plugin: 'kotlin-spring'
apply plugin: 'eclipse-wtp'
apply plugin: 'org.springframework.boot'
apply plugin: 'io.spring.dependency-management'
apply plugin: 'war'
group = 'com.example'
version = '0.0.1-SNAPSHOT'
sourceCompatibility = 1.8
compileKotlin {
kotlinOptions {
freeCompilerArgs = ["-Xjsr305=strict"]
jvmTarget = "1.8"
}
}
compileTestKotlin {
kotlinOptions {
freeCompilerArgs = ["-Xjsr305=strict"]
jvmTarget = "1.8"
}
}
repositories {
mavenCentral()
}
configurations {
providedRuntime
}
dependencies {
compile('org.springframework.boot:spring-boot-starter-web')
compile("org.jetbrains.kotlin:kotlin-stdlib-jdk8")
compile("org.jetbrains.kotlin:kotlin-reflect")
providedRuntime('org.springframework.boot:spring-boot-starter-tomcat')
testCompile('org.springframework.boot:spring-boot-starter-test')
compile('org.springframework.boot:spring-boot-starter-data-redis')
compile("com.fasterxml.jackson.module:jackson-module-kotlin:2.9.4")
compile("org.apache.commons:commons-pool2:2.5.0")
compile("redis.clients:jedis:2.9.0")
}
1つ目の謎です。
spring-boot 1.5の時に追加したコンポーネントはspring-boot-starter-data-redis, jackson-module-kotlinだけでしたが、2.0の時はさらにcommons-pool2, jedisが必要でした。
spring-boot-starter-data-redisにcommons-pool2, jedisが依存していてもよさそうです。。。
Kotlin
package com.example
import com.example.service.SampleService
import org.springframework.web.bind.annotation.RequestMapping
import org.springframework.web.bind.annotation.RequestMethod
import org.springframework.web.bind.annotation.RestController
@RestController
class SampleController(
val sampleService: SampleService
) {
@RequestMapping(value = ["/sample-redis"], method = [RequestMethod.GET])
fun sampleReids(): SampleDto? {
return sampleService.getSampleDto();
}
@RequestMapping(value = ["/sample-redis2"], method = [RequestMethod.GET])
fun sampleReids2(): SampleDto? {
return sampleService.getSampleDto2();
}
}
package com.example
import java.io.Serializable
class SampleDto(val id:Int, val name:String):Serializable
package com.example
import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper
import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.Configuration
import org.springframework.data.redis.connection.jedis.JedisConnectionFactory
import org.springframework.data.redis.core.RedisTemplate
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer
import org.springframework.data.redis.serializer.StringRedisSerializer
@Configuration
class SampleConfiguration {
@Bean
fun jedisConnectionFactory(): JedisConnectionFactory {
return JedisConnectionFactory()
}
@Bean
fun redisTemplate(): RedisTemplate<String, SampleDto> {
val template = RedisTemplate<String, SampleDto>()
template.setConnectionFactory(jedisConnectionFactory())
template.keySerializer = StringRedisSerializer()
val jackson2JsonRedisSerializer = Jackson2JsonRedisSerializer(SampleDto::class.java)
val om = jacksonObjectMapper()
jackson2JsonRedisSerializer.setObjectMapper(om)
template.valueSerializer = jackson2JsonRedisSerializer
return template;
}
@Bean
fun redisTemplate2(): RedisTemplate<String, String> {
val template = RedisTemplate<String, String>()
template.setConnectionFactory(jedisConnectionFactory())
template.keySerializer = StringRedisSerializer()
template.valueSerializer = StringRedisSerializer()
return template;
}
}
2つ目の謎です。
connectionFactoryを設定する時の実装が1.5と2.0で違っていました。
template.connectionFactory = jedisConnectionFactory()
template.setConnectionFactory(jedisConnectionFactory())
本当は = で設定できるのですかね?
KotlinではJavaの時とは違い Jackson2JsonRedisSerializerを直接設定しても使えなかったので、作成した後にjacksonObjectMapperを設定しました。
redisTemplateの型パラメータを使ってSampleDtoをAnyにしたかったのですが、うまくいきませんでした。
たぶんできるとおもうんだけど。。。
なので、ServiceでredisTemplate2でjson変換をしてConfigurationで文字列を保存するようにしました。
package com.example.service
import com.example.SampleDto
interface SampleService {
fun getSampleDto(): SampleDto?
fun getSampleDto2(): SampleDto?
}
package com.example.service
import com.example.SampleDto
import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper
import org.springframework.data.redis.core.RedisTemplate
import org.springframework.stereotype.Service
@Service
class SampleServiceImpl(
val redisTemplate:RedisTemplate<String, SampleDto>,
val redisTemplate2:RedisTemplate<String, String>
):SampleService {
override fun getSampleDto():SampleDto? {
redisTemplate.opsForValue().set("test_dto", SampleDto(1, "aab"))
return redisTemplate.opsForValue().get("test_dto")
}
override fun getSampleDto2():SampleDto? {
val sampleDto = SampleDto(1, "aac")
val om = jacksonObjectMapper()
var jsonStr = om.writeValueAsString(sampleDto)
redisTemplate2.opsForValue().set("test_dto2", jsonStr)
val jsonStr2 = redisTemplate2.opsForValue().get("test_dto2")
return om.readValue(jsonStr2 ?: "{}", SampleDto::class.java)
}
}
参考
- Jackson Kotlin Module Example
- Kotlin – Convert Object to/from JSON with Jackson 2.x
- Java: Spring Boot で Redis を使う!
Kotlin、難しいです。。。
謎だらけです。