我正在寻找一种方法,只将JSON请求中的某些字段包含在我的服务中,然后相应地记录它们以避免记录太多数据。
要包含的字段以及日志将在属性文件中配置。
由于我使用Spring Boot作为我的服务,杰克逊JAR应该已经可用。
由于请求JSON与嵌套数组和对象很复杂,因为字段不确定我是否可以通过Jackson实现我的要求。
有没有办法使用Jackson API从输入请求JSON中仅提取某些字段及其值?
基本上,我正在研究2个用例。
1.从Json String中选择一个或多个元素(我打算通过配置传递),然后渲染它们
2.内联选择并更新一个或多个元素。我想在渲染之前屏蔽元素的值。
我提供的代码用于选择我使用的元素和Json以及我期望的内容。
public String getValues(String key,String jsonString){
String fieldNodeStr =null;
try {
ObjectMapper mapper = new ObjectMapper();
JsonNode node = mapper.readTree(jsonString);
JsonNode fieldNode = node.at(key);
fieldNodeStr = mapper.writerWithDefaultPrettyPrinter().writeValueAsString(fieldNode);
System.out.println(fieldNodeStr);
} catch (IOException e) {
System.out.println("IOException:",e);
}catch (Exception e) {
System.out.println("Exception:",e);
}
}
我的Json如下,
{
"employeeId" : "5353",
"salesId" : "sales005",
"manager" : {
"userId" : "managerUser",
"isSuperUser" : false,
"firstName":"manager first name",
"lastName":"manager last name"
},
"administrator" : {
"userId" : "administratorUser",
"isSuperUser" : false,
"firstName":"admin first name",
"lastName":"admin last name"
},
"requester" : [
{
"id":"1234",
"demographic" : {
"firstName" : "hello",
"lastName" : "hai"
}
},
{
"id":"1235",
"demographic" : {
"firstName" : "welcome",
"lastName" : "user"
}
}
]
}
我有两个问题如下。
如果我传递“/ manager / userId”,“/ administrator / isSuperUser”(OR)“/ salesId”我可以获得预期值。
但是,如果想要获取/ requester / id(OR)/ requester / demographic(OR)/ requester / demographic / lastName,我无法获取。 我得到空值。
当我通过“/ requester / id”(OR)“/ requester / demographic”时,我期待以下内容。
"requester" : [
{
"id":"1234"
},
{
"id":"1235"
}
]
"requester" : [
{
"demographic" : {
"firstName" : "hello",
"lastName" : "hai"
}
},
{
"demographic" : {
"firstName" : "welcome",
"lastName" : "user"
}
}
]
除了fetch之外,我还希望在使用JsonPointer定位它们后更新内联值
我的代码如下所示,用于更新
public String findAndUpdate(String key,String jsonString,String repValue){
String fieldNodeStr =null;
try {
ObjectMapper mapper = new ObjectMapper();
JsonNode node = mapper.readTree(jsonString);
JsonNode fieldNode = node.at(key);
//Update the value of located node to a different one
((ObjectNode) fieldNode).put(key,repValue);
fieldNodeStr = mapper.writerWithDefaultPrettyPrinter().writeValueAsString(fieldNode);
System.out.println(fieldNodeStr);
} catch (IOException e) {
System.out.println("IOException:",e);
}catch (Exception e) {
System.out.println("Exception:",e);
}
return fieldNodeStr;
}
当我通过“/ manager / userId”作为键的值时,我得到以下错误,
17:21:24.829 [main] ERROR com.demo.jsondemo.TestClass - Exception:
java.lang.ClassCastException: com.fasterxml.jackson.databind.node.TextNode cannot be cast to com.fasterxml.jackson.databind.node.ObjectNode
at com.demo.jsondemo.TestClass.findAndUpdate(TestClass.java:95) [classes/:na]
at com.demo.jsondemo.TestClass.main(TestClass.java:221) [classes/:na]
答案 0 :(得分:2)
您可以使用RFC 6901定义的JSON指针(用于标识JSON文档中特定值的字符串语法)。
出于示例目的,请考虑以下JSON:
{
"firstName": "John",
"lastName": "Doe",
"address": {
"street": "21 2nd Street",
"city": "New York",
"postalCode": "10021-3100",
"coordinates": {
"latitude": 40.7250387,
"longitude": -73.9932568
}
}
}
要查询coordinates
节点,可以使用以下JSON指针表达式:
/address/coordinates
Jackson 2.3.0引入了对JSON Pointer的支持,可以使用如下:
String json = "{\"firstName\":\"John\",\"lastName\":\"Doe\",\"address\":{\"street\":"
+ "\"21 2nd Street\",\"city\":\"New York\",\"postalCode\":\"10021-3100\","
+ "\"coordinates\":{\"latitude\":40.7250387,\"longitude\":-73.9932568}}}";
ObjectMapper mapper = new ObjectMapper();
JsonNode node = mapper.readTree(json);
JsonNode coordinatesNode = node.at("/address/coordinates");
可以将coordinates
节点解析为bean:
Coordinates coordinates = mapper.treeToValue(coordinatesNode, Coordinates.class);
或者可以写成String
:
String coordinatesNodeAsString = mapper.writerWithDefaultPrettyPrinter()
.writeValueAsString(coordinatesNode);
JSON指针的一个很好的替代品是JSONPath。在Java中,有一个名为Jayway JsonPath的实现,它与Jackson集成。
要使用JsonPath查询coordinates
节点,可以使用以下表达式:
$.address.coordinates
查询节点的代码如下:
JsonNode coordinatesNode = JsonPath.parse(json)
.read("$.address.coordinates", JsonNode.class);
JsonPath需要以下依赖项:
<dependency>
<groupId>com.jayway.jsonpath</groupId>
<artifactId>json-path</artifactId>
<version>2.2.0</version>
</dependency>
而且,为了与杰克逊整合,需要以下几行:
Configuration.setDefaults(new Configuration.Defaults() {
private final JsonProvider jsonProvider = new JacksonJsonProvider();
private final MappingProvider mappingProvider = new JacksonMappingProvider();
@Override
public JsonProvider jsonProvider() {
return jsonProvider;
}
@Override
public MappingProvider mappingProvider() {
return mappingProvider;
}
@Override
public Set<Option> options() {
return EnumSet.noneOf(Option.class);
}
});
根据您在问题中提供的其他详细信息,我会说JSONPath将为您提供JSON指针的更多灵活性。
您可以尝试以下操作:
/requester/id
。$.requester[*].id
/requester/demographic
。$.requester[*].demographic
这些表达式可以在线测试。看看以下资源:
阅读Jayway JsonPath documentation以了解如何正确使用它。
答案 1 :(得分:0)
Jackson的JsonView注释应该允许您使用特定视图标记某些字段/ getter。以下内容应该有效。
public class Item {
public static class LoggingView {}
@JsonView(LoggingView.class)
public int id;
@JsonView(LoggingView.class)
public String name;
public byte[] data;
}
通过执行以下操作,您可以在不编写id
的情况下撰写name
和data
:
public class Something {
private static final Logger logger = LoggerFactory.getLogger();
private static final ObjectWriter loggingItemWriter = new ObjectMapper().writerWithView(Item.LoggingView.class);
public void doSomething(Item item) {
...
logger.info(loggingItemWriter.writeValueAsString(item));
...
}
}