Аннотации Джексона и REST Android: десериализация массива объектов JSON

У меня есть служба REST, которая возвращает данные, которые выглядят так:

[
    { bookmark object json here },
    { bookmark object json here },
    { bookmark object json here },
    ...
]

Мой клиентский класс REST выглядит так:

@Rest(rootUrl = Constants.ApiConfig.API_ROOT, converters = {MappingJackson2HttpMessageConverter.class})
public interface RestApiClient {
    @Get("/bookmark/read?id={identifier}")
    public BookmarkList getBookmarks(String identifier);
}

Список закладок выглядит так:

public class BookmarkList {
    List<Bookmark> bookmarks;

    @JsonValue
    public List<Bookmark> getBookmarks() {
        return bookmarks;
    }

    @JsonCreator
    public void BookmarkList(@NotNull List<Bookmark> bookmarks) {
        this.bookmarks = bookmarks;
    }
}

Однако, когда я использую эту настройку, я получаю следующую ошибку:

Не удалось прочитать JSON: невозможно десериализовать экземпляр com.whatever.entity.BookmarkList из токена START_ARRAY

Я хочу что-то вроде примера EventList на https://github.com/excilys/androidannotations/wiki/Rest-API#get, но, похоже, это не работает для меня из коробки.

Есть ли способ заставить это работать?


person mwu    schedule 09.08.2013    source источник


Ответы (2)


Хо... Мы должны обновить эту часть документации. Решение-оболочка работает, но не подходит для API.

Если вы посмотрите на сгенерированный код для @Get("url") MyReturnedType testService(), вы должны увидеть что-то вроде этого:

return restTemplate.exchange(rootUrl.concat("url"), //
    HttpMethod.GET, //
    null, //
    MyReturnedType.class, //
    urlVariables)//
  .getBody();

Возвращаемый класс вводится как параметр вызова exchange. В случае коллекции дженериков (например, List<MyReturnedType>) мы не можем внедрить List.class из-за проверки типов в методе возврата обмена.

Тем не менее, вы сможете использовать этот небольшой трюк в аннотированном методе @Rest:

public class BookmarkList extends List<Bookmark> {
}
person DayS    schedule 11.08.2013
comment
Мне это нравится больше, чем мое оригинальное решение, поскольку оно лучше использует сгенерированный код. - person mwu; 12.08.2013
comment
Я обновил вики, чтобы заменить решение для упаковки этим - person DayS; 26.08.2013

Я думаю, что неправильно понял пример на https://github.com/excilys/androidannotations/wiki/Rest-API#get. Я думаю, что в этом примере массив все еще должен быть обернут внутри объекта JSON (было бы неплохо, если бы они включали примеры данных JSON).

Данные, к которым я подключаюсь, не возвращают объект, обертывающий массив таким образом, поэтому я изменил клиент REST, чтобы он выглядел следующим образом:

@Rest(rootUrl = Constants.ApiConfig.API_ROOT, converters = {MappingJackson2HttpMessageConverter.class})
public interface RestApiClient {
    @Get("/bookmark/read?id={identifier}")
    public ArrayNode getBookmarks(String identifier);
}

И я написал метод в другом классе для итерации ArrayNode и создания закладок:

public List<Bookmark> getBookmarks(Content content) {
    ArrayList<Bookmark> bookmarks = new ArrayList<Bookmark>();
    ArrayNode bookmarksData = apiClient.getBookmarks(content.getAcid());

    for(JsonNode bookmarkData : bookmarksData) {
        Bookmark bookmark = objectMapper.convertValue(bookmarkData, Bookmark.class);
        bookmarks.add(bookmark);
    }
    return bookmarks;
}

Так что это не так удобно (мне пришлось самому писать больше кода), но у меня все заработало.

person mwu    schedule 09.08.2013