Jackson ObjectMapper десериализовать объект с массивом

Есть несколько похожих вопросов здесь и здесь, но они не вполне соответствует моей ситуации. Моя строка JSON состоит из объекта с массивом:

{
  "data": [
    {
      "id": 1,
      "title": "Sample training",
      "date": "2016-10-03 10:00:00",
      "subscription": "2016-09-20 12:34:50"
    },
    {
      "id": 2,
      "title": "Second training",
      "date": "2016-10-06 10:00:00",
      "subscription": "2016-09-20 12:54:50"
    }
  ]
}

Каждый объект в массиве является компонентом Java:

public class TrainingInfo {

    private int id;
    private String title;
    @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd HH:mm:ss")
    private LocalDateTime date;
    @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd HH:mm:ss")
    private LocalDateTime subscription;

    // Consructors, getters and setters omitted 
    // ...
}

Я могу прочитать один TrainingInfo с помощью:

ObjectMapper mapper = new ObjectMapper();
mapper.registerModule(new JavaTimeModule());
TrainingInfo training = mapper.readValue(jsonTrainingInfo, TrainingInfo.class);

Но я не могу прочитать весь массив. Я попытался создать новый Java-бин, просто содержащий массив, и прочитать его, например:

private class TrainingsArray {
    private TrainingInfo[] data;

    public TrainingInfo[] getData() {
        return data;
    }

    public void setData(TrainingInfo[] data) {
        this.data = data;
    }
}

ObjectMapper mapper = new ObjectMapper();
mapper.registerModule(new JavaTimeModule());
TrainingsArray trainings = mapper.readValue(jsonTrainingsArray, TrainingsArray.class);

Но это просто выдает IOException. Что мне не хватает?

ОБНОВЛЕНИЕ. Возникло исключение:

com.fasterxml.jackson.databind.JsonMappingException: Can not construct instance of JsonMapperTest$TrainingsArray: no suitable constructor found, can not deserialize from Object value (missing default constructor or creator, or perhaps need to add/enable type information?)
 at [Source: {
  "data": [
    {
      "id": 1,
      "title": "Sample training",
      "date": "2016-10-03 10:00:00",
      "subscription": "2016-09-20 12:34:50"
    },
    {
      "id": 2,
      "title": "Second training",
      "date": "2016-10-06 10:00:00",
      "subscription": "2016-09-20 12:54:50"
    }
  ]
}; line: 2, column: 3]

    at com.fasterxml.jackson.databind.JsonMappingException.from(JsonMappingException.java:270)
    at com.fasterxml.jackson.databind.DeserializationContext.instantiationException(DeserializationContext.java:1456)
    at com.fasterxml.jackson.databind.DeserializationContext.handleMissingInstantiator(DeserializationContext.java:1012)
    at com.fasterxml.jackson.databind.deser.BeanDeserializerBase.deserializeFromObjectUsingNonDefault(BeanDeserializerBase.java:1205)
    at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserializeFromObject(BeanDeserializer.java:314)
    at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserialize(BeanDeserializer.java:148)
    at com.fasterxml.jackson.databind.ObjectMapper._readMapAndClose(ObjectMapper.java:3798)
    at com.fasterxml.jackson.databind.ObjectMapper.readValue(ObjectMapper.java:2842)
    at JsonMapperTest.shouldMapJsonResponseToTrainingsArray(JsonMapperTest.java:90)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)
    at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:45)
    at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:15)
    at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:42)
    at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:20)
    at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:263)
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:68)
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:47)
    at org.junit.runners.ParentRunner$3.run(ParentRunner.java:231)
    at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:60)
    at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:229)
    at org.junit.runners.ParentRunner.access$000(ParentRunner.java:50)
    at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:222)
    at org.junit.runners.ParentRunner.run(ParentRunner.java:300)
    at org.junit.runner.JUnitCore.run(JUnitCore.java:157)
    at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:68)
    at com.intellij.rt.execution.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:51)
    at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:237)
    at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:70)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)
    at com.intellij.rt.execution.application.AppMain.main(AppMain.java:147)

person houcros    schedule 25.11.2016    source источник
comment
Не могли бы вы включить IOException?   -  person Luke Melaia    schedule 25.11.2016
comment
Я думаю, потому что вы определили его как частный класс.   -  person grape_mao    schedule 25.11.2016
comment
Сделайте свой класс TrainingsArray классом верхнего уровня или, по крайней мере, статическим вложенным классом вместо внутреннего класса. Для построения внутреннего класса требуется ссылка на его внешний экземпляр. Джексону пришлось бы создать экземпляр JsonMapperTest. А этого не будет.   -  person JB Nizet    schedule 25.11.2016
comment
сделайте свой класс TrainingsArray доступным, сделав его public вместо private, если вы хотите сохранить его как внутренний класс, сделайте его тоже static   -  person Nicolas Filotto    schedule 25.11.2016
comment
JB и Николя правы, внутренний класс тоже может быть проблемой, я предположил, что это обычный класс...   -  person grape_mao    schedule 25.11.2016
comment
@grape_mao @Nicolas Filotto @JB Nizet Вы были в порядке. Достаточно было изменить класс с private на public, чтобы тест заработал. Я просто не думал, что это повлияет... Если кто-то из вас действительно ответит, я буду рад его принять.   -  person houcros    schedule 25.11.2016
comment
В настоящее время некоторые люди пишут длинные ответы на простые вопросы только для того, чтобы заработать больше баллов, что для меня бессмысленно и является пустой тратой времени.   -  person grape_mao    schedule 25.11.2016
comment
Я согласен, но я считаю, что все же приятно иметь ответ, даже если он короткий, например, сделайте свой класс общедоступным, а не закрытым. Для будущих читателей это сразу показывает, что решение было найдено, каким бы тривиальным оно ни было :)   -  person houcros    schedule 25.11.2016


Ответы (1)


Каким бы глупым это ни казалось, решение состояло в том, чтобы сделать класс TrainingsArray общедоступным.

person houcros    schedule 06.12.2016