date not format as in hibernate 5 with jsonb in hibernate 6

wfsdck30  于 2023-10-23  发布在  其他
关注(0)|答案(1)|浏览(120)

我正在迁移到quarkus 3,我找不到一种方法来正确序列化(如在hibernate 5中)我的OffsetDateTime,用于实体中用jsonb注解的字段:
这是我的一个实体,OffsetDateTime在持久化时不会有问题,因为我在配置中添加了参数hibernate-mapping.timezone.default-storage=“NORMALIZE”,因此我可以使用时区正确获取日期

package myPackage;

import com.fasterxml.jackson.annotation.JsonInclude;
import com.orange.erable.ohp.common.quarkus.rest.internal.identifier.models.IdentifierCharacteristicNameDTO;
import com.orange.erable.ohp.persistence.entities.enums.EIdentifierCategory;
import com.orange.erable.ohp.persistence.entities.enums.EIdentifierStatus;
import io.hypersistence.utils.hibernate.type.basic.PostgreSQLEnumType;
import io.quarkus.hibernate.orm.panache.PanacheEntityBase;
import lombok.Data;
import org.hibernate.annotations.Type;

import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.EnumType;
import jakarta.persistence.Enumerated;
import jakarta.persistence.Id;
import jakarta.persistence.Table;
import jakarta.persistence.Transient;
import jakarta.validation.constraints.NotNull;

import java.lang.reflect.Field;
import java.time.OffsetDateTime;
import java.util.UUID;

@Data
@Entity
@Table(name = "t_identifier")
public class IdentifierEntity extends PanacheEntityBase {

    @Id
    private String idohp;

    private String msisdn;

    private String idAdv;

    private String contractAid;

    private String countryCode;

    @NotNull
    @Enumerated(EnumType.STRING)
    @Type(PostgreSQLEnumType.class)
    @Column(columnDefinition = "status")
    private EIdentifierStatus status;

    @Enumerated(EnumType.STRING)
    @Type(PostgreSQLEnumType.class)
    @Column(columnDefinition = "category")
    private EIdentifierCategory category;

    @Column(updatable = false)
    private OffsetDateTime creationDate = OffsetDateTime.now();

    private OffsetDateTime updateDate = OffsetDateTime.now();

    @JsonInclude(JsonInclude.Include.NON_NULL)
    @Transient
    private boolean updated = false;

    @JsonInclude(JsonInclude.Include.NON_NULL)
    @Transient
    private boolean created = false;
}

但是对于这个包含先前实体的实体,OffsetDateTime内部标识符没有以正确的格式持久化,它是以UTC格式持久化的,我错过了我的时区:

package myPackage;

import io.hypersistence.utils.hibernate.type.json.JsonBinaryType;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.hibernate.annotations.*;

import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import jakarta.persistence.Table;

import java.time.OffsetDateTime;

@Data
@NoArgsConstructor
@Entity
@Table(name = "t_identifier_history")
public class IdentifierHistoryEntity {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private long id;

    private String idohp;

    @Type(JsonBinaryType.class)
    @Column(columnDefinition = "jsonb")
    private IdentifierEntity identifier;

    @Column(insertable = false, updatable = false)
    private OffsetDateTime creationDate = OffsetDateTime.now();

    @Column(insertable = false)
    private OffsetDateTime updateDate = OffsetDateTime.now();

    private String historyVersion;

    public IdentifierHistoryEntity(IdentifierEntity identifierEntity, String historyVersion) {
        this.idohp = identifierEntity.getIdohp();
        this.identifier = identifierEntity;
        this.historyVersion = historyVersion;
    }
}

我尝试在标识符字段上设置@JdbcTypeCode(SqlTypes.JSON)
我尝试创建自己的格式Map器,并使用quarkus. hibernate-mapping. unauthorized-properties.“hibernate.type.json_format_mapper”=“myCustommapper”引用它:

public class RegisterJacksonCustomizer implements FormatMapper {
    private final FormatMapper delegate = new JacksonJsonFormatMapper(createObjectMapper());

    private static ObjectMapper createObjectMapper() {
        ObjectMapper objectMapper = new ObjectMapper();
        objectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
        objectMapper.enable(DeserializationFeature.READ_UNKNOWN_ENUM_VALUES_AS_NULL);
        objectMapper.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);
        objectMapper.disable(SerializationFeature.WRAP_ROOT_VALUE);
        objectMapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);

        final JavaTimeModule javaTimeModule = new JavaTimeModule();

        javaTimeModule.addSerializer(OffsetDateTime.class, new CustomOffsetDateTimeSerializer(DATE_TIME_FORMATTER));
        javaTimeModule.addDeserializer(OffsetDateTime.class, new CustomOffsetDateTimeDeserializer(DateTimeFormatter.ISO_OFFSET_DATE_TIME));

        objectMapper.registerModule(javaTimeModule);
        return objectMapper;
    }

    @Override
    public <T> T fromString(CharSequence charSequence, JavaType<T> javaType, WrapperOptions wrapperOptions) {
        return delegate.fromString(charSequence, javaType, wrapperOptions);
    }

    @Override
    public <T> String toString(T t, JavaType<T> javaType, WrapperOptions wrapperOptions) {
        return delegate.toString(t, javaType, wrapperOptions);
    }
}

结合此配置:

quarkus:
  hibernate-orm:
    mapping:
      timezone:
        default-storage: "NORMALIZE"
    jdbc:
      timezone: "Europe/Paris"
    unsupported-properties:
      - "hibernate.type.json_format_mapper": "pathToMyMapper"
laximzn5

laximzn51#

我看到你的问题中有几个令人困惑的地方,所以我将分别回答它们。

JSONMap很可能忽略对象/关系Map!

当您将属性Map为JSON/XML时,您避开了任何关系Map,因此jsonb标识符中的日期忽略quarkus.hibernate-orm.mapping.timezone.default-storage也就不足为奇了。如果IdentifierEntity中的Integer列被Map为数据库中的字符串,也会发生同样的情况:JSON序列化仍然会将其Map为整数。
如果你想改变你的实体被序列化为JSON的方式,你将不得不使用一个自定义的FormatMapperdoesn't have first-class support in Quarkus yet有一个不支持的解决方案。你声称你试过了,但如果你想得到帮助,你应该解释什么不起作用。

NORMALIZE不会保留时区!

OffsetDateTime内部标识符没有以正确的格式持久化,它以UTC格式持久化,我丢失了我的时区
您使用的是hibernate-orm.mapping.timezone.default-storage=NORMALIZE,因此您得到的正是预期的行为:日期/时间标准化为UTC。
请参阅文档的此部分:
NORMALIZE不存储时区信息,只是将时间戳转换为UTC
如果你想保留时区,我建议你使用AUTO,它将使用一个原生的DB类型,如果可能的话,它将保留时区,否则将使用一个单独的时区列。

编辑后更新

您的配置缺少quarkus前缀?

quarkus: # This is missing in your snippet
  hibernate-orm:
    mapping:
      timezone:
        default-storage: "NORMALIZE"
    jdbc:
       timezone: "Europe/Paris"
    unsupported-properties:
      - "hibernate.type.json_format_mapper": "pathToMyMapper"

我实际上有我的日期的权利,因为时区是插入时,阅读从数据库感谢配置,但它不是持久的时区
好吧,这将是一个问题,因为你会失去更新的时区。
我重申一下:
如果你想保留时区,我建议你使用AUTO,它将使用一个原生的DB类型来保留时区,如果可能的话,或者一个单独的时区列。
关于你的格式Map器,对不起,但是我们离我的专业领域太远了,让我们回家有人插话告诉你你的实现中有什么问题。您可能需要显示CustomOffsetDateTimeSerializer的代码。

相关问题