如何使用Gson以不区分大小写的方式使用containsKey?

时间:2016-09-21 18:51:24

标签: java json gson

我有一个JSON字符串,我使用Gson转换为JSON Object。但是,我想使用containsKey作为不区分大小写的方式。

这就是我现在正在做的事情。

    ByteBuffer buffer = ByteBuffer.wrap(payload);
    String data = forName("UTF-8").newDecoder().decode(buffer).toString();

    Gson gson = new Gson();
    Map<String, String> map = gson.fromJson(data, new TypeToken<HashMap<String, Object>>() {
    }.getType());

然后我使用此方法isTupleValid来检查元组是否有效。

private boolean isTupleValid(Map<String, String> map) {
    return map != null && map.containsKey(TYPE)
            && map.containsKey(XID)
            && map.containsKey(CTP)
            && map.get(TYPE).equals("pageview");
}

但是,有时json字符串可能是

{"xid": "xid"}或它可以是{"xID":"xid"}

有没有办法以区分大小写的方式使用containsKey

2 个答案:

答案 0 :(得分:0)

gson.fromJson(data, new TreeMap<>(...).getClass())没有多大意义,因为getClass()只返回对象类,而不是它的内部状态 - 简单来说,无论传递给{的参数是什么,总是得到TreeMap.class {1}}构造函数。

对我来说,有两种选择。他们两个使用“规范化”地图,各有利弊。

首先,让我们创建公共类,以便在两种方法演示之间分享基础知识:

Commons.java

TreeMap

CaseInsensitive1.java

此选项不会触及原始的反序列化策略,因此使用代码必须检查不区分大小写的本身。有必要将“地图规范化”代码放在有意义的地方。请注意,原始地图保持不变。

final class Commons {

    private Commons() {
    }

    static final String CTP = "ctp";
    static final String TYPE = "type";
    static final String XID = "xid";

    static final String JSON_1 = "{\"xid\":\"foo\",\"type\":\"pageview\",\"ctp\":\"ctp\"}";
    static final String JSON_2 = "{\"xID\":\"foo\",\"tYPE\":\"pageview\",\"cTP\":\"ctp\"}";

    static Map<String, Object> normalizeMap(final Map<String, Object> map) {
        final Map<String, Object> normalized = new TreeMap<>(CASE_INSENSITIVE_ORDER);
        normalized.putAll(map);
        return normalized;
    }

}

CaseInsensitive2.java

此选项创建一个特殊的GSON实例,以“规范化”方式反序列化public final class CaseInsensitive1 { private CaseInsensitive1() { } public static void main(final String... args) { final Gson gson = new Gson(); @SuppressWarnings("unchecked") final Map<String, Object> map1 = gson.fromJson(JSON_1, Map.class); @SuppressWarnings("unchecked") final Map<String, Object> map2 = gson.fromJson(JSON_2, Map.class); out.println(isTupleValid(map1)); out.println(isTupleValid(map2)); } private static boolean isTupleValid(final Map<String, Object> map) { if ( map == null ) { return false; } final Map<String, Object> ciMap = normalizeMap(map); return ciMap.containsKey(TYPE) && ciMap.containsKey(XID) && ciMap.containsKey(CTP) && ciMap.get(TYPE).equals("pageview"); } } 。请注意,自从我为该具体类型映射反序列化策略后,Map<String, Object>随处可见。当然,它可能只映射到mapStringObjectTypeMap.class需要另一个GSON实例才能“继承”您可能需要的基本构建的行为。尽管decorateGson方法现在与您的方法等效,但此选项的缺点是您丢失了原始JSON对象的属性顺序。但是,您可能希望使用case-insensitive maps not based on TreeMap(不确定,但它可以使地图以不区分​​大小写的方式保持原始属性顺序)。

isTupleValid

对我来说,选项#1看起来更好,因为它没有以任何方式装饰原始反序列化的对象(如果我以后需要它在代码中区分大小写?)并且执行不区分大小写的检查只有才真正需要

答案 1 :(得分:0)

如果只需要检查键是否存在而无需检索值。您可以访问keySet。流式传输并使用anyMatch谓词调用ignoreCase。就您而言:

return ciMap.keySet().stream().anyMatch(key -> key.equalsIgnoreCase(TYPE))
                && ciMap.keySet().stream().anyMatch(key -> key.equalsIgnoreCase(XID))
                && ciMap.keySet().stream().anyMatch(key -> key.equalsIgnoreCase(CTP))
                && ciMap.get(TYPE).equals("pageview");

PS:您可以考虑使用适当的数据结构。在这种情况下,键不能相等,但是返回true。这违反了地图合同。