Пользовательская Java-карта deserialzer в Gson - PullRequest
0 голосов
/ 15 сентября 2018

Можно ли преобразовать массив пар объектов в Map, выбрав значения из каждой пары, не создавая промежуточный POJO?

Например, скажем, что есть 2 Java класса (Key.class, Value.class) и массив JSON, построенный из сериализованных пар их объектов, следующим образом

[
  {"key":{}, "value":{}}, // Objects k1, v1
  {"key":{}, "value":{}}, // Objects k2, v2
  {"key":{}, "value":{}}, // Objects k3, v3
  {"key":{}, "value":{}}, // Objects k4, v4
]

Может Gson «напрямую» (т. Е. Без определения POJO) десериализовать вышеуказанный массив в Map, в котором фактические ключи и значения заполняются из манипуляций с соответствующими Key и Value объекты, а не "полные" объекты?

Другими словами, учитывая два Java типа K и V, которые могут отличаться от Key и Value, десериализация на пару должна составлять

(k1:Key, v1:Value) --> (k1':K, v1':V)

, где

k1' = function(k1)
v1' = function(v1)

Адаптер, подобный этому, не работает:

GsonBuilder builder = new GsonBuilder();
Type type = (new TypeToken<Map<K, V>>() {}).getType();    
builder.registerTypeAdapter(type, new JsonDeserializer<Map<Key, Value>>() {
  @Override
  public Map<K, V> deserialize(JsonElement json, Type type, JsonDeserializationContext context) throws JsonParseException {
    // Custom deserialization block,
    // invoking the `function()` method
  }
Gson gson = builder.create();

Использование вышеприведенного адаптера приводит к Gson передаче всего массива в метод deserialize(), где им нужно манипулировать вручную, что утомительно и подвержено ошибкам.

С пользовательским POJO как

public class KeyValue {
  Key k;
  Value v;
}

вышеуказанный массив JSON может быть десериализован в массив или набор KeyValue объектов, которые затем могут быть преобразованы в Map<K, V>. Но можно ли сделать то же самое без KeyValue POJO;

1 Ответ

0 голосов
/ 15 сентября 2018

Если вы хотите избежать использования класса POJO, который вы называете KeyValue, я думаю, что единственный способ сделать это с помощью gson - это создать адаптер.Причина в том, что ваш JSON не соответствует ни одному универсальному встроенному классу, и поэтому gson не сможет его понять, не имея для этого собственной логики.

Поскольку у вас есть Key и Value классы, которые вы можете использовать в своем адаптере.Я думаю, вы обнаружите, что это уменьшает утомительность кода.

public static void main(String[] args) throws IOException {
        GsonBuilder builder = new GsonBuilder();
        Type type = (new TypeToken<Map<Key, Value>>() {}).getType();    
        builder.registerTypeAdapter(type, new JsonDeserializer<Map<Key, Value>>() {
          @Override
          public Map<Key, Value> deserialize(JsonElement json, Type type, JsonDeserializationContext context) throws JsonParseException {
              Map<Key, Value> resultMap = new HashMap<>();
              JsonArray jArr = json.getAsJsonArray();
              for(int i=0; i < jArr.size(); i++){
                  JsonObject item = jArr.get(i).getAsJsonObject();
                  processKeyValue(item, resultMap);
              }
              return resultMap;
          }

          private void processKeyValue(JsonObject mapEntry, Map<Key, Value> resultMap){
              Gson gson = new Gson();
              Key key = gson.fromJson(mapEntry.get("key"), Key.class);
              Value value = gson.fromJson(mapEntry.get("value"), Value.class);
              resultMap.put(key, value);
          }
        });
        Gson gson = builder.create();

        //Note: assume that the variable "json" is a JSON string. I removed my code for getting the string since I'm just reading from a file and I don't know how you're getting your data.

        // Deserialization

        Map<Key,Value> outputMap = gson.fromJson(json, type);


        System.out.println("RESULTS: "+outputMap.toString());
    }

Я использовал данные вашего примера, но немного изменил их, чтобы получить немного больше контента.Я создал два очень простых класса POJO для Key и Value - у них есть только поле String с именем id, метод получения и установки для этого поля и метод toString.

Это был ввод, который я использовал при запуске кода выше:

[
  {"key":{"id":"k1"}, "value":{"id":"v1"}}, 
  {"key":{"id":"k2"}, "value":{"id":"v2"}},
  {"key":{"id":"k3"}, "value":{"id":"v3"}}, 
  {"key":{"id":"k4"}, "value":{"id":"v4"}}
]

Вывод:

RESULTS: {Key [id=k2]=Value [id=v2], Key [id=k1]=Value [id=v1], Key [id=k3]=Value [id=v3], Key [id=k4]=Value [id=v4]}
...