使用Gson将json转换为Map.Entry对象

Nou*_*vay 8 java android json gson

简单易用

如果我要求Gson将一些有效的json转换为MyMap,那么它就没有问题

public class MyMap{
   Map<Long,String> content;
}


MyMap myMap = gson.fromJson(json, new TypeToken<MyMap>() {}.getType());
Run Code Online (Sandbox Code Playgroud)

硬版本:

我如何让Gson做以下事情?

public class MyDS{
    Map<Map.Entry<Long,String>,Map<Long,String>> content;
}

MyDS myDS = gson.fromJson(json, new TypeToken<MyDS>() {}.getType());
Run Code Online (Sandbox Code Playgroud)

示例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"
      }
    }
Run Code Online (Sandbox Code Playgroud)

更多笔记

为了更好的衡量,我尝试运行单元测试,我所做的就是尝试用Gson读取json,并得到以下错误跟踪:

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)
Run Code Online (Sandbox Code Playgroud)

如果键的形式是无关紧要"[3, rabbit]""{3, rabbit}"

Nic*_*tto 4

假设您有有效的 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"
      }
   }
}
Run Code Online (Sandbox Code Playgroud)

为了实现你想要的,你可以简单地实现你自己的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)
        );
    }
}
Run Code Online (Sandbox Code Playgroud)

然后我可以JSON使用以下方法反序列化我的内容:

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

MyDS myDS = gson.fromJson(json, type);
Run Code Online (Sandbox Code Playgroud)

  • @AxelH 它表示除“]”之外的任何字符的序列 (2认同)