【问题标题】:Java:JSON to map using GSONJava:JSON 使用 GSON 进行映射
【发布时间】:2018-10-17 12:55:30
【问题描述】:

我有一个这样的字符串

{"key0":"value0","key1":"value1","key0":"value3"}

我想将它存储在地图中,所需的结果是 {"key0":"value3","key1":"value1"}

使用 org.json.JsonObject:我将字符串传递给构造函数并抛出 Duplicate key 异常

使用 GSON:当我尝试通过 new Gson.fromJson(string,Type) 时出现同样的异常

使用 Jackson:确实有效

是否有使用 JSONObject 和 Gson 实现相同目的的解决方法

【问题讨论】:

  • 您确实意识到拥有相同的键会导致覆盖该值。我认为,即使它在杰克逊中工作,如果键在输入中重复,你也不能保证特定键的值是什么。
  • 您能否详细说明所需结果背后的逻辑?是否只是某个键的最后一个值,以便它们碰巧出现在 JSON 文件/字符串中?所以你假设“value0”首先插入到地图中,然后“value3”覆盖它?我认为在任何地方都无法保证订单。但是您还应该考虑到您的示例不是有效的 JSON,如果它表示地图。另一方面:如何序列化地图并在结果 JSON 中为同一个键设置两个值?

标签: java json jackson gson


【解决方案1】:

有趣的是,如果您先将该 json 转换为 Object,然后再转换为 Map<String,String>,您想要的结果就会发生:

String json = "{\"key0\":\"value0\",\"key1\":\"value1\",\"key0\":\"value3\"}";
Gson gson = new Gson();
Object obj = gson.fromJson(json, Object.class);
try {
    Map<String,String> map = (Map<String, String>)obj;
    // Outputs...
    // key0=value3
    // key1=value1
    for (Map.Entry<String,String> entry : map.entrySet()) {
        System.out.println(entry.getKey() + "=" + entry.getValue());
    }
} catch (ClassCastException e) {
    e.printStackTrace();
}

【讨论】:

  • 成功了。但是谁能解释一下?在文档中找不到太多。我的理解是 .fromJson 的第二个约定指定了如何解释反序列化的对象。由于 Map 不允许重复的条目,它引发了错误。如果我错了,请纠正我
  • 看起来gson.fromJson() 实际上首先将结果转换为Object,因此默认情况下您可以使用Object 作为gson.fromJson() 的返回类型。 Object 的实际类型我相信要么是 LinkedTreeMap(这是一个 json 对象)要么是 ArrayList。您必须查看 Gson 源代码才能了解它们是如何转换的。无论哪种方式,您始终可以使用Object,然后检查它的类型。
【解决方案2】:

GSON 使用MapTypeAdapterFactory 反序列化地图。以下是其源代码的简短摘录,其中将新条目放入地图中:

V replaced = map.put(key, value);
if (replaced != null) {
    throw new JsonSyntaxException("duplicate key: " + key);
}

知道至少有一种方法可以绕过这种严格的行为:创建自己的地图,覆盖方法 put(..) 以始终返回 null,例如:

public class DuploMap extends HashMap<String, String>{
    @Override
    public String put(String key, String value) {
        super.put(key, value);
        return null; 
    }
}

然后像这样脱轨:

gson.fromJson(JSON, DuploMap.class);

不会抛出该异常。

【讨论】:

    【解决方案3】:

    如果您不介意手动操作,可以使用 GSON 的 JsonReader。

    有利的一面:

    • 更快(无反射,无投射)
    • 完全由您控制

    --

    String json = "{"key0":"value0","key1":"value1","key0":"value3"}";
    JsonReader jsonReader = new JsonReader(new StringReader(json));
    HashMap<String,String> map = new HashMap<String, String>()
    String currKey;
    try {
        while(jsonReader.hasNext()){
            JsonToken nextToken = jsonReader.peek();
               if(JsonToken.NAME.equals(nextToken)){
                   currKey = jsonReader.nextName();
               }
               if(JsonToken.STRING.equals(nextToken)){
                   map.put(currKey, jsonReader.nextString())
               }
        }
    } catch (IOException e) {
       e.printStackTrace();
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多