spring-data-rest icon indicating copy to clipboard operation
spring-data-rest copied to clipboard

Mongo Auditing: @CreatedDate field gets set to null on updates with Spring Data Rest [DATAREST-1204]

Open spring-projects-issues opened this issue 8 years ago • 12 comments

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

spring-projects-issues avatar Feb 09 '17 13:02 spring-projects-issues

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

spring-projects-issues avatar Feb 09 '17 13:02 spring-projects-issues

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

spring-projects-issues avatar Feb 23 '18 14:02 spring-projects-issues

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

spring-projects-issues avatar Feb 23 '18 15:02 spring-projects-issues

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;

mjustin avatar Jan 14 '21 23:01 mjustin

you can make that variable editable = false like this exemple

@Column(name = "creationDate", nullable = false, updatable = false)

boo3lem avatar Jun 23 '21 08:06 boo3lem

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

SimoneGiusso avatar Jun 15 '22 10:06 SimoneGiusso

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.

v-dimi avatar Dec 08 '22 14:12 v-dimi

Up issue. I have this problem too

lamponyuh avatar Oct 10 '23 15:10 lamponyuh

In my case, createdDate is null when I provide an ID. It only gets populated when I allow Mongo to generate an ID

cybersokari avatar May 09 '24 06:05 cybersokari