Mapowanie dynamicznie zmieniającego się JSON'a do obiektów

0

Witajcie,
Mam problem z mapowaniem JSON'a do obiektów. Mój problem polega na tym, że json może przyjąć następujące postacie:

{
    "success":true,
    "inventory":[]
}

lub:

{
    "success":true,
    "inventory":{
        "123": {
            "name":"przedmiot"
        }
    }
}

Zwracany JSON różni się w zależności od parametrów requesta.
Chciałbym mieć możliwość napisania tego tak, że jeżeli nie uda się parsowanie sekcji inventory, reszta została poprawnie przetworzona.

Mój model:

public class Inventory {
    private boolean success;
    private HashMap<String, Item> inventory;
    
    public static class Item {
        private String name;
    }
}

I kod, którego używam do pobrania i mapowania JSON'a

Inventory inv = restTemplate.getForObject("http://example.com/inventory?id=123", Inventory.class);

Problem w tym że metoda getForObject zwraca mi wyjątek, kiedy JSON wygląda jak ten 1 i nie dostaję instancji obiektu.

Macie pomysł jak to zrobić? Użyć do tego celu GSON i przepisywać każde pole ręcznie (jest ich troche więcej niż tutaj napisałem)?

0

Troche to dziwne, ze raz jest zwracana tablica a raz obiekt.
Pytanie czy na poziomie klienta wiesz jaki bedzie response to wtedy mozesz stworzyc dwie klasy inventory i parsowac na nie. Ewentualnie try catch czyli pierw proba parsowania na InventoryZTablica a pozniej z Obiektem

0

Chodzi tutaj o API steama, i pobieranie inventory gracza. Sam jestem tym ździwiony.

http://steamcommunity.com/profiles/<steam id>/inventory/json/<app id>/<context id>

Jeżeli użytkownik ma itemy w inventory, pokazywane są obiekty, gdy ich nie ma pusta tablica.

Niestety, ale nie wiem.

1

Jeśli masz dużo takich przypadków i jesteś pewien, że nie poprawisz tego po stronie usługi to:

  1. Stwórz własny wrapper dla Map<String, String>, np:
    public class MapWrapper extends HashMap<String, String> implements Map<String, String> {}

  2. Stwórz własny adapter dla tego typu:

public class MapWrapperAdapter implements JsonDeserializer<MapWrapper> {
    @Override
    public MapWrapper deserialize(JsonElement jsonElement, Type type, JsonDeserializationContext jsonDeserializationContext) throws JsonParseException {
        // ... some code
        return myWrapperResult;
    }
}
  1. Stwórz Gsona z zarejestrowanym adapterem:
GsonBuilder builder = new GsonBuilder();
builder.registerTypeAdapter(MapWrapper.class, new MyWrapperAdapter());

Gson gson = builder.create();

Edit:
Oczywiście trzeba podmienić typ pola inventory.

Deserializuj :)

0

Dzięki za odpowiedź. Aktualnie korzystam z Jacksona. Nie da się zrobić tego jakoś za pomocą adnotacji albo ustawień Jacksona? Tak żeby pomijał pola, których nie uda się zmapować? Próbowałem @JsonIgnore(ignoreUnknown = true), ale bezskutecznie

0

Do tego używamy @JsonView

0

@JsonView mógłbym użyć jeżeli wiedziałbym co zwróci mi api. Tutaj tego nie wiem

0

Możliwe ze zostaje CI do napisania własny deserializer

1

Napisałem, że musisz de facto napisać własny deserializer - ale tylko i wyłącznie dla map, które podejrzewasz o takie głupie zachowanie. Potem podmieniasz typ pola w Inventory:

public class Inventory {
    private boolean success;
    private MapWrapper inventory;
 
}

I całą resztę już za Ciebie gson załatwia.

1 użytkowników online, w tym zalogowanych: 0, gości: 1