这个想法是将Entity更改为:
import com.example.demo.pojo.SamplePojo
import com.vladmihalcea.hibernate.type.json.JsonBinaryType
import com.vladmihalcea.hibernate.type.json.JsonStringType
import org.hibernate.annotations.Type
import org.hibernate.annotations.TypeDef
import org.hibernate.annotations.TypeDefs
import javax.persistence.*
@Entity
@Table(name = "tests")
@TypeDefs(
TypeDef(name = "json", typeClass = JsonStringType::class),
TypeDef(name = "jsonb", typeClass = JsonBinaryType::class)
)
data class SampleEntity (
@Id @GeneratedValue
val id: Long?,
val name: String?,
@Type(type = "jsonb")
@Column(columnDeFinition = "jsonb")
var data: Map<String, Any>?
) {
/**
* Dependently on use-case this can be done differently:
* https://stackoverflow.com/questions/37873995/how-to-create-empty-constructor-for-data-class-in-kotlin-android
*/
constructor(): this(null, null, null)
}
由于我们可以完全控制业务逻辑中的POJO,因此唯一缺少的部分是将POJO转换为Map并将Map转换为POJO
SamplePojo实现
data class SamplePojo(
val payload: String,
val flag: Boolean
) {
constructor(map: Map<String, Any>) : this(map["payload"] as String, map["flag"] as Boolean)
fun toMap() : Map<String, Any> {
return mapOf("payload" to payload, "flag" to flag)
}
}
这是一种解决方法,但是它允许我们使用任何深度级别的结构。
PS我注意到您使用Serializer
并重新定义了equals, toString, hashCode
。如果使用,则不需要此data class
。
如果您需要比以上更灵活的结构Map<String,Any>
,则可以使用JsonNode
。代码示例
实体:
import com.fasterxml.jackson.databind.JsonNode
import com.vladmihalcea.hibernate.type.json.JsonBinaryType
import com.vladmihalcea.hibernate.type.json.JsonStringType
import org.hibernate.annotations.Type
import org.hibernate.annotations.TypeDef
import org.hibernate.annotations.TypeDefs
import javax.persistence.*
@Entity
@Table(name = "tests")
@TypeDefs(
TypeDef(name = "json", typeClass = JsonStringType::class),
TypeDef(name = "jsonb", typeClass = JsonBinaryType::class)
)
data class SampleJsonNodeEntity (
@Id @GeneratedValue
val id: Long?,
val name: String?,
@Type(type = "jsonb")
@Column(columnDeFinition = "jsonb")
var data: JsonNode?
) {
/**
* Dependently on use-case this can be done differently:
* https://stackoverflow.com/questions/37873995/how-to-create-empty-constructor-for-data-class-in-kotlin-android
*/
constructor(): this(null, null, null)
}
更改存储库中的实体:
import com.example.demo.entity.SampleJsonNodeEntity
import org.springframework.data.jpa.repository.JpaRepository
interface SampleJsonNodeRepository: JpaRepository<SampleJsonNodeEntity, Long> {
}
测试两种方法:
import com.example.demo.DbTestInitializer
import com.example.demo.entity.SampleJsonNodeEntity
import com.example.demo.entity.SampleMapEntity
import com.example.demo.pojo.SamplePojo
import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper
import junit.framework.Assert.assertEquals
import junit.framework.Assert.assertNotNull
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.boot.test.autoconfigure.jdbc.AutoConfigureTestDatabase
import org.springframework.boot.test.context.SpringBootTest
import org.springframework.test.context.ContextConfiguration
import org.springframework.test.context.junit4.SpringRunner
@RunWith(SpringRunner::class)
@SpringBootTest
@ContextConfiguration(initializers = [DbTestInitializer::class])
@AutoConfigureTestDatabase(replace = AutoConfigureTestDatabase.Replace.NONE)
class SampleRepositoryTest {
@Autowired
lateinit var sampleMapRepository: SampleMapRepository
@Autowired
lateinit var sampleJsonNodeRepository: SampleJsonNodeRepository
lateinit var dto: SamplePojo
lateinit var mapEntity: SampleMapEntity
lateinit var jsonNodeEntity: SampleJsonNodeEntity
@Before
fun setUp() {
dto = SamplePojo("Test", true)
mapEntity = SampleMapEntity(null,
"POJO1",
dto.toMap()
)
jsonNodeEntity = SampleJsonNodeEntity(null,
"POJO2",
jacksonObjectMapper().valueToTree(dto)
)
}
@Test
fun createMapPojo() {
val id = sampleMapRepository.save(mapEntity).id!!
assertNotNull(sampleMapRepository.getOne(id))
assertEquals(sampleMapRepository.getOne(id).data?.let { SamplePojo(it) }, dto)
}
@Test
fun createJsonNodePojo() {
val id = sampleJsonNodeRepository.save(jsonNodeEntity).id!!
assertNotNull(sampleJsonNodeRepository.getOne(id))
assertEquals(jacksonObjectMapper().treeToValue(sampleJsonNodeRepository.getOne(id).data, SamplePojo::class.java), dto)
}
}