Запрос, отправленный клиентом, был синтаксически неверным. Серверная часть Java ZonedDateTime

Я надеюсь получить помощь в устранении этой проблемы. Если я отправлю следующий JSON на свой сервер, он будет работать правильно:

{
    "approvalRequired": false,
    "location": {
        "locationName": "<+37.33233141,-122.03121860> +/- 5.00m (speed 0.00 mps / course -1.00) @ 9/16/18, 9:24:59 PM Pacific Daylight Time",
        "longitude": -122.0312186,
        "latitude": 37.332331410000002
    }
}

Однако, если я сейчас пришлю следующее:

{
    "approvalRequired": false,
    "scheduledStartTime": "2016-01-01T10:24:00+01:00",
    "location": {
        "locationName": "<+37.33233141,-122.03121860> +/- 5.00m (speed 0.00 mps / course -1.00) @ 9/16/18, 9:24:59 PM Pacific Daylight Time",
        "longitude": -122.0312186,
        "latitude": 37.332331410000002
    }
}

Я получаю указанную выше ошибку. В моем бэкэнд-коде есть следующее:

@DynamoDBTypeConverted(converter = ZonedDateTimeTypeConverter.class)
@DynamoDBAttribute(attributeName = "scheduledStartTime")
public ZonedDateTime scheduledStartTime;

А подпись метода API выглядит так:

@RequestMapping(method = RequestMethod.POST)
public ResponseEntity create(@RequestBody Event event) {...}

Я считаю, что проблема в том, что JSON не может быть проанализирован на ZonedDateTime. Есть ли у кого-нибудь совет относительно того, (1) какое время формата строки json ZonedDateTime автоматически принимает или (2) как заставить DTO анализировать зонированное время даты?

Спасибо!

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

fgamess 17.09.2018 07:18

Конечно. Что конкретно вы ищете? Предположим, Spring MVC. Меня больше интересует понимание того, как отладить это, просто получение ответа ..

Alex Kornhauser 18.09.2018 00:50

Непонятно, как реализован ваш ZonedDateTimeTypeConverter (пожалуйста, покажите достаточно информации), но обычно ZonedDateTime не принимает что-то вроде 558851094.57158995. Попробуйте отправить строку типа "2007-12-03T10:15:30+01:00[Europe/Paris]", как в документ ZonedDateTime.

OOPer 18.09.2018 04:14

Если я буквально попробую эту точную строку, она тоже не сработает: {"subscriptionRequired": false, "duledStartTime ":" 2007-12-03T10: 15: 30 + 01: 00 [Europe \ / Paris] "," location " : {"locationName": "<+ 37.33233141, -122.03121860> + \ / - 5,00 м (скорость 0,00 м / с \ / курс -1,00) @ 19/9/18, 12:16:05 PM Pacific Daylight Time", "долгота": -122.0312186, "широта": 37.332331410000002}}

Alex Kornhauser 19.09.2018 21:17

@AlexKornhauser, какой парсер вы используете, не могли бы вы предоставить часть конфигурации Spring для этого? И если вы не возражаете, сообщите нам также версию Spring, используемую на вашей стороне.

marme1ad 23.09.2018 04:38

Что такое «вышеуказанная ошибка»? Содержимое ZonedDateTimeTypeConverter.java?

Mumrah81 24.09.2018 13:54

Попробуйте 2015-09-22T19: 58: 22.947Z

Amit Parashar 24.09.2018 20:35

Это не вопрос Swift, это вопрос Java.

Cristik 26.09.2018 07:06
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
9
8
394
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

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

Решение:

Предположим, вы используете наиболее "стандартную" конфигурацию, основанную на FasterXML Джексон.

Если это так, то вам просто нужно правильно настроить сериализатор и десириализатор для ZonedDateTime в вашем приложении; и это могут быть либо пользовательские, либо из Джексон-тип-данных-jsr310(рекомендуемые).


Я создал небольшой / минимальный пример, основанный на Spring 5.0.9 и Джексон 2.9.6 (последние версии на данный момент).

Вы можете найти его здесь: spring5-rest-zoneddatetime >>, основные части:

  1. Event DTO:

    public class Event {
    
        private long id;
        private String name;
        private ZonedDateTime time;
    
        // Constructors, public getters and setters
    
    }
    

    Поле time может быть public, таким же, как в вашем образце, это тоже нормально, но если поле private - тогда вам понадобятся геттер и сеттер public.

    ЗАМЕТКА: Я игнорирую здесь аннотации @DynamoDBTypeConverted и @DynamoDBAttribute, поскольку они связаны с логикой сохранения, а не с уровнем REST.

  2. EventController содержит только один метод, аналогичный вашему:

    @RestController
    public class EventController {
    
        @RequestMapping(value = "/event", method = RequestMethod.POST)
        public ResponseEntity post(@RequestBody Event event) {
            System.out.println("Event posted: " + event.toString());
            return ResponseEntity.ok(event);
        }
    
    }
    
  3. Зависимости в pom.xml выглядят так:

    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-webmvc</artifactId>
        <version>5.0.9.RELEASE</version>
    </dependency>
    
    <dependency>
        <groupId>com.fasterxml.jackson.core</groupId>
        <artifactId>jackson-databind</artifactId>
        <version>2.9.6</version>
    </dependency>
    
    <dependency>
        <groupId>com.fasterxml.jackson.datatype</groupId>
        <artifactId>jackson-datatype-jsr310</artifactId>
        <version>2.9.6</version>
    </dependency>
    

    Важным здесь является реализация типа данных JSR-310, которая также вводит com.fasterxml.jackson.datatype.jsr310.ser.ZonedDateTimeSerializer и com.fasterxml.jackson.datatype.jsr310.deser.InstantDeserializer.


Дополнительная информация:

  1. Если потребуется настраиваемый сериализатор / десириализатор, проверьте этот вопрос >>

  2. Следующие форматы даты будут поддерживаться для поля time:

    • "2018-01-01T22:25:15+01:00[Europe/Paris]" - не совсем ISO 8601, кстати
    • "2018-01-01T22:25:15+01:00"
    • "2018-01-01T22:25:15.000000001Z"
    • 1514768461.000000001 - число с плавающей запятой, количество секунд от 1970-01-01, 00:00:00 [UTC]
  3. По умолчанию ответ REST APi будет использовать числа с плавающей запятой для дат, например в нашем случае ответ будет выглядеть так:

    {
        "id": 3,
        "name": "Test event",
        "time": 1514768460
    }
    

    Чтобы вместо этого возвращать строковые значения, проверьте, например, это вопрос >>

  4. Также необходимо упомянуть, что если вы будете использовать вместо этого Весенний ботинок (хороший стартер) - все, что обсуждалось выше, будет работать из коробки.

Ответом для меня было то, что мне пришлось использовать как ядро ​​Джексона, так и типы данных, как вы рекомендовали, а не только один. Спасибо за четкий ответ!

Alex Kornhauser 26.09.2018 22:38

Отправить в этом формате 2016-08-22T14: 30 + 08: 00 [Азия / Куала_Лумпур]

LocalDateTime ldt = LocalDateTime.of(2016, Month.AUGUST, 22, 14, 30);

ZonedDateTime klDateTime = ldt.atZone(ZoneId.of("Asia/Kuala_Lumpur"));

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