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

Java GSON:如何从Json获取不区分大小写的元素?,java,json,gson,case-insensitive,Java,Json,Gson,Case Insensitive,当JSON对象在传递给方法时包含jsonKey时,下面显示的代码运行良好。我想知道。。。是否有办法获得分配给键的不区分大小写表示形式的值 示例: public String getOutputEventDescription(JsonElement outputEvent) throws ParserException { return retrieveString(outputEvent, DESCRIPTION); } [ {"field":"one"}, {"Field":"

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

示例:

public String getOutputEventDescription(JsonElement outputEvent) throws ParserException {
    return retrieveString(outputEvent, DESCRIPTION);
}
[
 {"field":"one"},
 {"Field":"two"},
 {"FIELD":"three"},
 {"fIElD":"four"}
]
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);
  }
}
无论描述是定义为“描述”、“描述”还是“描述”,都应起作用


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


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

不幸的是,在
GsonBuilder
中注册a不会有多大好处,因为它的翻译方向与预期相反:从Java字段名到JSON元素名。它不能合理地用于您的目的

(详情:

翻译请求的结果在
FieldNamingStrategy.translateName(字段)处结束
,其中翻译后的名称用于从
JsonObject
获取关联的JSON元素,该对象具有名为
members
LinkedHashMap
,将JSON元素名称映射到其关联值。翻译后的名称用作
get(字符串)的参数
成员的方法,Gson没有提供使此最终调用不区分大小写的机制

members
映射中填充了对
JsonObject.add(String,jsoneelement)
的调用,该调用由
Streams.parseRecursive(JsonReader)
生成,从
JsonReader
检索的JSON元素名称用作“members”的键。(
JsonReader
使用的字符与JSON中的字符完全相同,但转义字符“\”除外。)在整个调用堆栈中,Gson不提供任何机制来更改用于填充
成员的键,例如,使其全部为小写或大写

FieldNamingPolicy
的工作方式相同。)

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

input.json:

public String getOutputEventDescription(JsonElement outputEvent) throws ParserException {
    return retrieveString(outputEvent, DESCRIPTION);
}
[
 {"field":"one"},
 {"Field":"two"},
 {"FIELD":"three"},
 {"fIElD":"four"}
]
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);
  }
}
Foo.java:

public String getOutputEventDescription(JsonElement outputEvent) throws ParserException {
    return retrieveString(outputEvent, DESCRIPTION);
}
[
 {"field":"one"},
 {"Field":"two"},
 {"FIELD":"three"},
 {"fIElD":"four"}
]
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);
  }
}
导入java.io.FileReader;
导入java.lang.reflect.Type;
导入java.util.Map.Entry;
导入com.google.gson.gson;
导入com.google.gson.GsonBuilder;
导入com.google.gson.JsonDeserializationContext;
导入com.google.gson.JsonDeserializer;
导入com.google.gson.JsonElement;
导入com.google.gson.JsonObject;
导入com.google.gson.JsonParseException;
公开课Foo
{
公共静态void main(字符串[]args)引发异常
{
GsonBuilder GsonBuilder=新的GsonBuilder();
gsonBuilder.registerTypeAdapter(MyClass.class,新的MyTypeAdapter());
Gson-Gson=gsonBuilder.create();
MyClass[]myObjects=gson.fromJson(新文件读取器(“input.json”)、MyClass[].class);
System.out.println(gson.toJson(myObjects));
}
}
类MyClass
{
字符串字段;
}
类MyTypeAdapter实现JsonDeserializer
{
@凌驾
公共MyClass反序列化(JsonElement json,类型myClassType,JsonDeserializationContext)
抛出JsonParseException
{
//json={“字段”:“一”}
JsonObject originalJsonObject=json.getAsJsonObject();
JsonObject replacementJsonObject=新建JsonObject();
for(Entry elementEntry:originalJsonObject.entrySet())
{
String key=elementEntry.getKey();
JsonElement value=originalJsonObject.get(键);
key=key.toLowerCase();
replacementJsonObject.add(键,值);
}
返回新的Gson().fromJson(replacementJsonObject,MyClass.class);
}
}
或者,您可以首先处理原始JSON,将所有元素名称更改为相同大小写,全部为小写或大写。然后,将更改后的JSON传递给Gson进行反序列化。这当然会降低JSON处理的速度

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


不幸的是,情况与之类似。翻译的工作方式非常相似:它们从Java字段名转换为JSON元素名。任何可用的
JsonParser.Feature
更改都不会自定义
JsonParser
以强制将JSON元素名转换为所有较高或较低的case.

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

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

当我遇到一个问题时,我偶然发现了这个问题,在两个端点使用了不同的命名约定,并随后发现了一个侵入性较小的解决方案

Gson确实支持设置命名约定,在序列化和反序列化时,从Java模型名称映射到JSON名称时使用