2

I want to receive items using retrofit and parse them into a Java list. However, the server response is not a JSON array but a JSON object containing the items. That is why retrofit cannot just convert the response into a java list.

The response looks something like this:

{
    "4": {
        "key": "value",
        ...
    },
    "5": {
        ...
    }, 
    ...
}

Usually, I would try to receive the items like this:

@GET("items")
Call<List<Item>> getItems();

But this obviously does not work and Retrofit responds: Expected BEGIN_ARRAY but was BEGIN_OBJECT

What is my best option to convert this object into a java list using retrofit?

  • I faced this case once, I believe there is no way that Retrofit can fully parse the response like this, we have to catch the root object -> use GSon to convert it to String, then parse it manually. The best way: tell server guy to fix it, he did a very bad and stupid thing! – Phong Nguyen Aug 16 '19 at 14:42
  • I thin the solution could be someting like in this post: https://stackoverflow.com/questions/37550388/retrofit-to-parser-json-with-an-indefinite-number-of-object-names Maybe something like Call>>. Try a bit arround, good luck. – Daniel Spiess Aug 16 '19 at 14:45
  • @ThinkTwiceCodeOnce Thank you for the answer. I am pretty sure that the server guys at Philips will not change this. But hopefully, they will not create something like this again. – Julian Eggers Aug 19 '19 at 20:16
  • @DanielSpiess: Thank you for the link. It is similar to Fred's answer and it solves my issue. – Julian Eggers Aug 19 '19 at 20:17

2 Answers2

2

I'd personally do this in 2 steps to avoid having to write a custom adapter for the deserialization.

I'd write the interface like:

@GET("items")
Call<Map<String, Item>> getItems();

And once you'd call the API on the response I'd just call values().

Things to take into consideration is that because the API returns a map and not a list, there's no guarantee that the order of any list you'd produce would be consistent. The json standard doesn't define any order for objects unless they're in a json array.

Fred
  • 16,367
  • 6
  • 50
  • 65
0

When you say the response is List, the JSON should be an "ARRAY".

E.g.:

[ "a", "b" ]

or

{ 
   "xxx": [ "a", "b" ] 
}

In either case, the objects you'd want to parse into would look like:

List<String> for the first one.

Thing for the second one.

And Thing would look like:

class Thing {
   public List<String> xxx;
}

You're trying to parse this:

{
    "4": {
        "key": "value",
        ...
    },
    "5": {
        ...
    }, 
    ...
}

So based on the above information, what do you think your response looks like when parsed? (hint: you can try something like this Java POJO generator to get an idea ;)

Martin Marconcini
  • 26,875
  • 19
  • 106
  • 144
  • 1
    Thank you for answering. I cannot change the server response. That is why I have to deal with this stupid 'object-list'. – Julian Eggers Aug 19 '19 at 20:27
  • 1
    Gotcha, I see you've already gotten an answer. I was simply teasing you to see if you could figure it out on your own (it's just a Map<> not a List<>) but glad to hear you've solved it ;) – Martin Marconcini Aug 20 '19 at 13:15