在我的实体的枚举字段中,我添加了@CassandraType(type = DataType.Name.INT)。然而,在发送给Cassandra的语句中使用的不是枚举的序号,而是字符串表示。因此,我得到以下错误:
org.springframework.data.cassandra.CassandraInvalidQueryException: SessionCallback; CQL [INSERT INTO thing (thing_id,some_enum) VALUES (1,'Foo');]; Expected 4 or 0 byte int (3); nested exception is com.datastax.driver.core.exceptions.InvalidQueryException: Expected 4 or 0 byte int (3)下面你可以找到一个最小的例子,重现这个问题。
我做错了什么?
test/src/main/kotlin/enumtest/Application.kt
package enumtest
import org.springframework.boot.autoconfigure.SpringBootApplication
import org.springframework.boot.runApplication
@SpringBootApplication
class Application
fun main(args: Array<String>) {
runApplication<Application>(*args)
}test/src/main/kotlin/enumtest/SomeEnum.kt
package enumtest
enum class SomeEnum {
Foo,
Bar
}test/src/main/kotlin/enumtest/Thing.kt
package enumtest
import com.datastax.driver.core.DataType
import org.springframework.data.cassandra.core.cql.PrimaryKeyType
import org.springframework.data.cassandra.core.mapping.CassandraType
import org.springframework.data.cassandra.core.mapping.Column
import org.springframework.data.cassandra.core.mapping.PrimaryKeyColumn
import org.springframework.data.cassandra.core.mapping.Table
@Table("thing")
@Suppress("unused")
class Thing(
@PrimaryKeyColumn(name = "thing_id", ordinal = 0, type = PrimaryKeyType.PARTITIONED)
var thingId: Long,
@CassandraType(type = DataType.Name.INT)
@Column("some_enum")
var someEnum: SomeEnum
)test/src/main/kotlin/enumtest/ThingRepository.kt
package enumtest
import org.springframework.data.cassandra.repository.CassandraRepository
import org.springframework.stereotype.Repository
@Repository
interface ThingRepository : CassandraRepository<Thing, Long>test/src/main/resources/application.yml
spring:
data:
cassandra:
contact-points: localhost
port: 9142
keyspace_name: enumtesttest/src/test/kotlin/enumtest/PersistenceTest.kt
package enumtest
import org.cassandraunit.spring.CassandraDataSet
import org.cassandraunit.spring.CassandraUnitDependencyInjectionTestExecutionListener
import org.cassandraunit.spring.EmbeddedCassandra
import org.junit.Assert
import org.junit.Test
import org.junit.runner.RunWith
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.boot.test.context.SpringBootTest
import org.springframework.test.context.TestExecutionListeners
import org.springframework.test.context.junit4.SpringRunner
@RunWith(SpringRunner::class)
@SpringBootTest
@TestExecutionListeners(
listeners = [CassandraUnitDependencyInjectionTestExecutionListener::class],
mergeMode = TestExecutionListeners.MergeMode.MERGE_WITH_DEFAULTS
)
@CassandraDataSet(value = ["cql/cassandra_schema.cql"], keyspace = "enumtest")
@EmbeddedCassandra
class PersistenceTest {
@Autowired
lateinit var thingRepository: ThingRepository
@Test
fun `test save`() {
thingRepository.save(Thing(1, SomeEnum.Foo))
val things = thingRepository.findAll()
Assert.assertEquals(1, things.size)
val thing = things[0]
Assert.assertEquals(SomeEnum.Foo, thing.someEnum)
}
}test/src/test/resources/cql/cassandra_schema.cql
CREATE KEYSPACE IF NOT exists enumtest
WITH REPLICATION = {'class':'SimpleStrategy', 'replication_factor':1};
CREATE TABLE IF NOT exists enumtest.thing (
thing_id bigint,
some_enum int,
PRIMARY KEY (thing_id)
);test/build.gradle
plugins {
id 'org.springframework.boot' version '2.1.4.RELEASE'
id 'org.jetbrains.kotlin.jvm' version '1.3.30'
id 'org.jetbrains.kotlin.plugin.spring' version '1.3.30'
}
apply plugin: 'io.spring.dependency-management'
group = 'com.example'
version = '0.0.1-SNAPSHOT'
sourceCompatibility = '1.8'
repositories {
mavenCentral()
maven { url "https://repository.apache.org/snapshots/" }
}
dependencies {
implementation group: 'org.springframework.boot', name: 'spring-boot-starter'
implementation group: 'org.springframework.boot', name: 'spring-boot-starter-data-cassandra'
implementation group: 'org.jetbrains.kotlin', name: 'kotlin-stdlib-jdk8'
implementation group: 'org.jetbrains.kotlin', name: 'kotlin-reflect'
testImplementation group: 'org.cassandraunit', name: 'cassandra-unit-spring', version: '3.5.0.1'
testImplementation group: 'org.springframework.boot', name: 'spring-boot-starter-test'
}
compileKotlin {
kotlinOptions {
freeCompilerArgs = ['-Xjsr305=strict']
jvmTarget = '1.8'
}
}
compileTestKotlin {
kotlinOptions {
freeCompilerArgs = ['-Xjsr305=strict']
jvmTarget = '1.8'
}
}下面是下载到实用实验的最小示例的完整版本:https://drive.google.com/open?id=1zzIDhbWycaj4WXrze2sAmw8xRPacA8Js
编辑:因为它似乎是一个bug,我刚刚打开了Jira问题。
发布于 2019-05-04 02:31:49
我已经尝试了很长一段时间,我似乎终于得到了它!
我遇到了和你和编解码器一样的问题.我不知道为什么不起作用。根据他们的文件,你做的完全正确。
所以我实现了我自己的卡桑德拉写转换器。见下文
@Configuration
class CassandraConfig(val cluster: Cluster){
@Bean
fun setCustomCassandraConversions() = CassandraCustomConversions(listOf(EnumWriteConverter.INSTANCE, EnumReadConverter.INSTANCE))
@WritingConverter
enum class EnumWriteConverter : Converter<Enum<MyEnum>, Int> {
INSTANCE;
override fun convert(source: Enum<MyEnum>) = source.ordinal
}
@ReadingConverter
enum class EnumReadConverter : Converter<Int, Enum<MyEnum>> {
INSTANCE;
override fun convert(source: Int) = MyEnum.values()[source]
}
}在对Cassandra进行每次写入时,这都应该使用覆盖的转换器将它所看到的MyEnum类型的所有枚举转换为Int。这使您有可能为不同类型的enums拥有多个这样的值,可能出于某种原因,您希望从它们中写入其他自定义值,而不是总是转换所有枚举。
希望这行得通!
编辑注意在删除{}(例如在每个转换器上)并向CassandraCustomConversions注册ReadingConverter方面发生的变化
发布于 2019-05-23 14:15:36
这是自Spring版本的固定 2.1.5。
但是,@CassandraType需要在Kotlin中显式地放置在getter上,因为否则在运行时看不到它。
在实践中,这只是意味着取代这一点:
@CassandraType(type = DataType.Name.INT)
var someEnum: SomeEnum在此基础上:
@get: CassandraType(type = DataType.Name.INT)
var someEnum: SomeEnumhttps://stackoverflow.com/questions/55915849
复制相似问题