Ik stel mijn oplossing voor in een pull-request
Het idee is om Entiteit te veranderen in:
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)
}
- Elke entiteit moet een standaardconstructor hebben of standaardinstellingen voor al zijn parameters
- In plaats van POJO op te slaan, opslaan als
Map<String, Any>
typ
Aangezien we de volledige controle hebben over wat er in POJO in bedrijfslogica zal zijn, is het enige ontbrekende onderdeel het converteren van POJO naar Map en Map naar POJO
VoorbeeldPojo-implementatie
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)
}
}
Dit is eerder een tijdelijke oplossing, maar het stelt ons in staat om met structuren op diepteniveau te werken.
PS Ik heb gemerkt dat je Serializer
. gebruikt en opnieuw gedefinieerd equals, toString, hashCode
. Je hebt dit niet nodig als je data class
gebruikt .
UPDATE:
Als u een flexibelere structuur nodig heeft dan Map<String, Any>
, kunt u JsonNode
. gebruiken . Codevoorbeeld
Entiteit:
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)
}
Wijzig entiteit in repository:
import com.example.demo.entity.SampleJsonNodeEntity
import org.springframework.data.jpa.repository.JpaRepository
interface SampleJsonNodeRepository: JpaRepository<SampleJsonNodeEntity, Long> {
}
Tests voor beide benaderingen:
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)
}
}