使用GSON,如何在某些键具有特殊字符时将JSON转换为Java

时间:2014-08-30 13:41:16

标签: java json gson

外部API为我提供了一个JSON对象,如下所示:

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

如您所见,除了一个嵌套对象之外,所有键都以@符号开头。我们正在使用GSON来解析JSON,并且我尝试尽可能简单地执行此操作,而无需手动将每个键转换为有效的Java字段名称。

我目前正在尝试使用此代码:

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

并且除了TournamentEntry之外没有匹配任何字段。

我尝试添加了一个gson字段命名策略,但这似乎是一种全有或全无的方法,并且无法处理某些密钥具有" @"签字和一些不要。

我如何告诉GSON放弃" @"转换为Java字段名称时的符号,同时仍然处理没有@符号的嵌套对象?

2 个答案:

答案 0 :(得分:3)

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的优点在于它可以在每个字段的基础上工作,因此您只需要在需要时进行注释。

答案 1 :(得分:1)

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

以下是如何执行此操作的示例。它检查元素是否是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);
        }
    }
}

请记住,如果您的JSON非常嵌套,递归方法将抛出StackOverflowError,但希望绝对不会这样。