Jooq:如何将JSONB列Map到Kotlin数据类字段?

rlcwz9us  于 2023-02-19  发布在  Kotlin
关注(0)|答案(2)|浏览(192)

我有一个表,它有一个metadata jsonb列,这应该是关于其他表/PK的数据的json数组。我可以向数据库中插入行,但由于这个json列,我很难将记录Map到数据类中。

CREATE TABLE IF NOT EXISTS tracked_event
(
    id          uuid primary key,
    user_id     uuid references "user"      not null,
    -- other columns
    metadata jsonb not null
);

我为它创建了一个数据类:

data class TrackedEvent(
    val id: UUID,
    val userId: UUID,
    // other fields
    val metadata: List<Metadata>
)

data class Metadata(
    val tableRef: String,
    val value: UUID
)

我可以像这样为它创建一行:

fun createTrackedEvent(trackedEvent: TrackedEvent): TrackedEvent {
        val record = dslContext.newRecord(TRACKED_EVENT, trackedEvent)
        record.metadata = JSONB.jsonb(objectMapper.writeValueAsString(trackedEvent.metadata))
        record.store()
        return record.into(TrackedEvent::class.java) // issue here
    }

但是,最后一行代码有一个序列化问题:

Resolved [org.springframework.http.converter.HttpMessageNotWritableException: Could not write JSON: object is not an instance of declaring class; nested exception is com.fasterxml.jackson.databind.JsonMappingException: object is not an instance of declaring class (through reference chain: com.my.project.TrackedEvent["metadata"]->java.util.ArrayList[0]->java.util.LinkedHashMap["tableRef"])]

注意,如果我将数据类改为使用Array而不是List,它可以正常工作,但我认为这应该可以用于Kotlin的列表。

data class TrackedEvent(
    val id: UUID,
    val userId: UUID,
    // other fields
    val metadata: Array<Metadata> // this works but then it asks me the following: Property with 'Array' type in a 'data' class: it is recommended to override 'equals()' and 'hashCode()' 
)
oogrdqng

oogrdqng1#

最好的方法是将Converter直接附加到生成的代码中,如下所示:

这样,无论何时访问此信息,从/到JSONB/List<MetaData>的转换都将透明地完成。代码生成配置来自上述文档:

<configuration>
  <generator>
    <database>
      <forcedTypes>
        <forcedType>
          <userType><![CDATA[kotlin.Array<com.example.Metadata>]]></userType>
          <jsonConverter>true</jsonConverter>
          <includeExpression>(?i:tracked_event\.metadata)</includeExpression>
        </forcedType>         
      </forcedTypes>
    </database>
  </generator>
</configuration>

有关更多详细信息以及所需的其他依赖项,请参见文档。

brccelvz

brccelvz2#

@Lukas Eder提供的答案帮助我找到了解决方案!我想我应该在这里多扩展一点,以防有人也遇到这个问题。
我们在这个项目中生成Java类模型,所以我能够通过让用户类型如下来使其工作:

<userType><![CDATA[java.util.List<com.example.Metadata>]]></userType>

然后,在我的Repository中,我不再需要将元数据数组Map到jsonb:

fun createTrackedEvent(trackedEvent: TrackedEvent): TrackedEvent {
        val record = dslContext.newRecord(TRACKED_EVENT, trackedEvent)
        // record.metadata = JSONB.jsonb(objectMapper.writeValueAsString(trackedEvent.metadata)) // this is no longer needed! YAY :D
        record.store()
        return record.into(TrackedEvent::class.java)
    }

data class TrackedEvent(
    val id: UUID,
    val userId: UUID,
    // other fields
    val metadata: List<Metadata> // this stayed as a List instead of an array!
)

相关问题