Java 8 LocalDateTime десериализован с использованием Gson

У меня есть JSON с атрибутом даты и времени в формате «2014-03-10T18: 46: 40.000Z», которые я хочу десериализовать в поле java.time.LocalDateTime с помощью Gson.

При попытке десериализации я получаю сообщение об ошибке:

java.lang.IllegalStateException: Expected BEGIN_OBJECT but was STRING

person fische    schedule 10.03.2014    source источник
comment
Это происходит во время сериализации или десериализации. Если это второй - проверьте, действителен ли ваш json - например, он должен начинаться с { (он же BEGIN_OBJECT), но вместо этого ваш json начинается с символа   -  person Svetlin Zarev    schedule 11.03.2014
comment
Я ошибаюсь во время десериализации. Json - ›Объект. Но я думаю, что мой Json в порядке. Если я заменю в своем объекте свой атрибут LocalDateTime на String, он заработает.   -  person fische    schedule 11.03.2014
comment
json имеет формат {"key":"value"} Ваш json определенно недействителен. Как я сказал в gson, { is BEGIN_OBJECT, и он говорит, что он отсутствует. Просто println() json, чтобы проверить, правильно ли он. Также вы можете распечатать объект serialized, чтобы увидеть, как должен выглядеть json :)   -  person Svetlin Zarev    schedule 11.03.2014
comment
Хорошо, теперь я понимаю, почему это не работает. Но, может быть, ты знаешь, что я могу сделать? Как специальные параметры с Gson, например, если у меня есть строка со специальной датой и временем, чтобы десериализовать это поле и создать объект, который мне нужен?   -  person fische    schedule 11.03.2014
comment
Я не могу вам ничего сказать, пока не увижу веревку. Но в любом случае вы не можете десериализовать его, если он не является действительным json. ИМХО, лучшее (и, возможно, единственное), что вы можете сделать, - это сделать эту строку действительной json.   -  person Svetlin Zarev    schedule 11.03.2014
comment
Строка выглядит так: 2014-03-10T18: 46: 40.000Z. Итак, мне нужно получить объект этого (объект datetime из mysql?).   -  person fische    schedule 11.03.2014
comment
Вы думали о том, что строка отметки времени выглядит как глобальная отметка времени UTC-ISO-8601 (буква Z в конце!)? Это не представление местной метки времени. На самом деле я не могу протестировать преобразование в LocalDateTime (у меня нет Java 8), но предполагаю, что это преобразование может завершиться неудачно.   -  person Meno Hochschild    schedule 13.03.2014
comment
@fische: Как говорит Мено, у вас есть OffsetDateTime, а не LocalDateTime. Также вам могут быть интересны мои настраиваемые сериализаторы для java.time сущностей: github.com/gkopff/gson -javatime-сериализаторы   -  person Greg Kopff    schedule 15.04.2014


Ответы (4)


Ошибка возникает, когда вы десериализуете атрибут LocalDateTime, потому что GSON не может проанализировать значение атрибута, поскольку он не знает об объектах LocalDateTime.

Используйте метод registerTypeAdapter GsonBuilder, чтобы определить настраиваемый адаптер LocalDateTime. Следующий фрагмент кода поможет вам десериализовать атрибут LocalDateTime.

Gson gson = new GsonBuilder().registerTypeAdapter(LocalDateTime.class, new JsonDeserializer<LocalDateTime>() {
    @Override
    public LocalDateTime deserialize(JsonElement json, Type type, JsonDeserializationContext jsonDeserializationContext) throws JsonParseException {
        Instant instant = Instant.ofEpochMilli(json.getAsJsonPrimitive().getAsLong());
        return LocalDateTime.ofInstant(instant, ZoneId.systemDefault());
    }
}).create();
person Randula    schedule 22.05.2014

Чтобы расширить ответ @ Randula, чтобы проанализировать строку с зонированной датой и временем (2014-03-10T18: 46: 40.000Z) в JSON:

Gson gson = new GsonBuilder().registerTypeAdapter(LocalDateTime.class, new JsonDeserializer<LocalDateTime>() {
@Override
public LocalDateTime deserialize(JsonElement json, Type type, JsonDeserializationContext jsonDeserializationContext) throws JsonParseException {
    return ZonedDateTime.parse(json.getAsJsonPrimitive().getAsString()).toLocalDateTime();
}
}).create();
person Evers    schedule 21.03.2016
comment
этот параметр для десериализации типа Тип, что это именно? - person mcgyver5; 25.02.2017
comment
@ mcgyver5 - это java.lang.reflect.Type - person Lambart; 27.03.2018
comment
это не строка с зонированной датой и временем, а момент времени (docs.oracle.com/javase/8/docs/api/java/time/format/) - person Francis; 21.12.2020

Чтобы еще больше расширить ответ @Evers:

Вы можете еще больше упростить лямбду следующим образом:

GSON GSON = new GsonBuilder().registerTypeAdapter(LocalDateTime.class, (JsonDeserializer<LocalDateTime>) (json, type, jsonDeserializationContext) ->
    ZonedDateTime.parse(json.getAsJsonPrimitive().getAsString()).toLocalDateTime()).create();
person nterry    schedule 23.08.2016

Следующее сработало для меня.

Java:

Gson gson = new GsonBuilder().registerTypeAdapter(LocalDateTime.class, new JsonDeserializer<LocalDateTime>() { 
@Override 
public LocalDateTime deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException { 

return LocalDateTime.parse(json.getAsString(), DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm")); } 

}).create();

Test test = gson.fromJson(stringJson, Test.class);

где stringJson - это Json, который хранится как строковый тип

Json:

"dateField": "2020-01-30 15:00"

где dateField имеет тип LocalDateTime, который присутствует в строковой переменной stringJson.

person greenhorn    schedule 23.04.2020