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

e37o9pze  于 2022-11-06  发布在  其他
关注(0)|答案(4)|浏览(254)

JSON对象包含传递给方法的jsonKey时,下面显示的代码运行良好。我想知道...是否有一种方法可以获得分配给键的不区分大小写的表示形式的值?

范例:

public String getOutputEventDescription(JsonElement outputEvent) throws ParserException {
    return retrieveString(outputEvent, DESCRIPTION);
}

无论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();
}
xmjla07d

xmjla07d1#

不幸的是,将FieldNamingStrategy注册到GsonBuilder并没有什么好处,因为它只会以与期望相反的方向进行转换:从Java字段名称到JSON元素名称。它不能合理地用于您的目的。
(In详细信息:
翻译请求的结果在FieldNamingStrategy.translateName(Field)结束,其中翻译后的名称用于从JsonObject中获取关联的JSON元素,JsonObject有一个LinkedHashMap<String, JsonElement>,称为members,将JSON元素名称Map到它们的关联值。并且Gson没有提供使这个最终调用不区分大小写的机制。
membersMap使用从Streams.parseRecursive(JsonReader)发出的对JsonObject.add(String, JsonElement)的调用进行填充,从JsonReader检索的JSON元素名称用作“members”的键。(JsonReader使用的字符与JSON中的字符完全相同,但转义字符“\”除外。)在整个调用堆栈中,Gson没有提供用于改变用于填充members的键的机制,例如,使其全部小写或全部大写。
FieldNamingPolicy的工作方式与此相同。)
一个合理的解决方案可能是简单地使用自定义反序列化程序,沿着所示。

输入.json:

[
 {"field":"one"},
 {"Field":"two"},
 {"FIELD":"three"},
 {"fIElD":"four"}
]

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

或者,您可以先处理原始JSON,将所有元素名更改为相同的大小写,全部小写或全部大写。然后,将更改后的JSON传递给Gson进行反序列化。这当然会减慢JSON处理。
如果您能够更改项目的Gson代码,那么最有效的更改部分可能是JsonReader中对name = nextString((char) quote);的调用。由于nextString(char)还用于获取JSON元素值,因此我可能只需要复制一个它来获取名称,然后进行一些小的更改来强制元素名称全部为小写或全部为大写。当然,这种方法会将您的项目锁定到Gson的一个版本,否则您需要重复此更改以升级到更新的Gson版本。
不幸的是,Jackson的情况与此类似。不幸的是,PropertyNamingStrategy的翻译工作方式大致相同:它们将Java字段名转换为JSON元素名。没有一个可用的JsonParser.Feature修改可以定制JsonParser来强制JSON元素名全部大写或全部小写。

ohfgkhjo

ohfgkhjo2#

我也遇到过类似的问题。我这样做是为了绕过这个问题。(用它们对应的小写版本替换所有的键,并在匹配类中有所有小写字段)。希望这能有所帮助。

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();
am46iovg

am46iovg3#

不幸的是,在当前的实现中似乎没有一种方法可以做到这一点。如果你看一下Gson源代码,更具体地说,看一下JsonObject实现,你会发现底层的数据结构是一个链接的哈希Map。get调用只是调用Map上的get,它反过来使用你的键的哈希代码和equals方法来找到你要找的对象。
唯一的解决方法是强制执行一些键的命名约定。最简单的方法是强制所有键为小写。如果你需要大小写混合的键,那么你会遇到更多的困难,需要编写一个更复杂的算法来转换键,而不是简单地调用jsonKey.toLowerCase()。

q43xntqr

q43xntqr4#

当我遇到在两个端点使用不同命名约定的问题时,我偶然发现了这个问题,随后发现了一个侵入性较小的解决方案。
Gson确实支持设置从Java模型名称Map到JSON名称时使用的命名约定,无论是在序列化还是反序列化时。使用构建器的setFieldNamingPolicy方法可以更改此行为。

GsonBuilder gsonBuilder = new GsonBuilder();
gsonBuilder.setFieldNamingPolicy(FieldNamingPolicy.UPPER_CAMEL_CASE);
Gson gson = gsonBuilder.create();

请看这里关于这个主题的一篇不错的文章,包括对不同政策的概述。
这并不是一个真正的不区分大小写的解决方案,但它确实提供了一种方法来解决大小写不匹配的许多情况。

相关问题