Укажите, как LocalDateTime хранится в Azure CosmosDB для NoSQL

У меня есть проект весенней загрузки, использующий базу данных Azure Cosmos для nosql в качестве базы данных, используя артефакт CosmosRepository из spring-cloud-azure-starter-data-cosmos. Моя сущность выглядит так:

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;
}

проблема в том, что при сохранении данных creationTime по какой-то причине сохраняется как массив (пример: "creationTime": [2024, 6, 16, 16, 51, 25, 571970017]), а не строка ISO, которая, как я ожидаю, будет использоваться по умолчанию. По-видимому, это создает проблемы при использовании метода репозитория для сортировки сообщений по времени (public List<Post> findAllByOrderByCreationTimeDesc();). Есть ли способ указать, что LocalDateTime будет храниться как строка ISO, не меняя creationTime на String и делая это вручную? Я пробовал комментировать creationTime с помощью весеннего @DateTimeFormat, но, похоже, безрезультатно.

Где вы видите числовой массив? В Cosmos DB или с помощью отладчика/инспектора? Пробовали ли вы получить эти данные обратно из Cosmos и распечатать их значение? Казалось бы, в рамках существует проблема с сериализацией, но я просто хотел проверить, не видите ли вы это только в инспекторе?

Architect Jamie 16.06.2024 21:45

@ArchitectJamie Это числовой массив внутри самой Cosmos DB при запросе элементов контейнера.

Overdrowsed 16.06.2024 23:39

Интересный. Можете ли вы опубликовать код, который используете для записи своего объекта в Cosmos? В большинстве случаев Java неявно вызывает toString() для LocalDateTime, создавая строку ISO 8601, но может показаться, что сериализатор не делает этого.

Architect Jamie 17.06.2024 00:22

@ArchitectJamie Я использую CosmosRepository и его метод save(), без специального кода

Overdrowsed 17.06.2024 00:30

Я проверил исходный код SDK и увидел, что Джексон используется для сериализации в JSON. Я опубликовал ответ для вас. Надеюсь, это сработает. Дайте мне знать, если он нуждается в доработке.

Architect Jamie 17.06.2024 02:03
1
5
68
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Spring Data Azure Cosmos DB использует Джексона для сериализации объектов в формате Json. Это поведение Джексона по умолчанию, которое приводит к тому, что даты сохраняются в виде числовых массивов.

Джексон поддерживает ряд различных аннотаций, которые позволяют ему узнать, как следует сериализовать ввод и форматировать вывод.

Вариант 1. Используйте аннотацию

Вы можете использовать аннотацию @JsonFormat в классе модели, указав рекомендуемый формат ISO 8601 для 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;
}

Вариант 2. Переопределить поведение по умолчанию в свойствах приложения.

Если вы предпочитаете переопределить поведение Джексона по умолчанию в области приложения, вы можете сделать это в своем файле application.properties или application.yml.

# 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'

Вариант первый работает, спасибо. Не уверен насчет второго, поскольку сериализация дат в виде строк уже кажется значением по умолчанию для Spring (при проверке запросов REST), я предполагаю, что пакет Azure имеет где-то отдельную конфигурацию для Джексона.

Overdrowsed 17.06.2024 16:32

@Overdrowsed Скорее всего, ты прав. Почему они сделали это, если это означает, что вы не можете использовать встроенные функции даты Cosmos, остается загадкой.

Architect Jamie 17.06.2024 16:48

@Overdrowsed Я копнул немного глубже и обнаружил, что есть специальные условия для правильного форматирования объектов ZonedDateTime, но не LocalDateTime. Я думаю, вместо этого вы могли бы использовать зонирование, поскольку информация о зонировании удалена из формата, но это похоже на недосмотр со стороны разработчиков.

Architect Jamie 17.06.2024 17:09

На данный момент @JsonFormat работает достаточно хорошо, я могу заменить на ZonedDateTime или, возможно, в будущем создать проблему на github, спасибо за вашу помощь

Overdrowsed 18.06.2024 00:24

Другие вопросы по теме