使用GSON,如何JSON转换成Java时,一些键有特殊字符

问题描述:

外部API给了我一个JSON对象,如下所示:使用GSON,如何JSON转换成Java时,一些键有特殊字符

{ 
    "@date": "1407436242", 
    "@duration": "2411", 
    "Entry": { 
     "@position": "3", 
     "@playerName": "fred" 
    } 
} 

正如你可以看到,所有的键开始的@符号,除了为一个,这是一个嵌套的对象。我们正在使用GSON来解析JSON,并且我正在尽可能简单地执行此操作,而无需手动将每个密钥转换为有效的Java字段名称。

我目前使用此代码尝试:

MyObject response = gson.fromJson(stringInput, MyObject.class); 

这种匹配除了TournamentEntry没有字段。

我试过添加了一个gson字段命名策略,但是这似乎是一个全有或全无的方法,并且无法处理某些键具有“@”符号,而有些键不符合。

如何让GSON在转换为Java字段名称时删除“@”符号,同时仍处理没有@符号的嵌套对象?

+0

您可以尝试使用jsonString.replaceAll(“\\ @”,“”)来移除所有的@ – SparkOn 2014-08-30 13:47:50

+0

您可以使用十几种不同的JSON工具包中的任何一种来生成相应的嵌套Map对象。 – 2014-08-30 13:58:00

+0

@SparkOn这就是我正在使用的当前方法......但某些值域中可能有@符号......所以这并不理想。 – 2014-08-30 14:27:09

您可以尝试首先使用GSON的JsonParser将您的JSON解析为JsonElement,然后对其进行预处理,以删除以@开头的任何密钥并将其替换为实际密钥。之后,您可以拨打gson.fromJson修改JsonElement而不是JSON字符串。

下面是如何做到这一点的一个例子。它检查元素是否是JSON对象,如果是,则替换所有以@开头的键。所有的值然后通过相同的方法递归地放置(这样你也可以在你的例子中替换例如@position)。

public static void main(String... args) { 
    String json = "{\n" 
      + " \"@date\": \"1407436242\",\n" 
      + " \"@duration\": \"2411\",\n" 
      + " \"Entry\": {\n" 
      + "  \"@position\": \"3\",\n" 
      + "  \"@playerName\": \"fred\"\n" 
      + " }\n" 
      + "}"; 

    JsonParser jsonParser = new JsonParser(); 
    JsonElement jsonElement = jsonParser.parse(json); 

    // Modify the JsonElement, replacing any keys beginning with @ 
    removeAtSymbolsInKeys(jsonElement); 

    MyObject myObject = new Gson().fromJson(jsonElement, MyObject.class); 
    System.out.println(myObject); 
} 

private static void removeAtSymbolsInKeys(JsonElement jsonElement) { 
    if (jsonElement.isJsonObject()) { 
     JsonObject jsonObject = jsonElement.getAsJsonObject(); 
     Set<Entry<String, JsonElement>> entrySet = new HashSet<>(jsonObject.entrySet()); // Make a copy so we can modify JsonObject 

     for (Entry<String, JsonElement> entry : entrySet) { 
      String key = entry.getKey(); 
      JsonElement value = entry.getValue(); 

      if (key.startsWith("@")) { 
       String newKey = key.replaceFirst("@", ""); 
       jsonObject.add(newKey, value); 
       jsonObject.remove(key); 
      } 

      // Replace the keys of any values that are objects 
      removeAtSymbolsInKeys(value); 
     } 
    } 
} 

请记住,递归方法将抛出的StackOverflowError如果你的JSON是极其嵌套的,但这应该有希望永远如此。

+0

你知道,只写一个接受Map的构造函数会更简单,更直接。 – 2014-09-02 19:19:24

+0

@HotLicks也许,但原始问题要求解决方案“无需手动将每个键转换为有效的Java字段名称”。 – andersschuller 2014-09-02 19:44:37

Gson提供了SerializedName注释,它应该允许使用那些时髦的json标识符。这将使你的类看起来像这样:

package com.example; 

import com.google.gson.annotations.SerializedName; 
import java.util.Date; 

public class Event { 

    @SerializedName("@date") 
    private Date date; 

    @SerializedName("@duration") 
    private long duration; 

    @SerializedName("Entry") 
    private Entry entry; 

} 

package com.example; 

import com.google.gson.annotations.SerializedName; 

public class Entry { 

    @SerializedName("@position") 
    private int position; 

    @SerializedName("@playerName") 
    private String playerName; 

} 

约@SerializedName伟大的事情是,它在每场的基础上,所以你只需要在需要时进行注释。