Mongo Auditing: @CreatedDate field gets set to null on updates with Spring Data Rest
  • 04-Jun-2023
Lightrun Team
Author Lightrun Team
Share
Mongo Auditing: @CreatedDate field gets set to null on updates with Spring Data Rest

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

Lightrun Team
Lightrun Team
04-Jun-2023

Explanation of the problem

In the JIRA issue DATAREST-1204, Benjamin Cody reported an issue with a Spring Boot application that utilizes the spring-boot-starter-data-rest and spring-boot-starter-data-mongodb dependencies. The application makes use of the Mongo auditing feature, which automatically sets insert and update timestamps on records using the @CreatedDate and @LastModifiedDate annotations.

The problem arises when performing updates on records using the generated REST/HAL endpoint. While inserting a record correctly sets both the insert and update timestamps to the current time, updating a record causes the insert timestamp to be overwritten with null, while the update timestamp is updated correctly. This unexpected behavior occurs when there are public getters/setters defined for the insert and update fields. However, removing these getters/setters resolves the issue, and the fields are written as expected, with the insert timestamp being written only once during inserts and remaining unchanged during updates. Interestingly, the @Version annotated field is not affected by the presence of public getters/setters, as it is neither output by the REST endpoint nor can be set explicitly by the client.

To demonstrate this scenario, Benjamin Cody has provided a minimal project with a test case, which can be found at the following GitHub repository: https://github.com/bencody/spring_data_mongo_createddate. The issue affects version 2.6.10 (Ingalls SR10) of the mentioned dependencies.

This problem highlights an inconsistency in the behavior of the Spring Boot application when using the Mongo auditing feature and public getters/setters for insert and update fields. By examining the provided GitHub project and analyzing the behavior of the REST/HAL endpoint, the Spring Boot application can be investigated to identify the root cause and potential solutions to ensure the proper handling of timestamps during updates.

 

Troubleshooting with the Lightrun Developer Observability Platform

Getting a sense of what’s actually happening inside a live application is a frustrating experience, one that relies mostly on querying and observing whatever logs were written during development.
Lightrun is a Developer Observability Platform, allowing developers to add telemetry to live applications in real-time, on-demand, and right from the IDE.

  • Instantly add logs to, set metrics in, and take snapshots of live applications
  • Insights delivered straight to your IDE or CLI
  • Works where you do: dev, QA, staging, CI/CD, and production

Start for free today

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

To solve the problem described in the issue, the following steps can be taken:

  1. Review the Entity Mapping: Examine the entity mapping and ensure that the @CreatedDate and @LastModifiedDate annotations are correctly applied to the respective fields in the entity class. Verify that the annotations are placed on the appropriate fields and that the field types are compatible with the timestamp values.

 

import org.springframework.data.annotation.CreatedDate;
import org.springframework.data.annotation.LastModifiedDate;

@Entity
public class YourEntity {

    @CreatedDate
    private Date createdDate;

    @LastModifiedDate
    private Date lastModifiedDate;

    // Rest of the entity definition
    // ...
}

 

  1. Check Getter and Setter Methods: If public getters and setters are present for the insert and update fields, review them to ensure they are correctly implemented. Pay attention to any custom logic that may modify the values of these fields during updates. Consider removing the public getters/setters and allowing Spring Data to handle the assignment of timestamps automatically.

 

// Remove public getters and setters for insert and update fields
public class YourEntity {

    @CreatedDate
    private Date createdDate;

    @LastModifiedDate
    private Date lastModifiedDate;

    // Rest of the entity definition
    // ...
}

 

  1. Test and Verify Behavior: After making the necessary changes, retest the application to ensure that the insert and update timestamps are handled correctly. Perform insert and update operations through the REST/HAL endpoint and verify that the timestamps are set appropriately without any unintended overwriting or null values.

By carefully reviewing the entity mapping, adjusting the presence of public getters/setters, and conducting thorough testing, the issue should be resolved, and the insert and update timestamps should be managed correctly within the Spring Boot application using the Mongo auditing feature.

 

Other popular problems with spring-data-rest

  1. Circular Reference Serialization Error: Problem Description: When working with entities that have bidirectional relationships, such as a parent-child relationship, Spring Data REST may encounter a circular reference serialization error. This occurs when serializing the entities to JSON and can lead to an infinite loop or incomplete serialization.

Solution: To resolve this issue, you can use Jackson’s @JsonIgnoreProperties annotation to exclude the circularly referenced properties during serialization. Here’s an example:

@Entity
public class Parent {

    // Other fields and annotations
    
    @OneToMany(mappedBy = "parent")
    @JsonIgnoreProperties("parent")
    private List<Child> children;
    
    // Getters and setters
}

@Entity
public class Child {

    // Other fields and annotations
    
    @ManyToOne
    @JsonIgnoreProperties("children")
    private Parent parent;
    
    // Getters and setters
}

 

By annotating the circularly referenced properties with @JsonIgnoreProperties, Spring Data REST will exclude those properties during serialization, avoiding the circular reference error.

  1. Customizing Endpoint Paths: Problem Description: Spring Data REST generates default endpoint paths based on entity names, which may not always align with the desired API structure. Developers may want to customize the endpoint paths to better match their application’s requirements.

Solution: To customize the endpoint paths, you can use the @RepositoryRestResource annotation on the repository interface associated with the entity. Here’s an example:

 

@RepositoryRestResource(path = "custom-entities")
public interface CustomEntityRepository extends JpaRepository<CustomEntity, Long> {
    // Custom repository methods
}

 

In this example, the @RepositoryRestResource annotation is used with the path attribute set to “custom-entities”. This will change the endpoint path for the CustomEntity to “/custom-entities” instead of the default path based on the entity name.

  1. Handling Pagination and Sorting: Problem Description: When working with large collections of entities, it becomes important to handle pagination and sorting efficiently. Spring Data REST provides support for pagination and sorting out of the box, but developers may encounter challenges in configuring and using these features effectively.

Solution: To enable pagination and sorting for an endpoint, you can use the PagingAndSortingRepository interface provided by Spring Data. Here’s an example:

 

@RepositoryRestResource
public interface ProductRepository extends PagingAndSortingRepository<Product, Long> {
    // Repository methods
}

 

By extending the PagingAndSortingRepository interface, you gain access to methods for pagination and sorting, such as findAll(Pageable pageable) and findAll(Sort sort). Additionally, Spring Data REST automatically exposes these features through the generated REST endpoints. Clients can use query parameters like page, size, sort, etc., to control the pagination and sorting behavior of the API.

By addressing circular reference serialization errors, customizing endpoint paths, and handling pagination and sorting effectively, developers can overcome some of the common challenges encountered while using Spring Data REST. These solutions help ensure a smooth and tailored experience when building RESTful APIs with Spring Data.

 

A brief introduction to spring-data-rest

Spring Data REST is a powerful framework that simplifies the development of RESTful APIs by combining the capabilities of Spring Data and Spring MVC. It provides a convenient way to expose CRUD operations and query endpoints for entities in a Spring Data repository. With Spring Data REST, developers can quickly create a fully functional API with minimal boilerplate code and benefit from automatic resource mapping, content negotiation, and hypermedia support.

At its core, Spring Data REST leverages the concepts of HATEOAS (Hypermedia as the Engine of Application State) to enrich the API responses with links and metadata, enabling clients to navigate and discover related resources. It automatically generates RESTful endpoints for each repository, following REST conventions. For example, given a Person entity and its corresponding repository, Spring Data REST automatically exposes endpoints such as /persons for retrieving all persons, /persons/{id} for retrieving a specific person, and /persons/search for executing custom queries.

In addition to basic CRUD operations, Spring Data REST provides advanced features such as pagination, sorting, filtering, and projection out of the box. These features can be easily customized and extended to meet specific requirements. With pagination, for example, clients can request a specific page size and navigate through large result sets efficiently. Sorting allows clients to specify the desired ordering of the results, and filtering enables them to narrow down the data based on specific criteria. Moreover, Spring Data REST supports projections, which allow clients to retrieve a subset of properties from an entity, reducing network overhead and improving performance. Overall, Spring Data REST empowers developers to build robust and discoverable RESTful APIs with ease.

 

Most popular use cases for spring-data-rest

    1. Exposing Data Entities as RESTful Resources: Spring Data REST allows developers to expose their data entities as RESTful resources with minimal effort. By simply annotating the repository interfaces with the @RepositoryRestResource annotation, Spring Data REST automatically generates RESTful endpoints for the entities. For example, consider a Customer entity with a corresponding repository interface:

 

@RepositoryRestResource
public interface CustomerRepository extends JpaRepository<Customer, Long> {
    // Custom query methods
}

 

With this setup, Spring Data REST automatically exposes endpoints such as /customers for retrieving all customers, /customers/{id} for retrieving a specific customer, and /customers/search for executing custom queries.

  1. Customizing API Endpoints and Querying: Spring Data REST provides flexibility in customizing API endpoints and querying data. Developers can define custom query methods in the repository interface and expose them as RESTful endpoints. For instance, suppose we want to retrieve all customers with a specific last name:

 

@RepositoryRestResource
public interface CustomerRepository extends JpaRepository<Customer, Long> {
    List<Customer> findByLastName(@Param("lastName") String lastName);
}

 

With this custom query method, Spring Data REST generates an endpoint /customers/search/findByLastName that can be used to retrieve customers based on the provided last name. This allows clients to perform fine-grained queries against the exposed data.

  1. Enabling HATEOAS and Hypermedia Support: Spring Data REST embraces the principles of HATEOAS and provides hypermedia support in API responses. By including hypermedia links and metadata in the API responses, clients can navigate and discover related resources dynamically. Spring Data REST automatically generates hypermedia links for relationships between entities, allowing clients to follow links and traverse the API. Here’s an example of how hypermedia links can be included in the API response:

 

{
  "firstName": "John",
  "lastName": "Doe",
  "_links": {
    "self": {
      "href": "http://example.com/customers/1"
    },
    "orders": {
      "href": "http://example.com/customers/1/orders"
    }
  }
}

 

In this response, the _links field provides links to the current resource (self) and related resources (orders). This hypermedia support enhances the discoverability and navigability of the API, making it easier for clients to interact with the exposed data entities.

 

Share

It’s Really not that Complicated.

You can actually understand what’s going on inside your live applications.

Try Lightrun’s Playground

Lets Talk!

Looking for more information about Lightrun and debugging?
We’d love to hear from you!
Drop us a line and we’ll get back to you shortly.

By submitting this form, I agree to Lightrun’s Privacy Policy and Terms of Use.