如何使用JPA和Hibernate自动序列化和反序列化JSON字符串?

时间:2012-08-14 08:55:19

标签: json hibernate jpa orm jackson

我有数据类/表“用户”,其中包含“首选项”

CREATE table "user"; 
ALTER TABLE "user" ADD COLUMN preferences TEXT;

首选项类型是TEXT,我在那里存储JSON。

public class User extends AbstractEntity{
public String preferences;
}

因此user.preferences值为"{notifyByEmail:1, favouriteColor:"blue" }"

如何用一些注释包装它,以便我可以像

一样访问它
user.preferences.notifyByEmail

或者无需包装到数据对象

user.preferences.get("notifByEmail");
user.preferences.set("notifByEmail",true);

我想可能会有一些杰克逊注释可以添加到字段中 像

@JsonGenerate
public String preferences;

我对JPA相当新,文档很陡。

我相信我的情况很常见。任何人都可以提供任何例子吗?

4 个答案:

答案 0 :(得分:11)

可以使用JPA Converter实现此目的。

实体;

    Toolbar toolbar = (Toolbar) findViewById(R.id. toolbar_target_ranges);

    LinearLayout toolbarRow = (LinearLayout) toolbar.findViewById(R.id. target_ranges_layout_main);

    toolbarRow.setLayoutParams(new Toolbar.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT, Gravity.CENTER));

转换器:

@Id
@GeneratedValue
Long id;

@Column(name = "mapvalue")
@Convert(converter = MapToStringConverter.class)
Map<String, String> mapValue;

保存数据:

@Converter
public class MapToStringConverter implements AttributeConverter<Map<String, String>, String> {

    ObjectMapper mapper = new ObjectMapper();

    @Override
    public String convertToDatabaseColumn(Map<String, String> data) {
        String value = "";
        try {
            value = mapper.writeValueAsString(data);
        } catch (JsonProcessingException e) {
            e.printStackTrace();
        }
        return value;
    }

    @Override
    public Map<String, String> convertToEntityAttribute(String data) {
        Map<String, String> mapValue = new HashMap<String, String>();
        TypeReference<HashMap<String, Object>> typeRef = new TypeReference<HashMap<String, Object>>() {
        };
        try {
            mapValue = mapper.readValue(data, typeRef);
        } catch (IOException e) {
            e.printStackTrace();
        }
        return mapValue;
    }

}

该值将作为

存储在DB中
Map<String, String> mapValue = new HashMap<String, String>();
mapValue.put("1", "one");
mapValue.put("2", "two");
DataEntity entity = new DataEntity();
entity.setMapValue(mapValue);
repo.save(entity);

答案 1 :(得分:5)

老实说,我认为您最好的解决方案是为您的房产创建一个单独的表格(首选项)。

+------------+
| preference |
+------------+---------+------+-----+
| Field      | Type    | Null | Key |
+------------+---------+------+-----+
| user_id    | bigint  | NO   | PRI |
| key        | varchar | NO   | PRI |
| value      | varchar | NO   |     |
+------------+---------+------+-----+

您可以在您的实体中将其映射到这样:

@Entity
public class User
{
    @Id
    private Long id;

    @ElementCollection
    @MapKeyColumn(name = "key")
    @Column(name = "value")
    @CollectionTable(name = "preference",
        joinColumns = @JoinColumn(name = "user_id"))
    private Map<String, String> preferences;
}

通过这种方式,您的数据库更加规范化,您不必愚弄“创造性解决方案”,例如将首选项存储为JSON。

答案 2 :(得分:2)

如果你真的需要这样的东西,最值得推荐的是下一个:

public class User extends AbstractEntity{
  @JsonIgnore //This variable is going to be ignored whenever you send data to a client(ie. web browser)
  private String preferences;

  @Transient //This property is going to be ignored whenever you send data to the database
  @JsonProperty("preferences") //Whenever this property is serialized to the client, it is going to be named "perferences" instead "preferencesObj"
  private Preferences preferencesObj;

  public String getPreferences() {
    return new ObjectMapper().writeValueAsString(preferencesObj);
  }

  pbulic void setPreferneces(String preferences) {
    this.preferences = preferences;
    this.preferncesObj = new ObjectMapper().readValue(preferences, Preferences.class);
  }

  pubilc Preferences getPreferencesObj() {
    return preferencesObj;
  }

  public void setPreferencesObj(Preferences preferencesObj) {
    this.preferencesObj = preferencesObj;
  }
}

附加说明:

  • 也许私有财产&#34;偏好&#34;可以删除,只使用getter和setter。
  • 我还没有测试过这段代码。
  • 以上代码旨在使用Jackson ObjectMapper和Hibernate模块。

答案 3 :(得分:1)

正如我在this article中所解释的那样,使用Hibernate持久化JSON对象非常容易。

  

您不必手动创建所有这些类型,您可以简单地获取   它们通过Maven Central使用以下依赖项:

<dependency>
    <groupId>com.vladmihalcea</groupId>
    <artifactId>hibernate-types-52</artifactId>
    <version>${hibernate-types.version}</version> 
</dependency> 
     

有关详细信息,请查看hibernate-types open-source project

现在,您需要在类级别或 package-info.java 包级别描述符中声明新类型:

@TypeDef(
    name = "jsonb-node", 
    typeClass = JsonNodeBinaryType.class
)

实体映射将如下所示:

@Type(type = "json-node")
@Column(columnDefinition = "json")
private JsonNode preferences;

那就是它!