1

I'm working on an API wrapper using retrofit but I'm having issues creating the returned object classes since some items from the same endpoint can contain different type of fields.

For example, the returning JSON can look like this for a basic item:

{
  "name": "Box of Honed Splint Armor",
  "description": "Double-click to unpack a full set of level 50 armor.",
  "type": "Container",
  "level": 0,
  "rarity": "Masterwork",
  "vendor_value": 86,
  "game_types": [
    "Wvw",
    "Dungeon",
    "Pve"
  ],
  "flags": [],
  "restrictions": [],
  "id": 9000,
  "chat_link": "[&AgEoIwAA]",
  "icon": "https://render.guildwars2.com/file/72D04673660ECB7FD904680D487030A41106F952/63218.png",
  "details": {
    "type": "Default"
  }
}

Or like this for a more detailed item:

{
  "name": "Strong Soft Wood Longbow of Fire",
  "description": "",
  "type": "Weapon",
  "level": 44,
  "rarity": "Masterwork",
  "vendor_value": 120,
  "default_skin": "3942",
  "game_types": [ "Activity", "Dungeon", "Pve", "Wvw" ],
  "flags": [ "SoulBindOnUse" ],
  "restrictions": [],
  "id": 28445,
  "chat_link":"[&AgEdbwAA]",
  "icon": "https://render.guildwars2.com/file/C6110F52DF5AFE0F00A56F9E143E9732176DDDE9/65015.png",
  "details": {
    "type": "LongBow",
    "damage_type": "Physical",
    "min_power": 385,
    "max_power": 452,
    "defense": 0,
    "infusion_slots": [],
    "infix_upgrade": {
      "attributes": [
        { "attribute": "Power", "modifier": 62 },
        { "attribute": "Precision", "modifier": 44 }
      ]
    },
    "suffix_item_id": 24547,
    "secondary_suffix_item_id": ""
  }
}

The details field can differ very much between different item types, and I'd prefer to have an easy way to access the fields corresponding to each type without the wrapper consumer has to type cast to a type-specific subclass of an empty base class like other wrappers require, like one of the best wrappers do.

Is there some way to hide fields depending on the type of the parent or something like that so I can include all possible fields in the item class?

Any suggestions?

Izaac Brånn
  • 94
  • 13
  • I thought that retrofit only populated fields that are returned in the JSON, so if there are extra fields that have no JSON value (e.g. basic item) then they will be null. – Scary Wombat Jan 09 '20 at 00:43
  • @Scary Wombat preferably, if possible, I would like that they weren't there at all. But if there is no way then a details class containing all fields is the best way to go then. – Izaac Brånn Jan 09 '20 at 00:49
  • You can serialize the item in more detail and get the value of any field but first comparing if there is any value in the field you want to get. – Bacar Pereira Jan 09 '20 at 00:50
  • see also https://stackoverflow.com/questions/45131547/retrofit2-convert-json-with-dynamic-keys-to-a-mapstring-model-with-model-als – Scary Wombat Jan 09 '20 at 00:51
  • @Scary Wombat I'd definitely go with the details class containing all fields, so if you'd like to put it up as an answer so that I can accept it I'd be delighted. Thanks for the help. Didn't know, or find any info in the docs that it sets missing values to null. Thought it would throw an exception for that. – Izaac Brånn Jan 09 '20 at 00:59

1 Answers1

1

As per https://www.baeldung.com/retrofit

Retrofit works by modeling over a base URL and by making interfaces return the entities from the REST endpoint.

For simplicity purposes we're going to take a small part of the JSON by modeling our User class that is going to take the values when we have received them:

public class User {
    private String login;
    private long id;
    private String url;
    // ...

    // standard getters an setters

}

We can see that we're only taking a subset of properties for this example. Retrofit won't complain about missing properties – since it only maps what we need, it won't even complain if we were to add properties that are not in the JSON.

Scary Wombat
  • 44,617
  • 6
  • 35
  • 64