Можно ли преобразовать массив пар объектов в 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, а не «полными» объектами?
Другими словами, учитывая два типа JavaK и 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;




Если вы хотите избежать класса 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]}
Да, похоже, это единственный подход. Спасибо.