【问题标题】:Persist Java Map as PostgreSQL jsonb using spring data jdbc使用spring数据jdbc将Java Map持久化为PostgreSQL jsonb
【发布时间】:2021-08-30 13:04:39
【问题描述】:

我正在使用spring-data-jdbc 将以下实体持久化到 PostgreSQL 中

@Table("abc_configurations")
data class AbcConfiguration(
    val name: String,
    val distribution: Map<String, Int>
)

分布是PostgreSQL表中的一个jsonb列:

CREATE TABLE abc_configurations
(
    name          VARCHAR(50)    PRIMARY KEY,
    distribution  JSONB    NOT NULL
);

我为此创建了以下custom converter

import com.fasterxml.jackson.core.type.TypeReference
import com.fasterxml.jackson.databind.ObjectMapper
import org.postgresql.util.PGobject
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.Configuration
import org.springframework.core.convert.converter.Converter
import org.springframework.data.convert.ReadingConverter
import org.springframework.data.convert.WritingConverter
import org.springframework.data.jdbc.core.convert.JdbcCustomConversions
import org.springframework.data.jdbc.core.convert.JdbcValue
import org.springframework.data.jdbc.repository.config.AbstractJdbcConfiguration
import org.springframework.data.jdbc.repository.config.EnableJdbcRepositories
import java.sql.JDBCType

@Configuration
@EnableJdbcRepositories
class DataConfig : AbstractJdbcConfiguration() {

    @Autowired
    private lateinit var objectMapper: ObjectMapper;

    @Bean
    override fun jdbcCustomConversions(): JdbcCustomConversions {
        val converters = listOf(
            DistributionWritingConverter(objectMapper),
            DistributionReadingConverter(objectMapper)
        )
        return JdbcCustomConversions(converters)
    }

    @WritingConverter
    class DistributionWritingConverter(private val objectMapper: ObjectMapper) : Converter<Map<String, Int>, JdbcValue> {
        override fun convert(source: Map<String, Int>): JdbcValue {
            return JdbcValue.of(objectMapper.writeValueAsString(source), JDBCType.VARCHAR)
        }
    }

    @ReadingConverter
    class DistributionReadingConverter(private val objectMapper: ObjectMapper) : Converter<PGobject, Map<String, Int>> {
        override fun convert(source: PGobject): Map<String, Int> {
            return objectMapper.readValue(source.value, object : TypeReference<Map<String, Int>>() {})
        }
    }
}

当我持久化一个实体时,它可以正常工作,并且分布 Map 会按预期持久化到 JSONB 列中。

问题是当我阅读实体时,我收到以下错误:Couldn't find PersistentEntity for type class java.lang.Integer!

org.springframework.data.mapping.MappingException: Couldn't find PersistentEntity for type class java.lang.Integer!
    at org.springframework.data.mapping.context.MappingContext.getRequiredPersistentEntity(MappingContext.java:79) ~[spring-data-commons-2.4.5.jar:2.4.5]
    at org.springframework.data.jdbc.core.convert.SqlGeneratorSource.lambda$getSqlGenerator$0(SqlGeneratorSource.java:62) ~[spring-data-jdbc-2.1.5.jar:2.1.5]
    at java.base/java.util.concurrent.ConcurrentMap.computeIfAbsent(ConcurrentMap.java:330) ~[na:na]
    at org.springframework.data.jdbc.core.convert.SqlGeneratorSource.getSqlGenerator(SqlGeneratorSource.java:61) ~[spring-data-jdbc-2.1.5.jar:2.1.5]
    at org.springframework.data.jdbc.core.convert.DefaultDataAccessStrategy.sql(DefaultDataAccessStrategy.java:583) ~[spring-data-jdbc-2.1.5.jar:2.1.5]
    at org.springframework.data.jdbc.core.convert.DefaultDataAccessStrategy.findAllByPath(DefaultDataAccessStrategy.java:362) ~[spring-data-jdbc-2.1.5.jar:2.1.5]
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:na]
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:64) ~[na:na]
    at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:na]
    at java.base/java.lang.reflect.Method.invoke(Method.java:564) ~[na:na]
    at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:344) ~[spring-aop-5.3.4.jar:5.3.4]

我已尝试将 @ReadingConverter 方法更改为以下方法,但不起作用:

  • Converter&lt;String, Map&lt;String, Int&gt;&gt;
  • Converter&lt;JdbcValue, Map&lt;String, Int&gt;&gt;

未使用 ReadingConverter。

我如何告诉 spring 使用自定义 @ReadingConverter

更新 (01.09.2021):

正如 Jen 和 Susan 所提到的,这是 spring-data-jdbc 库的问题。我继续进行以下工作。

data class Distribution(val value: Map<String, Int>)


@Table("abc_configurations")
data class AbcConfiguration(
    val name: String,
    val distribution: Distribution
)

【问题讨论】:

标签: java postgresql jsonb spring-data-jdbc


【解决方案1】:

Map 在 Spring Data JDBC 中得到了特殊处理,因此您不能简单地为它们使用转换器。 而是将地图包装在自定义类型中并为该类型注册转换器。

【讨论】:

  • 感谢 Jens,帮助解决了这个问题。您是否有任何解决此问题的计划,以便我们不必应用此解决方法。类似于列上的注释会覆盖此特殊处理?
  • 我们正在考虑如何改进对 JSON 的支持。我完全不确定这是否会/应该允许直接转换地图
猜你喜欢
  • 2020-04-14
  • 2015-02-18
  • 1970-01-01
  • 1970-01-01
  • 2020-06-28
  • 2021-04-15
  • 2020-11-07
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多