GSON:如何从Json获得不区分大小写的元素?

Jam*_*sev 12 java json case-insensitive gson

JSON对象包含jsonKey传递给方法时,下面显示的代码效果很好.我想知道...如果有办法将值分配给一个键的不区分大小写的表示?

例:

public String getOutputEventDescription(JsonElement outputEvent) throws ParserException {
    return retrieveString(outputEvent, DESCRIPTION);
}
Run Code Online (Sandbox Code Playgroud)

无论是否将DESCRIPTION定义为"描述","描述"或"DeScRipTIOn",都应该可以工作

protected String retrieveString(JsonElement e, String jsonKey) throws ParserException {

JsonElement value = e.getAsJsonObject().get(jsonKey);

if (value == null) {
    throw new ParserException("Key not found: " + jsonKey);
}

if (value.getAsString().trim().isEmpty()) {
    throw new ParserException("Key is empty: " + jsonKey);
}

return e.getAsJsonObject().get(jsonKey).getAsString();
}
Run Code Online (Sandbox Code Playgroud)

Pro*_*uce 8

遗憾的是,注册a FieldNamingStrategyGsonBuilder不会带来太大的好处,因为它仅在与期望相反的方向上进行转换:从Java字段名称到JSON元素名称.它不能合理地用于您的目的.

(详细地:

转换请求的结果结束于FieldNamingStrategy.translateName(Field),其中转换的名称用于从a获取关联的JSON元素JsonObject,其具有LinkedHashMap<String, JsonElement>被调用的membersJSON元素名称映射到其关联值.经翻译的名称被用作参数的get(String)方法members,和提供GSON没有机制用于向作出不区分大小写该最终呼叫.

members地图被填充有调用JsonObject.add(String, JsonElement),从制成Streams.parseRecursive(JsonReader),与来自检索到的JSON元素名称JsonReader用作密钥来"成员".(JsonReader使用与JSON中完全相同的字符,除了找到转义字符'\'之外.)在整个调用堆栈中,Gson没有为用于填充的键提供members改变的机制,例如,要制作全部小写或全部大写.

A FieldNamingPolicy以同样的方式工作.)

合理的解决方案可能是简单地使用自定义反序列化器,顺序如下.

input.json:

[
 {"field":"one"},
 {"Field":"two"},
 {"FIELD":"three"},
 {"fIElD":"four"}
]
Run Code Online (Sandbox Code Playgroud)

Foo.java:

import java.io.FileReader;
import java.lang.reflect.Type;
import java.util.Map.Entry;

import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.JsonDeserializationContext;
import com.google.gson.JsonDeserializer;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonParseException;

public class Foo
{
  public static void main(String[] args) throws Exception
  {
    GsonBuilder gsonBuilder = new GsonBuilder();
    gsonBuilder.registerTypeAdapter(MyClass.class, new MyTypeAdapter());
    Gson gson = gsonBuilder.create();
    MyClass[] myObjects = gson.fromJson(new FileReader("input.json"), MyClass[].class);
    System.out.println(gson.toJson(myObjects));
  }
}

class MyClass
{
  String field;
}

class MyTypeAdapter implements JsonDeserializer<MyClass>
{
  @Override
  public MyClass deserialize(JsonElement json, Type myClassType, JsonDeserializationContext context)
      throws JsonParseException
  {
    // json = {"field":"one"}
    JsonObject originalJsonObject = json.getAsJsonObject();
    JsonObject replacementJsonObject = new JsonObject();
    for (Entry<String, JsonElement> elementEntry : originalJsonObject.entrySet())
    {
      String key = elementEntry.getKey();
      JsonElement value = originalJsonObject.get(key);
      key = key.toLowerCase();
      replacementJsonObject.add(key, value);
    }
    return new Gson().fromJson(replacementJsonObject, MyClass.class);
  }
}
Run Code Online (Sandbox Code Playgroud)

或者,您可以首先处理原始JSON以将所有元素名称更改为相同的大小写,全部更低或全部更高.然后,将更改后的JSON传递给Gson进行反序列化.这当然会减慢JSON处理速度.

如果您能够为项目更改Gson代码,那么可能需要更改以获得最有效结果的部分是对name = nextString((char) quote);in 的调用JsonReader.因为nextString(char)也用于获取JSON元素值,我可能只是为了获取名称而复制它,然后进行小的更改以强制元素名称为全部更低或全部大写.当然,这种方法然后将您的项目锁定到Gson的一个版本,否则您需要重复此更改以升级到更新的Gson版本.

杰克逊相比,情况似乎不一样.PropertyNamingStrategy不幸的是,翻译工作方式大致相同:它们从Java字段名称转换为JSON元素名称.没有任何可用的JsonParser.Feature更改会自定义JsonParser强制JSON元素名称为全部大写或全部小写.


小智 7

我遇到了类似的问题.我这样做是为了解决这个问题.(将所有键替换为相应的小写版本,并在匹配类中包含所有小写字段).希望这可以帮助.

 input = input.replaceAll("\\s","");
        Matcher m = Pattern.compile("\"\\b\\w{1,}\\b\"\\s*:").matcher(input);
        StringBuilder sanitizedJSON = new StringBuilder();
        int last = 0;
        while (m.find()) {
            sanitizedJSON.append(input.substring(last, m.start()));
            sanitizedJSON.append(m.group(0).toLowerCase());
            last = m.end();
        }
        sanitizedJSON.append(input.substring(last));

        input = sanitizedJSON.toString();
Run Code Online (Sandbox Code Playgroud)


Pud*_*dge 5

不幸的是,在当前的实现中似乎没有办法做到这一点.如果您查看Gson源代码,更具体地说是JsonObject实现,您将看到底层数据结构是链接的哈希映射.get调用只是调用map上的get,而get又使用哈希码和equals方法来查找你要查找的对象.

唯一的方法是为您的密钥强制执行一些命名约定.最简单的方法是将所有键强制为小写.如果你需要混合大小写键,那么你将遇到更多困难,需要编写一个更复杂的算法来转换键而不是简单地调用jsonKey.toLowerCase().