【问题标题】:How to serialize and deserialize multi argument enum in Java using JPA 2.1 or lower (Postgres)如何使用 JPA 2.1 或更低版本 (Postgres) 在 Java 中序列化和反序列化多参数枚举
【发布时间】:2021-03-26 18:08:45
【问题描述】:

    public enum CameraType {
    
    CAMERA(false, false, "External lens ", ""),
    
    
    CameraType{
                boolean collector,
                boolean hidden,
                String description
            ) {
            this.collector = collector;
            this.granular = hidden;
            this.description = description;
            } // end ctor
           
           public void setHide(boolean hidden) {
               this.hide = hidden;
           }
    
    } // end enum

我的 CameraType 实例很少。

我有一个 "hidden" 属性的设置器,它在特定条件下设置为真或假。

现在我用 SecurityEntity 中的几个其他字段序列化 CameraType。

```
@Entity
@Table
public class Security {

 Few more fields...

@Enumerated(EnumType.STRING)
    @Column(nullable = false)
private CameraType cameraType

And other fields...
}
```

当我反序列化“隐藏”字段的值时,总是假的。如果我理解正确,在反序列化过程中会调用 ctor 并分配默认值。

有没有办法在每个 CameraType 实例反序列化后保留“隐藏”字段的值(真或假)。

我正在使用 Postgres DB 10。

enter code here

请帮忙。我没有线索。

【问题讨论】:

  • 你不能这样做,你不应该这样做,枚举是具有预定义实例的最终类,你不应该像上面那样改变它的属性。

标签: java jpa enums deserialization postgres-10


【解决方案1】:

根据定义,枚举是固定集合的不可变元素。因此,要表示一个枚举值,您只需要它的名称。这正是 JPA 在序列化/反序列化期间所做的。

您试图违反规则。虽然 Java 允许您将枚举几乎视为普通对象,但 JPA 会根据它们应该是什么来处理它们。这就是您的代码不起作用的原因。

您可以:

  • CameraType 制作成一个类并将其序列化,或者
  • CameraType 拆分为两部分,例如enum CameraType(不可变)和class CameraConfig(包含所有可变字段)

【讨论】:

  • 谢谢 jurez,这有帮助。
【解决方案2】:

前一个答案是正确的:枚举必须是不可变的,将部分分成不可变和可变数据是一个不错的选择。

这里有一个补充:使用枚举值进行数据库存储通常不是一个好的选择,因为当另一个开发人员决定重构枚举名称并且您在此之后从数据库中读取旧条目时,您会遇到一个崩溃的应用程序...

所以我建议使用javax.persistence.AttributeConverter 以特定的方式反序列化/序列化枚举并重命名保存方式。

这是一个非常简单的示例,其中包含一个名为 MyDefinition 的枚举:

enum MyDefinition{

   ONE("def_one"),
   TWO"def_two"),
   THREE("def_three"),
   
   ;
   
   private String id;

   private MyDefinition(String id){
      this.id=id;
   }

   public String getId(){
      return id;
   }

    public static MyDefinition fromId(String id) {
        for (MyDefinition definition : MyDefinition.values()) {
            if (definition.id.equals(id)) {
                return definition;
            }
        }
        return null;
    }


}

这里是转换器:

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

@Converter(autoApply = true)
public class MyDefinitionAttributeConverter implements AttributeConverter<MyDefinition, String> {

    @Override
    public String convertToDatabaseColumn(MyDefinition attribute) {
       if (attribute == null){
           return null;}
       }
       return attribute.getId();
    }

    @Override
    public MyDefinition convertToEntityAttribute(String dbData) {
        return MyDefinition.fromId(dbData);
    }
 
 

所以我们可以使用数据库的 id。在读取旧数据时,重命名枚举名称将不再导致应用程序崩溃。

【讨论】:

    猜你喜欢
    • 2021-11-30
    • 1970-01-01
    • 1970-01-01
    • 2021-11-28
    • 2014-08-10
    • 1970-01-01
    • 1970-01-01
    • 2013-05-20
    • 1970-01-01
    相关资源
    最近更新 更多