Jackson中不区分大小写的JsonNode

zdwk9cvp  于 6个月前  发布在  其他
关注(0)|答案(3)|浏览(114)

我需要格式化JSON对象并以不区分大小写的方式访问字段。示例:

String s = "{\"FOO\": 123}";
ObjectMapper mapper = new ObjectMapper();
JsonNode node = mapper.readTree(s);
node.get("foo"); // this should return the "FOO" field

字符串
这需要高性能,所以调用getFieldNames()并将结果小写不是一个好的解决方案。

wooyq4lh

wooyq4lh1#

没有自动化的方法,但您可以通过创建自定义的JsonNodeFactory来创建自定义的ObjectNode-然后您可以重写用于添加和访问条目的方法。

o2gm4chl

o2gm4chl2#

此功能自2.5(2015年1月)起可用:

ACCEPT_CASE_INSENSITIVE_PROPERTIES

允许对传入的JSON进行更宽容的格式化的特性。如果启用,bean属性将使用它们的小写等效项进行匹配,这意味着任何大小写组合(传入和匹配的名称通过小写规范化)应该可以。注意,由于传入的属性名称在比较之前需要小写,因此存在额外的性能开销,对于有大写字母的情况。对于已经是小写字母的名称的开销应该可以忽略不计。
默认情况下禁用该功能。
https://fasterxml.github.io/jackson-databind/javadoc/2.5/com/fasterxml/jackson/databind/MapperFeature.html

flseospp

flseospp3#

不幸的是,正如其他人所指出的,Jackson的JsonNode并没有提供一个不区分大小写的键查找的内部特性。然而,幸运的是,大多数JsonNode可以很容易地转换为一个map,还有一些其他的Map实现实际上提供了一个不区分大小写的查找。其中最简单的是Spring's LinkedCaseInsensitiveMap,但是Java's TreeMap也可以工作。
我们所要做的就是将JsonNode转换为所选的Map,并在那里进行查找。我在下面列出了一些示例,我使用下面的方法创建一个JsonNode,用于这些类;

public JsonNode createNode()
{
  Map<String, List<String>> table = new HashMap<>();
  table.put("first", new ArrayList<>(Arrays.asList("firstprop1", "firstprop2")));
  table.put("second", new ArrayList<>(Arrays.asList("secondprop1", "secondprop2")));
  table.put("third", new ArrayList<>(Arrays.asList("thirdprop1", "thirdprop2")));

  return new ObjectMapper().valueToTree(table);
}

字符串

LinkedCaseInsensiveMap

如果你正在使用Spring,我推荐使用LinkedCaseInsensitiveMap。你不需要更新你的依赖项,它“保留了键的原始顺序和原始大小写,同时允许包含,获取和删除任何键的调用。”

示例

public JsonNode getCaseInsensitiveKey(JsonNode node, String key)
{
  var mapper = new ObjectMapper();
  Map<String, Object> testing =
      mapper.convertValue(node, mapper.getTypeFactory().constructParametricType(LinkedCaseInsensitiveMap.class, List.class));
  return mapper.valueToTree(testing.get(key));
}

TreeMap

TreeMap是普通的java解决方案。TreeMap采用自定义比较器作为构造函数参数。您可以使用String捆绑的比较器CASE_INSENSITIVE_ORDER来创建不区分大小写的比较器。

示例

public JsonNode getCaseInsensitiveKeyFromTreeMap(JsonNode node, String key)
{
  var mapper = new ObjectMapper();
  TreeMap<String, Object> testing = new TreeMap<>(String.CASE_INSENSITIVE_ORDER);
  testing.putAll(mapper.convertValue(node, mapper.getTypeFactory().constructMapType(Map.class, String.class, List.class)));
  return mapper.valueToTree(testing.get(key));
}

测试

上述方法适用于以下测试。

@Test
public void testCaseInsensitivity()
{
  var testNode = createNode();
  var result1 = getCaseInsensitiveKey(testNode, "first");
  var result2 = getCaseInsensitiveKey(testNode, "FiRsT");
  var result3 = getCaseInsensitiveKey(testNode, "FIRST");
  assertEquals(result1, result2);
  assertEquals(result1, result3);
}

@Test
public void testCaseInsensitivityFromTreeMap()
{
  var testNode = createNode();
  var result1 = getCaseInsensitiveKeyFromTreeMap(testNode, "first");
  var result2 = getCaseInsensitiveKeyFromTreeMap(testNode, "FiRsT");
  var result3 = getCaseInsensitiveKeyFromTreeMap(testNode, "FIRST");
  assertEquals(result1, result2);
  assertEquals(result1, result3);

限制条件

请注意,上面的例子只适用于创建一个Map<String, List>。这意味着它不适用于OP的例子,它Map的是一个整数,而不是一个列表。然而,我们可以修改它,使用java泛型动态分配内部类。

示例

public <T> JsonNode getCaseInsensitiveKey(JsonNode node, String key, Class<T> clazz)
{
  var mapper = new ObjectMapper();
  Map<String, T> testing =
      mapper.convertValue(node, mapper.getTypeFactory().constructParametricType(LinkedCaseInsensitiveMap.class, clazz));
  return mapper.valueToTree(testing.get(key));
}

测试

现在,通过上述修改,我们可以测试OP示例并成功获得正确的结果。

@Test
public void useOfOpExample() throws JsonProcessingException
{
  String s = "{\"FOO\": 123}";
  ObjectMapper mapper = new ObjectMapper();
  JsonNode node = mapper.readTree(s);
  var fooNode1 = getCaseInsensitiveKey(node, "foo", Integer.class);
  var fooNode2 = getCaseInsensitiveKey(node, "FOO", Integer.class);
  assertEquals(fooNode1, fooNode2);
}


我们还可以使用我们以前的测试,稍作修改,也得到相同的结果。

@Test
public void testCaseInsensitivity()
{
  var testNode = createNode();
  var result1 = getCaseInsensitiveKey(testNode, "first", List.class);
  var result2 = getCaseInsensitiveKey(testNode, "FiRsT", List.class);
  var result3 = getCaseInsensitiveKey(testNode, "FIRST", List.class);
  assertEquals(result1, result2);
  assertEquals(result1, result3);
}

相关问题