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

Я надеюсь получить некоторую помощь в отладке этой проблемы. Если я отправлю следующий 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 для анализа зонированного времени даты?

Спасибо!


person Alex Kornhauser    schedule 17.09.2018    source источник
comment
Пожалуйста, дайте больше информации о различных используемых технологиях   -  person Franck Gamess    schedule 17.09.2018
comment
Конечно. Что конкретно вы ищете? Предположим, Spring MVC. Я больше заинтересован в том, чтобы понять, как отлаживать это, чем просто получить ответ.   -  person Alex Kornhauser    schedule 18.09.2018
comment
Непонятно, как реализован ваш ZonedDateTimeTypeConverter (пожалуйста, покажите достаточно информации), но обычно ZonedDateTime не принимает что-то вроде 558851094.57158995. Попробуйте отправить строку типа "2007-12-03T10:15:30+01:00[Europe/Paris]", как в документ ZonedDateTime.   -  person OOPer    schedule 18.09.2018
comment
Если я буквально попробую эту точную строку, она тоже не сработает: { ApprovalRequired: false, scheduleStartTime: 2007-12-03T10:15:30+01:00[Европа\/Париж], location: { locationName: ‹+37.33233141, -122.03121860› +\/- 5,00 м (скорость 0,00 м/с \/курс -1,00) @ 9/19/18, 12:16:05 по тихоокеанскому летнему времени, долгота: -122.0312186, широта: 37.332331410000002 } }   -  person Alex Kornhauser    schedule 19.09.2018
comment
@AlexKornhauser, какой синтаксический анализатор вы используете, не могли бы вы предоставить часть конфигурации Spring для этого? И если вы не возражаете, сообщите нам также версию Spring, используемую с вашей стороны.   -  person marme1ad    schedule 23.09.2018
comment
Что за ошибка выше? Содержимое ZonedDateTimeTypeConverter.java?   -  person Mumrah81    schedule 24.09.2018
comment
Попробуйте 2015-09-22T19:58:22.947Z   -  person Amit Parashar    schedule 24.09.2018
comment
Это не вопрос Swift, это вопрос Java.   -  person Cristik    schedule 26.09.2018


Ответы (2)


Решение:

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

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


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

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

  1. Event ДТО:

    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]" - not fully an ISO 8601 btw
    • "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. Также нужно отметить, что если вместо этого вы будете использовать Spring Boot (хороший старт) - все, что обсуждалось выше, будет работать из коробки.

person marme1ad    schedule 24.09.2018
comment
Ответ для меня заключался в том, что мне пришлось использовать как ядро ​​​​Jackson, так и типы данных, как вы рекомендовали, а не только один. Спасибо за ваш четкий ответ! - person Alex Kornhauser; 26.09.2018

Отправить в этом формате 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"));
person Jin Thakur    schedule 26.09.2018