I have a JPA entity that looks like:
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
. I'm sending a request via POST that looks like:
{
"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. 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. 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.
The reason why this is not persisted is because the constructor you have provided with col1
and col2
properties is never really called. 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. Therefore the value that is stored in the db for col3
is always null. See Jarrod Roberson's answer how to solve it :).
@JsonCreator
it is used like this: @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 .
This is a very old feature back from the
1.x
era. You can also annotate astatic
Factory Method instead and make the constructorprivate
for cases where you need to use more complicated logic like something that is constructed with a Builder Pattern .
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.
Section 2.1
The entity class must have a no-arg constructor. 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. You can simply use a JPA pre-persist listener to ensure col3 is set before the flush operation
https://docs.jboss.org/hibernate/orm/4.0/hem/en-US/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;
}
}
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.