Преобразование json в объект Map.Entry с помощью Gson

ЛЕГКАЯ ВЕРСИЯ

Если я попрошу Gson преобразовать какой-то действительный json в MyMap, у него нет проблем с этим

public class MyMap{ Map<Long,String> content; } MyMap myMap = gson.fromJson(json, new TypeToken<MyMap>() {}.getType()); 

ТРУДНАЯ ВЕРСИЯ:

Как мне заставить Gson сделать следующее?

 public class MyDS{ Map<Map.Entry<Long,String>,Map<Long,String>> content; } MyDS myDS = gson.fromJson(json, new TypeToken<MyDS>() {}.getType()); 

Пример json, если вам это действительно нужно.

 "content": { "[1, dog]": { "1": "max", "2": "pi", "3": "robot", "4": "catcher", "5": "reaper" }, "[2, cat]": { "6": "black", "7": "white", "8": "meow", "9": "mice", "10": "rat" }, "[3, rabbit]": { "16": "bunny", "17": "ears", "28": "burgerbun", "39": "alice", "50": "tweak" } } 

Больше заметок

Для хорошей меры я пытаюсь запустить единичный тест, где все, что я делаю, – это прочитать Json с Gson, и я получаю следующую трассировку ошибок:

 at sun.misc.Unsafe.allocateInstance(Native method) java.lang.reflect.Method.invoke!(Native method) com.google.gson.internal.UnsafeAllocator$1.newInstance(UnsafeAllocator.java:48) com.google.gson.internal.ConstructorConstructor$14.construct(ConstructorConstructor.java:223) com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$Adapter.read(ReflectiveTypeAdapterFactory.java:207) com.google.gson.internal.bind.TypeAdapterRuntimeTypeWrapper.read(TypeAdapterRuntimeTypeWrapper.java:40) com.google.gson.internal.bind.MapTypeAdapterFactory$Adapter.read(MapTypeAdapterFactory.java:186) com.google.gson.internal.bind.MapTypeAdapterFactory$Adapter.read(MapTypeAdapterFactory.java:145) com.google.gson.Gson.fromJson(Gson.java:861) com.google.gson.Gson.fromJson(Gson.java:826) com.google.gson.Gson.fromJson(Gson.java:775) 

Не имеет значения, имеют ли ключи форму "[3, rabbit]" для "{3, rabbit}"

Solutions Collecting From Web of "Преобразование json в объект Map.Entry с помощью Gson"

Предполагая, что у вас есть допустимое содержимое JSON типа:

 { "content": { "[1, dog]": { "1": "max", "2": "pi", "3": "robot", "4": "catcher", "5": "reaper" }, "[2, cat]": { "6": "black", "7": "white", "8": "meow", "9": "mice", "10": "rat" }, "[3, rabbit]": { "16": "bunny", "17": "ears", "28": "burgerbun", "39": "alice", "50": "tweak" } } } 

Для достижения того, что вы хотите, вы можете просто реализовать свой собственный Map.Entry Deserializer поскольку его нельзя десериализовать из коробки, потому что он не является массивом, а {3, rabbit} не является допустимым объектом JSON .

Таким образом, ваш Deserializer может полагаться на регулярное выражение, чтобы извлечь ключ, а затем создать экземпляр AbstractMap.SimpleEntry используя извлеченные значения, например:

 public class MapEntryDeserializer implements JsonDeserializer<Map.Entry<Long, String>> { /** * Pattern corresponding to: * Starts with [ * <a non empty sequence of digit characters>, * <a non empty sequence of any characters * Ends with ] */ private static final Pattern PATTERN = Pattern.compile("^\\[(\\d+), ?(.+)\\]$"); public Map.Entry<Long, String> deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException { // Extract the key/value pair from Strings of type [3, rabbit] String value = json.getAsString(); Matcher matcher = PATTERN.matcher(value); if (!matcher.find()) { throw new JsonParseException( String.format("The map entry doesn't have the expected format: %s", value) ); } return new AbstractMap.SimpleEntry<>( Long.valueOf(matcher.group(1)), matcher.group(2) ); } } 

Затем я могу десериализовать свой контент JSON :

 Type type = new TypeToken<MyDS>() {}.getType(); Gson gson = new GsonBuilder() .registerTypeAdapter(Map.Entry.class, new MapEntryDeserializer()) .create(); MyDS myDS = gson.fromJson(json, type); 

Согласно документации для Map.Entry:

Единственный способ получить ссылку на запись карты – это итератор этого вида коллекции.

https://docs.oracle.com/javase/8/docs/api/java/util/Map.Entry.html

Это означает, что вы не можете получить Map.Entry, пока не создадите исходную карту. Чтобы добиться того, что вы хотите, вам нужно проанализировать JSON на карте, а затем перебрать его, чтобы вставить его в свой объект MyDS.

Сказав это, в зависимости от вашего конечного использования могут быть более эффективные способы реорганизации / ввода данных после их разбора.