简体   繁体   English

在Spring Boot应用程序上的JPA(加上Jackson)中坚持“计算”字段

[英]Persist “computed” field in JPA (plus Jackson) on Spring Boot application

I have a JPA entity that looks like: 我有一个JPA实体,看起来像:

public final class Item implements Serializable {
  @Column(name = "col1")
  private String col1;

  @Column(name = "col2")
  @JsonProperty(access = JsonProperty.Access.WRITE_ONLY)
  private String col2;

  @Column(name = "col3")
  private String col3;

  Item() { }

  public Item(String col1, String col2) {
    this.col1 = col1;
    this.col2 = col2;
    col3 = col1 + col2 + "some other stuff";
  }

  // getters, equals, hashCode and toString
}

I would like to be able to persist col3 . 我希望能够坚持col3 I'm sending a request via POST that looks like: 我正在通过POST发送请求,如下所示:

{
  "col1": "abc",
  "col2": "def"
}

...and I'm receiving something like this: ...而我收到的是这样的:

[
    {
        "createdAt": "2017-09-07T19:18:17.04-04:00",
        "updatedAt": "2017-09-07T19:18:17.04-04:00",
        "id": "015e5ea3-0ad0-4703-af04-c0a3d46aa836",
        "col1": "abc",
        "col3": null
    }
]

Eventually, col3 is not being persisted in the database. 最终, col3不会col3在数据库中。 I don't have any setters. 我没有二传手。

Is there any way to achieve this? 有什么办法可以做到这一点?

UPDATE 更新

The accepted solution is the "less intrusive" one. 公认的解决方案是“较少干扰”的解决方案。 The proposed one from Jarrod Roberson also works flawlessly. Jarrod Roberson提出的建议也可以完美地工作。 And eventually, you can achieve the same by using a setter on col2 and set the value of col3 there — but I dislike this one...although a personal preference. 最终,您可以通过在col2上使用setter并在那里设置col3的值来实现相同的目的,但是我不喜欢这个……尽管个人喜好。

The reason why this is not persisted is because the constructor you have provided with col1 and col2 properties is never really called. 之所以不能持续下去,是因为从未真正调用过您提供的带有col1col2属性的构造函数。 When spring does the mapping (with help of jackson) from the JSON you send to the server it uses the default constructor to create the object and then calls the setters(sometimes through reflection) to set the values. 当spring从您发送到服务器的JSON中映射(借助jackson)时,它使用默认构造函数创建对象,然后调用setter(有时通过反射)来设置值。 Therefore the value that is stored in the db for col3 is always null. 因此, col3的数据库中存储的值始终为空。 See Jarrod Roberson's answer how to solve it :). 请参阅Jarrod Roberson的答案如何解决它:)。

What you are looking for is @JsonCreator it is used like this: 您正在寻找的是@JsonCreator它的用法如下:

@JsonCreator()
public Item(@JsonProperty("col1") String col1, @JsonProperty("col2") String col2) {
  this.col1 = col1;
  this.col2 = col2;
  this.col3 = col1 + col2 + "some other stuff";
}

Then remove the default no-args constructor and Jackson will use this one and what you want will happen auto-magically . 然后删除默认的no-args构造函数,Jackson将使用此构造函数,您想要的将自动进行

This is a very old feature back from the 1.x era. 这是1.x时代的一项非常古老的功能 You can also annotate a static Factory Method instead and make the constructor private for cases where you need to use more complicated logic like something that is constructed with a Builder Pattern . 您还可以注释static 工厂方法 ,并使构造函数private以用于需要使用更复杂的逻辑(例如使用“ 构建器模式”构造的事物)的情况。

Here is an example: 这是一个例子:

@JsonCreator()
public static Item construct(@JsonProperty("col1") String col1, @JsonProperty("col2") String col2) {
  return new Item(col1, col2, col1 + col2 + "some other stuff");
}

private Item(final String col1, final String col2, final String col3) {
  this.col1 = col1;
  this.col2 = col2;
  this.col3 = col3;
}

While there is an accepted answer it seems overly complex and requires the removal of the default constructor which is in violation of the JPA spec. 尽管有一个可以接受的答案,但它似乎过于复杂,需要删除违背JPA规范的默认构造函数。

Section 2.1 第2.1节

The entity class must have a no-arg constructor. 实体类必须具有no-arg构造函数。 The entity class may have other constructors as well. 实体类也可以具有其他构造函数。 The no-arg constructor must be public or protected. 无参数构造函数必须是公共的或受保护的。

There is no need to get Jackson involved here. 无需让Jackson参与其中。 You can simply use a JPA pre-persist listener to ensure col3 is set before the flush operation 您可以简单地使用JPA预持久侦听器来确保在刷新操作之前已设置col3

https://docs.jboss.org/hibernate/orm/4.0/hem/en-US/html/listeners.html https://docs.jboss.org/hibernate/orm/4.0/hem/zh-CN/html/listeners.html

public final class Item implements Serializable {
  @Column(name = "col1")
  private String col1;

  @Column(name = "col2")
  @JsonProperty(access = JsonProperty.Access.WRITE_ONLY)
  private String col2;

  @Column(name = "col3")
  private String col3;

  Item() { }

  @PrePersist
  public void updateCol3(){
      col3 = col1 + col2;
  }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM