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

2022-09-04 08:22:13

当对象包含传递给方法时,下面显示的代码可以很好地工作。我想知道...如果有一种方法可以将值分配给键的不区分大小写的表示形式?JSONjsonKey

例:

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

无论 DESCRIPTION 是定义为“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();
}

答案 1

不幸的是,使用 注册FieldNamingStrategy不会有太大好处,因为它只在与期望相反的方向上转换:从Java字段名称到JSON元素名称。它不能合理地用于您的目的。GsonBuilder

(详细内容:

翻译请求的结果在 结束,其中翻译后的名称用于从 中获取关联的 JSON 元素,该元素具有一个 称为 ,将 JSON 元素名称映射到其关联值。翻译后的名称被用作 方法的参数,而 Gson 没有提供任何机制来使这个最终调用不区分大小写。FieldNamingStrategy.translateName(Field)JsonObjectLinkedHashMap<String, JsonElement>membersget(String)members

映射中填充了对 的调用,从 中检索到 JSON 元素名称,用作“成员”的键。( 这些字符的使用与 JSON 中的字符完全相同,但发现转义字符“\”的情况除外。在整个调用堆栈中,Gson 没有为用于填充的键提供任何更改机制,例如,全部设置为小写或全部大写。membersJsonObject.add(String, JsonElement)Streams.parseRecursive(JsonReader)JsonReaderJsonReadermembers

A 以同样的方式工作。FieldNamingPolicy

一个合理的解决方案可能是简单地使用自定义反序列化程序,大致如下。

input.json:

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

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

不幸的是,对于杰克逊来说,情况似乎相似。不幸的是,使用 PropertyNameingStrategy 的翻译的工作方式大致相同:它们从 Java 字段名称转换为 JSON 元素名称。任何可用的更改都不会自定义 a 以强制 JSON 元素名称全部大写或全部小写。JsonParser.FeatureJsonParser


答案 2

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

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