使用Gson将json转换为Map.Entry对象 [英] Convert json to Map.Entry object with Gson

查看:993
本文介绍了使用Gson将json转换为Map.Entry对象的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

简单版本



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

  public class MyMap {
Map< Long,String>内容;


$ b MyMap myMap = gson.fromJson(json,new TypeToken< MyMap>(){} .getType());

HARD VERSION:

我如何让Gson执行以下操作?

  public class MyDS {
Map< Map.Entry< Long,String> ;,,地图<长,字符串>>内容;
}

MyDS myDS = gson.fromJson(json,new TypeToken< MyDS>(){} .getType());

示例json,如果您确实需要它。



< pre $ content:{
[1,dog]:{
1:max,
2: pi,
3:机器人,
4:捕手,
5:收割者
},
2,猫]:{
6:black,
7:white,
8:meow,
9 :老鼠,
10:老鼠
},
[3,rabbit]:{
16:bunny,
17:耳朵,
28:burgerbun,
39:alice,
50:tweak
}

更多笔记 $ b

为了更好的衡量,我尝试运行一个单元测试,其中我所做的只是尝试使用Gson读取json,并获得以下错误跟踪:

  at sun.misc.Unsafe.allocateInstance(本地方法)
java.lang.reflect.Method.invoke!(本地方法)
com.googl e.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] for {3,rabbit}

解决方案

假设您有一个有效的 JSON 类型内容:

  {
content:{
[1 ,dog):{
1:max,
2:pi,
3:robot,
4: 捕手,
5:收割者
},
[2,猫]:{
6:黑色,
7:白色,
8:喵,
9:老鼠,
10:鼠
},
[3,rabbit]:{
16:bunny,
17:耳朵,
28:burgerbun,
39:alice,
50:tweak
}
}
}

为了实现你想要的,你可以简单地实现你自己的 Map.Entry Deserializer ,因为它不能被反序列化,因为它不是一个数组,并且 {3,rabbit} 不是有效的 > JSON object。



因此,您的 Deserializer 可以依赖常规表达来提取关键字和值,然后使用提取的值创建一个 AbstractMap.SimpleEntry 的实例,如下所示:

  public class MapEntryDeserializer实现了JsonDeserializer< Map.Entry< Long,String>> {
$ b / **
*相应的模式:
*以[
*<一个非空的数字字符序列> ;,
* <任何字符的非空序列
*结束于]
* /
private static final Pattern PATTERN = Pattern.compile(^ \\ [(\\d + ),?(。+)\\ $);

public Map.Entry< Long,String> deserialize(JsonElement json,Type typeOfT,
JsonDeserializationContext上下文)抛出JsonParseException {
//从[3,rabbit]类型的字符串中提取键/值对
String value = json.getAsString( );
匹配匹配器= PATTERN.matcher(value);
if(!matcher.find()){
throw new JsonParseException(
String.format(地图条目没有预期的格式:%s,value)
);
}
返回新的AbstractMap.SimpleEntry<>(
Long.valueOf(matcher.group(1)),matcher.group(2)
);


$ / code $ / pre

然后我可以反序列化我的


$ b

 类型t​​ype = new TypeToken< MyDS>(){} .getType( ); 
Gson gson = new GsonBuilder()
.registerTypeAdapter(Map.Entry.class,new MapEntryDeserializer())
.create();

MyDS myDS = gson.fromJson(json,type);


EASY VERSION

If I ask Gson to convert some valid json to MyMap it has no problem doing it

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


MyMap myMap = gson.fromJson(json, new TypeToken<MyMap>() {}.getType());

HARD VERSION:

How do I get Gson to do the following?

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

MyDS myDS = gson.fromJson(json, new TypeToken<MyDS>() {}.getType());

Example json if you really need it.

"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"
      }
    }

more notes

For good measure, I try to run a unit test where all I do is try to read the json with Gson, and I get the following error trace:

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)

It does not matter if the keys are of the form "[3, rabbit]" for "{3, rabbit}"

解决方案

Assuming that you have a valid JSON content of type:

{
   "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"
      }
   }
}

To achieve what you want, you could simply implement your own Map.Entry Deserializer since it cannot be deserialized out of the box because it is not an array and {3, rabbit} is not a valid JSON object.

So your Deserializer could rely on a regular expression to extract the key and the value then create an instance of AbstractMap.SimpleEntry using the extracted values, something like:

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)
        );
    }
}

I can then deserialize my JSON content with:

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

MyDS myDS = gson.fromJson(json, type);

这篇关于使用Gson将json转换为Map.Entry对象的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆