首页 > 解决方案 > SpringBoot JPA 2.1 Converter 忽略 convertToDatabaseColumn

问题描述

我有以下转换器

import javax.persistence.AttributeConverter;
import javax.persistence.Converter;

@Converter(autoApply = true)
public class ImportedReasonConverter implements AttributeConverter<ImportedReason, String> {
    @Override
    public String convertToDatabaseColumn(final ImportedReason pImportedReason) {
        return pImportedReason.getValue();
    }

    @Override
    public ImportedReason convertToEntityAttribute(final String pImportedReason) {
        return ImportedReason.of(pImportedReason);
    }
}

由实体使用,例如

@Entity
@Table(
        name = "IMPORT_RECORD"
)
public class ImportRecordEntity implements Serializable {

    private static final long serialVersionUID = 2483327758356663412L;

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    @Column(name = "ID")
    private UUID id;

    @Column(name = "importedReason")
    private ImportedReason importedReason;

    public ImportedReason getImportedReason() {
        return importedReason;
    }

    public void setImportedReason(final ImportedReason importedReason) {
        this.importedReason = importedReason;
    }

{...}
}

在启动应用程序时,表由 Hibernate 创建,使用正确的列类型(这里:VARCHAR)。删除 autoApply=true 设置会导致启动失败 - 因此转换器本身会被识别。

但是:在保存带有设置为importedReason的值的实体时,我得到一个

Caused by: java.io.NotSerializableException: ImportedReason
    at java.base/java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1185)
    at java.base/java.io.ObjectOutputStream.defaultWriteFields(ObjectOutputStream.java:1553)
    at java.base/java.io.ObjectOutputStream.writeSerialData(ObjectOutputStream.java:1510)
    at java.base/java.io.ObjectOutputStream.writeOrdinaryObject(ObjectOutputStream.java:1433)
    at java.base/java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1179)
    at java.base/java.io.ObjectOutputStream.writeObject(ObjectOutputStream.java:349)
    at org.hibernate.internal.util.SerializationHelper.serialize(SerializationHelper.java:115)
    ... 43 more

尝试调试我的转换器,不会调用 ImportedReasonConverter.convertToDatabaseColumn(ImportedReason) 方法。因此,Hibernate 不会尝试写入 String 类型的值,而是输入 ImportedReason。

任何想法,为什么转换器不能正确使用?我已经使用 Java 8 + 11 和 Spring 2.1.5.RELEASE + 2.1.9.RELEASE (早期版本用于另一个项目)进行了尝试。我也尝试过使用其他一些转换器(例如内部类型 -> LocalDateTime),但我也有同样的问题。

非常感谢。斯特凡

标签: hibernatespring-bootconvertersjpa-2.1

解决方案


更新: 进一步调查显示,正在保存的实体已被全面分析,其转换器得到正确使用。 但是:如果该实体使用其他一些实体作为参考,而后者又使用要使用这些转换器转换的类型:那是它看到值但不使用转换器(出于某种原因)的时候。

因此,我在上面的 ImportRecordEntity 用于以下 PortfolioEntity,我实际上是在尝试保存它。保存 ImportRecordEntity 毫不费力。然后我将这个 ImportRecordEntity 实例(从保存方法返回)设置为 PortfolioEntity 实例并保存它。但是随后 Hibernate 崩溃了,因为它似乎分析了 PortfolioEntity 而不是 ImportRecordEntity ,它持有 ImportedReason - 所以它不知道 ImportedReasonConverter (参见 org.hibernate.event.internal.AbstractSaveEventListener.performSaveOrReplicate(Object, EntityKey, EntityPersister, boolean, Object, EventSource, boolean) - AbstractSaveEventListener.java:122 变量类型)。


@Entity
@Table(
        name = "PORTFOLIO"
)
public class PortfolioEntity implements Serializable {

    private static final long serialVersionUID = 3632725596750538287L;

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    @Column(name = "ID")
    private UUID id;

    @Column(name = "IMPORT_RECORD")
    private ImportRecordEntity importRecord;

{...}
}

推荐阅读