Search code examples
springspring-bootazurespring-dataazure-cosmosdb

Specify how LocalDateTime is stored in Azure CosmosDB for NoSQL


I have a spring boot project using azure cosmos db for nosql as the database, using CosmosRepository from spring-cloud-azure-starter-data-cosmos artifact. My entity looks like this:

import java.time.LocalDateTime;

import org.springframework.data.annotation.Id;

import com.azure.spring.data.cosmos.core.mapping.Container;
import com.azure.spring.data.cosmos.core.mapping.GeneratedValue;

import lombok.Data;

@Data
@Container
public class Post {
    @Id
    @GeneratedValue
    private String id;
    private String author;
    private String content;
    private String imageUrl;
    private LocalDateTime creationTime;
}

problem is, when persisting data, creationTime is for some reason stored as an array (example: "creationTime": [2024, 6, 16, 16, 51, 25, 571970017]), instead of an ISO string which I'd expect to be the default. This seemingly presents issues when using a repository method to sort posts by time (public List<Post> findAllByOrderByCreationTimeDesc();). Is there a way to specify that LocalDateTime be stored as an ISO string without changing creationTime to String and doing so manually? I have tried annotating creationTime with spring's @DateTimeFormat, seemingly to no avail.


Solution

  • Spring Data Azure Cosmos DB uses Jackson under the hood for serializing objects in Json format. It's Jackson's default behaviour which is resulting in dates being persisted as numerical arrays.

    Jackson does support a number of different annotations that let's it know how it should serialize input and format outout.

    Option 1 - Use an Annotation

    You can use the @JsonFormat annotation in your model class, specifying the recommended ISO 8601 format for Azure Cosmos DB.

    @Data
    @Container
    public class Post {
        @Id
        @GeneratedValue
        private String id;
        private String author;
        private String content;
        private String imageUrl;
        @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd'T'HH:mm:ss.fffffff'Z'")
        private LocalDateTime creationTime;
    }
    

    Option 2 - Override Default Behaviour in Application Properties

    If you prefer to override Jackson's default behaviour at application scope then you can do this in your application.properties or application.yml file.

    # Serialize dates as ISO 8601 strings
    spring.jackson.serialization.write-dates-as-timestamps=false
    spring.jackson.date-format=yyyy-MM-dd'T'HH:mm:ss.fffffff'Z'