Сериализация Jackson OffsetDateTime Z вместо часового пояса +00: 00? - PullRequest
0 голосов
/ 28 февраля 2020

Я использую Spring Boot со следующим ObjectMapper:

@Bean
public ObjectMapper objectMapper()
{
    final ObjectMapper mapper = new ObjectMapper();

    mapper.enable(SerializationFeature.INDENT_OUTPUT);

    mapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);  
    mapper.setDateFormat(new StdDateFormat().withColonInTimeZone(true)); // Makes no difference to output

    mapper.findAndRegisterModules();

    return mapper;
}

Когда OffsetDateTimes сериализуются и возвращаются в ответах, они имеют следующий формат:

"2020-02-28T12:28:29.01Z"
"2020-02-28T12:36:21.885Z"

Я бы ожидал, что информация о часовом поясе в конце будет выглядеть следующим образом:

"2020-02-28T10:41:25.287+00:00"

Есть ли что-то, что я пропускаю или делаю не так, или в любом случае я могу получить информацию о часовом поясе, сериализованную в формате +00:00 вместо 885Z формата?

Большое спасибо!

Ответы [ 4 ]

1 голос
/ 28 февраля 2020

Новый Java 8 Time API предоставляет DateTimeFormatter, где вы можете установить конец формата на один или несколько x или X. Согласно описанию API:

Смещение X и x: форматирует смещение на основе количества букв шаблона. Одна буква выводит только час, например, «+01», если минута не равна нулю, в этом случае также выводится минута, например, «+0130». Две буквы выводят час и минуту без двоеточия, например «+0130». Три буквы выводят часы и минуты с двоеточием, например, «+01: 30». Четыре буквы выводят час и минуту и ​​необязательную секунду без двоеточия, например «+013015». Пять букв выводят часы и минуты и необязательную секунду с двоеточием, например «+01: 30: 15». Шесть или более букв выбрасывают исключение IllegalArgumentException. Буква шаблона «X» (верхний регистр) будет выводить «Z», когда смещение для вывода будет нулевым, а буква шаблона «x» (нижний регистр) будет выводить «+00», «+0000» или «+00». : 00 '.

Итак, в вашем случае ваша строка форматирования должна заканчиваться xxx для +1:30, например, "yyyy-MM-dd'T'HH:mm:ss.SSSxxx" с SSS, всегда дающим миллисекунды.

Чтобы использовать это DateTimeFormatter с Джексоном, вам нужно либо определить собственный сериализатор

public class DefaultZonedDateTimeSerializer extends JsonSerializer<ZonedDateTime> {


  private static final DateTimeFormatter ISO_8601_FORMATTER = DateTimeFormatter
        .ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSSXXX")
        .withZone(ZoneId.of("UTC"));

  @Override
  public void serialize(ZonedDateTime value, JsonGenerator gen, SerializerProvider serializers) throws IOException {
    if (value == null) {
        throw new IOException("ZonedDateTime argument is null.");
    }

    gen.writeString(ISO_8601_FORMATTER.format(value));
}

и аннотировать соответствующие поля в ваших бобах с помощью

@JsonSerialize(using = DefaultZonedDateTimeSerializer.class)
private ZonedDateTime someTimeProperty;

, либо вам нужно преобразовать из DateTimeFormatter в DateFormat (более старый, но используемый Джексоном), как описано здесь: Использование DateTimeFormatter с ObjectMapper

1 голос
/ 28 февраля 2020

Существует несколько возможностей использования предварительно созданного форматирования или предоставления пользовательского шаблона для DateTimeFormatter.

Посмотрите на эти (очень простые) примеры:

public static void main(String[] arguments) {
    Instant now = Instant.now();

    ZonedDateTime zonedDateTime = ZonedDateTime.ofInstant(now, ZoneId.of("UTC"));
    OffsetDateTime offsetDateTime = OffsetDateTime.ofInstant(now, ZoneId.of("UTC"));

    System.out.println(zonedDateTime.toString());
    System.out.println(offsetDateTime.toString());
    System.out.println(zonedDateTime.format(DateTimeFormatter.ISO_ZONED_DATE_TIME));
    System.out.println(offsetDateTime.format(DateTimeFormatter.ISO_OFFSET_DATE_TIME));
    System.out.println(zonedDateTime.format(DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ssZ")));
    System.out.println(offsetDateTime.format(DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ssxxx")));
}

Я думаю, что вы ожидаете, что последний, шаблон, заканчивающийся xxx, который заставляет смещение всегда показываться в форме HH:mm, вывод кода:

2020-02-28T12:49:02.388Z[UTC]
2020-02-28T12:49:02.388Z
2020-02-28T12:49:02.388Z[UTC]
2020-02-28T12:49:02.388Z
2020-02-28T12:49:02+0000
2020-02-28T12:49:02+00:00
0 голосов
/ 28 февраля 2020

Следующие шаги решают эту проблему (взято из { ссылка }), спасибо также @Ralf Wagner и @deHaar:

<dependency>
  <groupId>com.fasterxml.jackson.datatype</groupId>
  <artifactId>jackson-datatype-jsr310</artifactId>
  <version>2.6.5</version>
</dependency>
public class OffsetDateTimeSerializer extends JsonSerializer<OffsetDateTime>
{
    private static final DateTimeFormatter ISO_8601_FORMATTER = DateTimeFormatter
        .ofPattern("yyyy-MM-dd'T'HH:mm:ssxxx")
        .withZone(ZoneId.of("UTC"));

    @Override
    public void serialize(OffsetDateTime value, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) throws IOException
    {
        if (value == null) {
            throw new IOException("OffsetDateTime argument is null.");
        }

        jsonGenerator.writeString(ISO_8601_FORMATTER.format(value));
    }
}
@Bean
public ObjectMapper objectMapper()
{

    ObjectMapper objectMapper = new ObjectMapper();
    objectMapper.enable(SerializationFeature.INDENT_OUTPUT);
    objectMapper.registerModule(new JavaTimeModule());
    SimpleModule simpleModule = new SimpleModule();

    simpleModule.addSerializer(OffsetDateTime.class, new OffsetDateTimeSerializer());
    objectMapper.registerModule(simpleModule);

    return objectMapper;
}
0 голосов
/ 28 февраля 2020

Если вы используете JodaDateTime, попробуйте следующее:

    @Bean
    public ObjectMapper getObjectMapper() {
        ObjectMapper objectMapper = new ObjectMapper();
        objectMapper.registerModule(new JodaModule());
        objectMapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false);
        return objectMapper;
    }
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...