spring-data-rest
spring-data-rest copied to clipboard
Mongo Auditing: @CreatedDate field gets set to null on updates with Spring Data Rest [DATAREST-1204]
Benjamin Cody opened DATAREST-1204 and commented
I've set up a Spring Boot application with spring-boot-starter-data-rest
and spring-boot-starter-data-mongodb
. I'm using the Mongo auditing feature to automatically set insert and update timestamps on my records using the @CreatedDate
and @LastModifiedDate
annotations.
I'm using the generated REST/HAL endpoint to insert and update records. When I insert a record, its insert and update timestamp both get set to the current time, as expected. However, when I perform an update, the insert timestamp get overwritten with null! :( The update timestamp gets updated correctly (as does the @Version
annotated field).
This issue occurs when I have public getters/setters for my insert/update fields. When I remove those getters/setters, the fields get written as I would expect: the insert timestamp only gets written once on inserts and doesn't change on updates, and the update timestamp always gets written. With the @Version
annotated field, it doesn't matter whether or not I have a public getter/setter: the version is never output by the REST endpoint and also cannot be set explicitly by the client.
I prepared a minimal project with a test which shows this scenario: https://github.com/bencody/spring_data_mongo_createddate
Affects: 2.6.10 (Ingalls SR10)
Reference URL: https://github.com/bencody/spring_data_mongo_createddate
2 votes, 4 watchers
Benjamin Cody commented
Note: instead of removing the public getter/setter of the @CreatedDate
field, adding the @JsonIgnore
annotation also prevents it from being set to null on updates. That's what I'm currently doing as a work-around. Obviously the data isn't output via REST by doing that, but that's OK for me
Keats commented
Note : @ReadOnlyProperty
doesn't help (it works on JPA entities though)
It appears there is no way to make it work while exposing the values to the client.
Note 2 : It obviously works well without SDR: just findOne, then update the fields.
Workaround : Write all controllers yourself and ditch SDR
Oliver Drotbohm commented
tl;dr: @JsonIgnoreProperties(value={ … }, allowGetters=true)
should do the trick and whether a value gets serialized or deserialized for a simple property is purely a matter of your Jackson setup.
I don't even think this is an issue Spring Data REST should care about. A property annotated with @CreatedDate
is a regular property, i.e. no special handling gets applied in the first place, which means that you have all Jackson customization means in place to make sure it handles it as you expect. A quick Google search revealed this comment by the Jackson maintainer
A more targeted Jackson solution is to annotate just the single field as being read-only:
@JsonProperty(access = JsonProperty.Access.READ_ONLY)
@CreatedDate
private Instant createdDate;
you can make that variable editable = false like this exemple
@Column(name = "creationDate", nullable = false, updatable = false)
The issue is more general and not related to mongo. The same behaviour happens with other DBs (e.g. postgreSQL). As suggested by @boo3lem a quick fix is to set the column as not updatable. The expected behaviour should be the following:
when a column is annotated with @CreatedDate
the column should be filled on inserts and skipped on updates
I observe a similar behavior with postgres. I have an entity like the following:
@Getter
@NoArgsConstructor
@AllArgsConstructor
@Entity
@Table
@EntityListeners(AuditingEntityListener.class)
public class MyObject {
@Id
private String myId;
@CreatedDate
@Column(name = "created_date", updatable = false)
private LocalDateTime createdDate;
private boolean myBoolean;
}
The table is created fine by the service.
The records are updated fine by the service.
However, if I edit a record manually and update the myBoolean
property, then when the service reads the records the createdDate
attribute is null, despite the fact that in the db I can see that this is not the case.
Up issue. I have this problem too
In my case, createdDate is null when I provide an ID. It only gets populated when I allow Mongo to generate an ID