当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();
}
答案 0 :(得分:8)
不幸的是,使用GsonBuilder
注册FieldNamingStrategy
并没有太大作用,因为它仅在与期望相反的方向上进行转换:从Java字段名称到JSON元素名称。它不能合理地用于您的目的。
(详情:
翻译请求的结果在FieldNamingStrategy.translateName(Field)
结束,其中翻译的名称用于从JsonObject
获取关联的JSON元素,LinkedHashMap<String, JsonElement>
具有members
,称为{{1}将JSON元素名称映射到它们的关联值。已翻译的名称用作get(String)
members
方法的参数,Gson不提供此最终调用的机制,使其不区分大小写。
members
地图填充了来自JsonObject.add(String, JsonElement)
的{{1}}调用,其中Streams.parseRecursive(JsonReader)
检索到的JSON元素名称是“成员”的关键字。 (JsonReader
使用与JSON中完全相同的字符,但发现转义字符'\'的例外情况。)在整个调用堆栈中,Gson没有为用于填充{{1}的密钥提供机制。改变,例如,使所有小写或全部大写。
JsonReader
的工作方式相同。)
合理的解决方案可能是简单地使用自定义反序列化器,如下所示。
<强> input.json:强>
members
<强> Foo.java:强>
FieldNamingPolicy
或者,您可以首先处理原始JSON以将所有元素名称更改为相同的大小写,所有元素名称都更低或全部更高。然后,将更改后的JSON传递给Gson进行反序列化。这当然会减慢JSON处理速度。
如果您能够更改项目的Gson代码,那么最有效的结果可能就是调用[
{"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);
}
}
。由于name = nextString((char) quote);
也用于获取JSON元素值,我可能只是为了获取名称而复制它,然后进行小的更改以强制将元素名称强制为所有较低或全部大写。当然,这种方法会将您的项目锁定到Gson的一个版本,否则您需要重复此更改以升级到更新的Gson版本。
使用Jackson时,情况显然不同。不幸的是,PropertyNamingStrategy
的翻译工作方式大致相同:它们从Java字段名称转换为JSON元素名称。没有可用的JsonReader
更改会自定义nextString(char)
以强制JSON元素名称为全部大写或全部小写。
答案 1 :(得分: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();
答案 2 :(得分:5)
不幸的是,在当前的实现中似乎没有办法做到这一点。如果您查看Gson源代码,更具体地说是JsonObject实现,您将看到底层数据结构是链接的哈希映射。 get调用只是调用map上的get,而get又使用哈希码和equals方法来查找你要查找的对象。
唯一的方法是为您的密钥强制执行一些命名约定。最简单的方法是将所有键强制为小写。如果你需要混合大小写键,那么你将遇到更多困难,需要编写一个更复杂的算法来转换键,而不是简单地调用jsonKey.toLowerCase()。
答案 3 :(得分:0)
当我遇到在两个端点使用不同的命名约定并随后发现侵入性较小的解决方案的问题时,我偶然发现了这个问题。
Gson 确实支持设置在从 Java 模型名称映射到 JSON 名称时使用的命名约定,无论是在序列化还是反序列化时。使用构建器的 setFieldNamingPolicy 方法更改此行为。
GsonBuilder gsonBuilder = new GsonBuilder();
gsonBuilder.setFieldNamingPolicy(FieldNamingPolicy.UPPER_CAMEL_CASE);
Gson gson = gsonBuilder.create();
请参阅 here 以获取有关该主题的精彩文章,包括对不同政策的概述。
这并不是真正不区分大小写的解决方案,但它确实提供了一种方法来解决许多大小写不匹配的情况。