原文网址:Jackson--使用/教程/示例_IT利刃出鞘的博客-CSDN博客
说明
本文用实例介绍Jackson的使用。
项目中我们经常会用到JSON,比如:将JSON字符串反序列化为对象、将对象序列华为JSON字符串。
实际我们常用的是SpringBoot默认的JakckSon与阿里巴巴的FastJson。个人推荐Jackson,因为它基本没有缺陷,而FastJson有很多缺陷。
Spring Boot支持与三种JSON mapping库集成:Gson、Jackson和JSON-B。Jackson是默认的。
Jackson是spring-boot-starter-json依赖中的一部分,spring-boot-starter-web中包含spring-boot-starter-json。也就是说,当项目中引入spring-boot-starter-web后会自动引入spring-boot-starter-json。
依赖
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency>
ObjectMapper如何匹配JSON对象的字段和Java对象的属性
默认情况下,Jackson通过将JSON字段的名称与Java对象中的getter和setter方法进行匹配,将JSON对象的字段映射到Java对象中的属性。 Jackson删除了getter和setter方法名称的“ get”和“ set”部分,并将其余名称的第一个字符转换为小写。
例如,名为brand的JSON字段与名为getBrand()和setBrand()的Java getter和setter方法匹配。 名为engineNumber的JSON字段将与名为getEngineNumber()和setEngineNumber()的getter和setter匹配。
如果需要以其他方式将JSON对象字段与Java对象字段匹配,则需要使用自定义序列化器和反序列化器,或者使用一些Jackson注解。
其他网址
英文官网(github)
Jackson使用指南 - 掘金 (实例很全)
通用注解(序列化/反序列化都有效)
注解 | 使用位置 | 含义 |
@JsonIgnore | field、getter、 setter、构造方法 | 放任意位置,都意味着忽略所有(即序列化和反序列化都被忽略)。 当setter上注解@JsonIgnore而getter上注解@JsonProperty,就会出现“只读”情况(read from input, but is not written output)。 |
@JsonProperty | 字段 | 表示外部属性名字。即:使用别名序列化,而不是对象的名字。 此注解也可强制字段参与: 1.字段的getter与setter写法不是标准的getXxx这样 2.字段的setter上加了@JsonIgnore,在getter上加@JsonProperty使此属性只读。 |
@JsonIgnoreProperties | 类 | 忽略属性,多个时用“,”隔开。与@JsonIgnore作用一致。 @JsonIgnoreProperties(ignoreUnknown = true):会忽略类中不存在的字段 |
@JsonIgnoreType | 类 | 当其他类有该类作为属性时,该属性将被忽略。 |
序列化注解(只在序列化时有效)
注解 | 使用位置 | 含义 | ||||||||||||||
@JsonPropertyOrder | 类 | 指定属性在 json 字符串中的顺序。 示例:@JsonPropertyOrder(value={"id","name"}) | ||||||||||||||
@JsonFormat | 字段 | 序列化为json后的格式。 示例: @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss",timezone="GMT+8") | ||||||||||||||
@JsonInclude | 属性、类 | 排除属性。用于类:排除所有。 示例:@JsonInclude(JsonInclude.Include.NON_NULL) 只有属性不为 null 时才序列化
| ||||||||||||||
@JsonAnyGetter | getter方法 | 像普通属性一样序列化Map | ||||||||||||||
@JsonGetter | getter方法 | 跟@JsonProperty等效 | ||||||||||||||
@JsonPropertyOrder | 类 | 在序列化的时候自定义属性输出顺序 | ||||||||||||||
@JsonRawValue | 字段 | 按照原样序列化属性的值。 | ||||||||||||||
@JsonValue | 方法、字段 | 定义整个实体的序列化方法,Jackson将会使用该方法的输出作为序列化输出。 类似于toString方法 | ||||||||||||||
@JsonRootName | 类 | 如果需要将实体包装一层,可以使用@JsonRootName来指定根包装器的名称 | ||||||||||||||
@JsonSerialize | 字段、getter方法 | 指定自定义序列化器来序列化实体 |
反序列化注解(只在反序列化时有效)
注解 | 使用位置 | 含义 |
@JsonCreator | 方法、构造器 | 指定反序列化使用的构造函数或方法 实例: @JsonCreator this.id = id; this.name = name; |
@JacksonInject | 方法、字段、参数 | 指定某个字段从注入赋值,而不是从Json |
@JsonAnySetter | 方法、字段 | 在反序列化时,将Map当成普通属性 |
@JsonAnySetter | setter方法 | 指定反序列化时的名称 |
@JsonDeserialize | 字段、setter方法 | 指定自定义反序列化器来反序列化实体 |
作用 | 方法 |
JSON字符串--> Java对象 | Car car = new ObjectMapper().readValue(jsonString, Car.class); |
JSON 字符输入流--> Java对象 | ObjectMapper objectMapper = new ObjectMapper(); String carJson = "{ \"brand\" : \"Mercedes\", \"doors\" : 4 }"; Car car = objectMapper.readValue(reader, Car.class); |
JSON文件--> Java对象 | ObjectMapper objectMapper = new ObjectMapper(); File file = new File("data/car.json"); Car car = objectMapper.readValue(file, Car.class); |
JSON via URL--> Java对象 | ObjectMapper objectMapper = new ObjectMapper(); URL url = new URL("file:data/car.json"); Car car = objectMapper.readValue(url, Car.class); 示例使用文件URL,也可用HTTP URL(例:http://jenkov.com/some-data.json)。 |
JSON字节输入流--> Java对象 | ObjectMapper objectMapper = new ObjectMapper(); InputStream input = new FileInputStream("data/car.json"); Car car = objectMapper.readValue(input, Car.class); |
JSON二进制数组--> Java对象 | ObjectMapper objectMapper = new ObjectMapper(); String carJson = "{ \"brand\" : \"Mercedes\", \"doors\" : 5 }"; byte[] bytes = carJson.getBytes("UTF-8"); Car car = objectMapper.readValue(bytes, Car.class); |
JSON数组字符串--> Java对象数组 | String jsonArray = "[{\"brand\":\"ford\"}, {\"brand\":\"Fiat\"}]"; ObjectMapper objectMapper = new ObjectMapper(); Car[] cars2 = objectMapper.readValue(jsonArray, Car[].class); |
JSON数组字符串--> List | String jsonArray = "[{\"brand\":\"ford\"}, {\"brand\":\"Fiat\"}]"; ObjectMapper objectMapper = new ObjectMapper(); List<Car> cars1 = objectMapper.readValue(jsonArray, new TypeReference<List<Car>>(){}); |
JSON字符串--> Map | String jsonObject = "{\"brand\":\"ford\", \"doors\":5}"; ObjectMapper objectMapper = new ObjectMapper(); |
有时候,与要从JSON读取的Java对象相比,JSON中的字段更多。 默认情况下,Jackson在这种情况下会抛出异常,报不知道XYZ字段异常,因为在Java对象中找不到该字段。
但是,有时应该允许JSON中的字段多于相应的Java对象中的字段。 例如,要从REST服务解析JSON,而该REST服务包含的数据远远超出所需的。 在这种情况下,可以使用Jackson配置忽略这些额外的字段。
objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
简介
将JSON字符串转为Java对象时,如果JSON字符串值为null的字段是Java的基本数据类型(int,long,float,double等),Jackson默认会将这个字段设置为初始值,比如:对于int,则将其设置为0。
我们可以进行自定义配置:基本数据为null让其报错,转换失败。
示例(默认情况)
Entity
package com.example.entity; import lombok.Data; @Data public class User { private String userName; private int age; }
Controller
package com.example.controller; import com.example.entity.User; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController; @RestController public class HelloController { @GetMapping("/test") public String test() throws JsonProcessingException { String json = "{\"userName\":\"Tony\", \"age\":null}"; ObjectMapper objectMapper = new ObjectMapper(); User user = objectMapper.readValue(json, User.class); System.out.println(user); return "test success"; } }
测试
访问:http://localhost:8080/test
后端结果:
示例(自定义配置)
Entity
package com.example.entity; import lombok.Data; @Data public class User { private String userName; private int age; }
Controller
package com.example.controller; import com.example.entity.User; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.DeserializationFeature; import com.fasterxml.jackson.databind.ObjectMapper; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController; @RestController public class HelloController { @GetMapping("/test") public String test() throws JsonProcessingException { String json = "{\"userName\":\"Tony\", \"age\":null}"; ObjectMapper objectMapper = new ObjectMapper(); objectMapper.configure(DeserializationFeature.FAIL_ON_NULL_FOR_PRIMITIVES, true); User user = objectMapper.readValue(json, User.class); System.out.println(user); return "test success"; } }
测试
访问:http://localhost:8080/test
后端结果
2021-09-18 22:12:46.132 ERROR 22264 --- [nio-8080-exec-1] o.a.c.c.C.[.[.[/].[dispatcherServlet] : Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception com.fasterxml.jackson.databind.exc.MismatchedInputException: Cannot map `null` into type int (set DeserializationConfig.DeserializationFeature.FAIL_ON_NULL_FOR_PRIMITIVES to 'false' to allow) at [Source: (String)"{"userName":"Tony", "age":null}"; line: 1, column: 27] (through reference chain: com.example.entity.User["age"]) at com.fasterxml.jackson.databind.exc.MismatchedInputException.from(MismatchedInputException.java:63) ~[jackson-databind-2.11.0.jar:2.11.0] at com.fasterxml.jackson.databind.DeserializationContext.reportInputMismatch(DeserializationContext.java:1438) ~[jackson-databind-2.11.0.jar:2.11.0] at com.fasterxml.jackson.databind.deser.std.NumberDeserializers$PrimitiveOrWrapperDeserializer.getNullValue(NumberDeserializers.java:161) ~[jackson-databind-2.11.0.jar:2.11.0] at com.fasterxml.jackson.databind.deser.impl.MethodProperty.deserializeAndSet(MethodProperty.java:127) ~[jackson-databind-2.11.0.jar:2.11.0] at com.fasterxml.jackson.databind.deser.BeanDeserializer.vanillaDeserialize(BeanDeserializer.java:293) ~[jackson-databind-2.11.0.jar:2.11.0] at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserialize(BeanDeserializer.java:156) ~[jackson-databind-2.11.0.jar:2.11.0] at com.fasterxml.jackson.databind.ObjectMapper._readMapAndClose(ObjectMapper.java:4482) ~[jackson-databind-2.11.0.jar:2.11.0] at com.fasterxml.jackson.databind.ObjectMapper.readValue(ObjectMapper.java:3434) ~[jackson-databind-2.11.0.jar:2.11.0] at com.fasterxml.jackson.databind.ObjectMapper.readValue(ObjectMapper.java:3402) ~[jackson-databind-2.11.0.jar:2.11.0] at com.example.controller.HelloController.test(HelloController.java:18) ~[classes/:na] at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.8.0_201] at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:1.8.0_201] at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:1.8.0_201] at java.lang.reflect.Method.invoke(Method.java:498) ~[na:1.8.0_201] at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:190) ~[spring-web-5.2.6.RELEASE.jar:5.2.6.RELEASE] at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:138) ~[spring-web-5.2.6.RELEASE.jar:5.2.6.RELEASE] at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:105) ~[spring-webmvc-5.2.6.RELEASE.jar:5.2.6.RELEASE] at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:879) ~[spring-webmvc-5.2.6.RELEASE.jar:5.2.6.RELEASE] at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:793) ~[spring-webmvc-5.2.6.RELEASE.jar:5.2.6.RELEASE] at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87) ~[spring-webmvc-5.2.6.RELEASE.jar:5.2.6.RELEASE] at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1040) ~[spring-webmvc-5.2.6.RELEASE.jar:5.2.6.RELEASE] at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:943) ~[spring-webmvc-5.2.6.RELEASE.jar:5.2.6.RELEASE] ... at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61) [tomcat-embed-core-9.0.35.jar:9.0.35] at java.lang.Thread.run(Thread.java:748) [na:1.8.0_201]
有时,可能希望以不同于Jackson ObjectMapper缺省方式的方式将JSON字符串读入Java对象。 可以将自定义反序列化器添加到ObjectMapper,可以按需要执行反序列化。
这是在Jackson的ObjectMapper中注册和使用自定义反序列化器的方式:
String json = "{\"userName\": \"Tony\", \"age\" : 22 }"; SimpleModule module = new SimpleModule("UserDeserializer", new Version(3, 1, 8, null, null, null)); module.addDeserializer(User.class, new UserDeserializer(User.class)); ObjectMapper mapper = new ObjectMapper(); mapper.registerModule(module); User user = mapper.readValue(json, User.class);
自定义反序列化器UserDeserializer类:
public class UserDeserializer extends StdDeserializer<User> { public UserDeserializer(Class<?> vc) { super(vc); } @Override public User deserialize(JsonParser parser, DeserializationContext deserializer) throws IOException { User user = new User(); while(!parser.isClosed()){ JsonToken jsonToken = parser.nextToken(); if(JsonToken.FIELD_NAME.equals(jsonToken)){ String fieldName = parser.getCurrentName(); System.out.println(fieldName); jsonToken = parser.nextToken(); if("userName".equals(fieldName)){ user.setUserName(parser.getValueAsString()); } else if ("age".equals(fieldName)){ user.setAge(parser.getValueAsInt()); } } } return user; } }
其他网址
Java基础之《jackson转换json、获取泛型Type》_csj50的专栏-CSDN博客
实例
Entity
package com.example.entity; import lombok.Data; @Data public class User { private String userName; private Integer age; }
Controller
package com.example.controller; import com.example.entity.User; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.core.type.TypeReference; import com.fasterxml.jackson.databind.JavaType; import com.fasterxml.jackson.databind.ObjectMapper; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController; import java.lang.reflect.Type; import java.util.List; @RestController public class HelloController { @GetMapping("/test") public String test() throws JsonProcessingException { ObjectMapper objectMapper = new ObjectMapper(); // 转为泛型Type指定的类型 //{"userName":"Tony", "age":22} String json1 = "{\"userName\":\"Tony\", \"age\":22}"; Type type1 = User.class; JavaType javaType1 = objectMapper.getTypeFactory().constructType(type1); User user = objectMapper.readValue(json1, javaType1); System.out.println("json1: " + user); // 转为泛型Type指定的类型 //{"success": true, "data": [{"userName":"Tony", "age":22}, {"userName":"Pepper", "age":21}]} String json2 = "{\"success\": true, \"data\": [{\"userName\":\"Tony\", \"age\":22}," + " {\"userName\":\"Pepper\", \"age\":21}]}"; Type type2 = Object.class; JavaType javaType2 = objectMapper.getTypeFactory().constructType(type2); Object object = objectMapper.readValue(json2, javaType2); System.out.println("json2: " + object); // 转为泛型TypeReference里的类型 //{"userName":"Tony", "age":22} String json3 = "{\"userName\":\"Tony\", \"age\":22}"; User user1 = objectMapper.readValue(json3, new TypeReference<User>() {}); System.out.println("json3: " + user1); // 将JSON数组转为List //[{"userName":"Tony", "age":22}, {"userName":"Pepper", "age":21}] String json4 = "[{\"userName\":\"Tony\", \"age\":22}, {\"userName\":\"Pepper\", \"age\":21}]"; JavaType javaType4 = objectMapper.getTypeFactory().constructCollectionType(List.class, User.class); List<User> userList4 = objectMapper.readValue(json4, javaType4); System.out.println("json4: " + userList4); // 将JSON数组转为List //[{"userName":"Tony", "age":22}, {"userName":"Pepper", "age":21}] String json5 = "[{\"userName\":\"Tony\", \"age\":22}, {\"userName\":\"Pepper\", \"age\":21}]"; JavaType javaType5 = objectMapper.getTypeFactory().constructCollectionType(List.class, User.class); List<User> userList5 = objectMapper.readValue(json5, javaType5); System.out.println("json5: " + userList5); return "test success"; } }
测试
访问:http://localhost:8080/test
后端结果:
方法 | 作用 |
String str = new ObjectMapper().writeValueAsString(obj) | Object转JSON字符串 |
byte[] bytes = new ObjectMapper().writeValueAsBytes(obj) | Object转JSON字节数组 |
ObjectMapper objectMapper = new ObjectMapper(); // 序列化BigDecimal时不使用科学计数法输出 objectMapper.configure(JsonGenerator.Feature.WRITE_BIGDECIMAL_AS_PLAIN, true); // 为空的字段不返回 objectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
默认情况下,Jackson会将java.util.Date对象序列化为其long型的值,该值是自1970年1月1日以来的毫秒数。但是,Jackson还支持将日期格式化为字符串。
Date-->long(默认)
该格式将Date序列化为自1970年1月1日以来的毫秒数(long类型)。
@Data public class Transaction{} private String type = null; private Date date = null; public Transaction() { } public Transaction(String type, Date date) { this.type = type; this.date = date; } }
Transaction transaction = new Transaction("transfer", new Date()); ObjectMapper objectMapper = new ObjectMapper(); String output = objectMapper.writeValueAsString(transaction); System.out.println(output);
运行结果
Date-->String(自定义)
Jackson也支持文本日期格式。 可在ObjectMapper上设置SimpleDateFormat来指定要使用的Jackson日期格式。
Transaction transaction = new Transaction("transfer", new Date()); ObjectMapper objectMapper = new ObjectMapper(); SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd"); objectMapper.setDateFormat(dateFormat); String output2 = objectMapper.writeValueAsString(transaction); System.out.println(output2);
运行结果
Jackson具有内置的树模型,可用于表示JSON对象。 如果不知道接收到的JSON的格式,或者由于某种原因而不能(或者只是不想)创建一个类来表示它,那么就要用到Jackson的树模型。 如果需要在使用或转化JSON之前对其进行操作,也需要被用到Jackson树模型。 所有这些情况在数据流场景中都很常见。
Jackson树模型由JsonNode类表示。 您可以使用Jackson ObjectMapper将JSON解析为JsonNode树模型,就像使用您自己的类一样。
JsonNode vs ObjectNode
Jackson JsonNode类是不可变的。 这意味着,实际上不能直接构建JsonNode实例的对象图。 而是创建JsonNode子类ObjectNode的对象图。 作为JsonNode的子类,可以在可以使用JsonNode的任何地方使用ObjectNode。
Jackson Tree Model简单例子
String carJson = "{ \"brand\" : \"Mercedes\", \"doors\" : 5 }"; ObjectMapper objectMapper = new ObjectMapper(); try { JsonNode jsonNode = objectMapper.readValue(carJson, JsonNode.class); //或者JsonNode jsonNode = objectMapper.readTree(carJson); } catch (IOException e) { e.printStackTrace(); }
访问JSON字段,数组和嵌套对象
String carJson = "{ \"brand\" : \"Mercedes\", \"doors\" : 5," + " \"owners\" : [\"John\", \"Jack\", \"Jill\"]," + " \"nestedObject\" : { \"field\" : \"value\" } }"; ObjectMapper objectMapper = new ObjectMapper(); try { JsonNode jsonNode = objectMapper.readValue(carJson, JsonNode.class); JsonNode brandNode = jsonNode.get("brand"); String brand = brandNode.asText(); System.out.println("brand = " + brand); JsonNode doorsNode = jsonNode.get("doors"); int doors = doorsNode.asInt(); System.out.println("doors = " + doors); JsonNode array = jsonNode.get("owners"); JsonNode jsonNode = array.get(0); String john = jsonNode.asText(); System.out.println("john = " + john); JsonNode child = jsonNode.get("nestedObject"); JsonNode childField = child.get("field"); String field = childField.asText(); System.out.println("field = " + field); } catch (IOException e) { e.printStackTrace(); }
将JSON解析为JsonNode(或JsonNode实例树)后,就可以浏览JsonNode树模型。
请注意,JSON字符串现在包含一个称为owners的数组字段和一个称为nestedObject的嵌套对象字段。
无论访问的是字段,数组还是嵌套对象,都可以使用JsonNode类的get()方法。 通过将字符串作为参数提供给get()方法,可以访问JsonNode的字段。 如果JsonNode表示数组,则需要将索引传递给get()方法。 索引指定要获取的数组元素。
作用 | 方法 | 说明 |
Java对象-->JsonNode | ObjectMapper objectMapper = new ObjectMapper(); Car car = new Car(); JsonNode carJsonNode = objectMapper.valueToTree(car); | JsonNode是转换后的Java对象的JSON表示形式。 可以通过Jackson ObjectMapper valueToTree()方法将Java对象转换为JsonNode。 |
JsonNode-->Java对象 | ObjectMapper objectMapper = new ObjectMapper(); String carJson = "{ \"brand\" : \"Mercedes\", \"doors\" : 5 }"; JsonNode carJsonNode = objectMapper.readTree(carJson); Car car = objectMapper.treeToValue(carJsonNode); | 示例有点“人为”,因为我们首先将JSON字符串转换为JsonNode,然后将JsonNode转换为Car对象。 显然,如果我们有对原始JSON字符串的引用,则最好将其直接转换为Car对象,而无需先将其转换为JsonNode。 |
JSON-->JsonNode | String json = "{ \"f1\" : \"v1\" } "; ObjectMapper objectMapper = new ObjectMapper(); JsonNode jsonNode = objectMapper.readTree(json); System.out.println(jsonNode.get("f1").asText()); | 要使用Jackson将JSON读取到JsonNode中,首先需要创建一个Jackson ObjectMapper实例。 在ObjectMapper实例上,调用readTree()并将JSON源作为参数传递。 |
JsonNode-->JSON | ObjectMapper objectMapper = new ObjectMapper(); JsonNode jsonNode = readJsonIntoJsonNode(); String json = objectMapper.writeValueAsString(jsonNode); | 要将Jackson的JsonNode写入JSON,还需要一个Jackson ObjectMapper实例。 在ObjectMapper上,调用writeValueAsString()方法或任何适合需要的写入方法 |
获取JsonNode字段 | 假设已将以下JSON解析为JsonNode { 此JSON对象具有两个名为field1和field2的字段。 如果有一个表示上述JSON对象的Jackson JsonNode,则可以这样获得两个字段: JsonNode jsonNode = ... //parse above JSON into a JsonNode JsonNode field1 = jsonNode.get("field1"); | JsonNode可以像JSON对象一样具有字段。 即使两个字段都是String字段,get()方法也始终返回JsonNode来表示该字段。 |
路径中获取JsonNode字段 | 假设JSON结构如下所示: { JsonNode nameNode = jsonNode.at("/identification/name"); | Jackson JsonNode有一个称为at()的特殊方法。 at()方法可以从JSON图中以给定JsonNode为根的任何位置访问JSON字段。 注意传递给at()方法的参数:字符串/ identification / name。 这是一个JSON路径表达式。 此路径表达式指定从根JsonNode到您要访问其值的字段的完整路径。 这类似于从文件系统根目录到Unix文件系统中文件的路径。 请注意,JSON路径表达式必须以斜杠字符(/字符)开头。 at()方法返回一个JsonNode,它表示请求的JSON字段。 要获取该字段的实际值,需要调用下一部分介绍的方法之一。 如果没有节点与给定的路径表达式匹配,则将返回null。 |
转换JsonNode字段 | String f2Str = jsonNode.get("f2").asText(); //使用默认值转换 ObjectMapper objectMapper = new ObjectMapper(); String json = "{ \"f1\":\"Hello\", \"f2\":null }"; JsonNode jsonNode = objectMapper.readTree(json); String f2Value = jsonNode.get("f2").asText("Default"); //错误示例 ObjectMapper objectMapper = new ObjectMapper(); String json = "{ \"f1\":\"Hello\" }"; JsonNode jsonNode = objectMapper.readTree(json); JsonNode f2FieldNode = jsonNode.get("f2"); | Jackson JsonNode类包含一组可以将字段值转换为另一种数据类型的方法。 例如,将String字段值转换为long或相反。 使用默认值转换: 如果JsonNode中的字段可以为null,则在尝试转换它时可以提供默认值。 在示例的JSON字符串中可以看到,声明了f2字段,但将其设置为null。 在这种情况下,调用jsonNode.get(“ f2”)。asText(“ Default”)将返回默认值,在此示例中为字符串Default。 asDouble(),asInt()和asLong()方法还可以采用默认参数值,如果尝试从中获取值的字段为null,则将返回默认参数值。 请注意,如果该字段在JSON中未显式设置为null,但在JSON中丢失,则调用jsonNode.get(“ fieldName”)将返回Java null值,您无法在该Java值上调用asInt() ,asDouble(),asLong()或asText()。 如果尝试这样做,将会导致NullPointerException。 |
创建一个ObjectNode | ObjectMapper objectMapper = new ObjectMapper(); ObjectNode objectNode = objectMapper.createObjectNode(); | 如前所述,JsonNode类是不可变的。 要创建JsonNode对象图,必须能够更改图中的JsonNode实例,例如 设置属性值和子JsonNode实例等。由于是不可变的,因此无法直接使用JsonNode来实现。而是创建一个ObjectNode实例,该实例是JsonNode的子类。 |
Set ObjectNode字段 | ObjectMapper objectMapper = new ObjectMapper(); JsonNode childNode = readJsonIntoJsonNode(); parentNode.set("child1", childNode); | 要在Jackson ObjectNode上设置字段,可以调用其set()方法,并将字段名称String和JsonNode作为参数传递。 |
Put ObjectNode字段 | objectNode.put("field1", "value1"); objectNode.put("field2", 123); objectNode.put("field3", 999.999); | ObjectNode类还具有一组方法,可以直接为字段put(设置)值。 这比尝试将原始值转换为JsonNode并使用set()进行设置要容易得多。 |
删除字段 | objectNode.remove("fieldName"); | ObjectNode类具有一个称为remove()的方法,该方法可用于从ObjectNode中删除字段。 |
循环JsonNode字段 | Iterator<String> fieldNames = jsonNode.fieldNames(); while(fieldNames.hasNext()) { JsonNode field = jsonNode.get(fieldName); | JsonNode类具有一个名为fieldNames()的方法,该方法返回一个Iterator,可以迭代JsonNode的所有字段名称。 我们可以使用字段名称来获取字段值。 |
场景
package com.example.config; import com.alibaba.fastjson.JSON; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.json.JsonMapper; import com.sun.org.apache.regexp.internal.RE; import org.springframework.beans.BeansException; import org.springframework.boot.ApplicationArguments; import org.springframework.boot.ApplicationRunner; import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContextAware; import org.springframework.stereotype.Component; import org.springframework.web.method.HandlerMethod; import org.springframework.web.servlet.mvc.method.RequestMappingInfo; import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping; import java.util.Map; @Component public class ApplicationContextTest implements ApplicationContextAware, ApplicationRunner { private ApplicationContext applicationContext; RequestMappingHandlerMapping handlerMapping; @Override public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { this.applicationContext = applicationContext; } @Override public void run(ApplicationArguments args) throws Exception { handlerMapping = applicationContext.getBean(RequestMappingHandlerMapping.class); Map<RequestMappingInfo, HandlerMethod> handlerMethods = handlerMapping.getHandlerMethods(); } public RequestMappingHandlerMapping getHandlerMapping() { return handlerMapping; } }
package com.example.controller; import com.alibaba.fastjson.JSON; import com.example.config.ApplicationContextTest; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; @RestController @RequestMapping("/hello") public class HelloController { @Autowired ApplicationContextTest applicationContextTest; @GetMapping("/test1") public String test1() { return "hello"; } @GetMapping("/test2") public String test2() throws JsonProcessingException { System.out.println(new ObjectMapper().writeValueAsString(applicationContextTest.getHandlerMapping())); return "hehe"; } }
错误日志:
com.fasterxml.jackson.databind.exc.InvalidDefinitionException: No serializer found for class org.springframework.boot.context.properties.source.SoftReferenceConfigurationPropertyCache and no properties discovered to create BeanSerializer (to avoid exception, disable SerializationFeature.FAIL_ON_EMPTY_BEANS) (through reference chain: org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping["applicationContext"]->org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext["environment"]->org.springframework.web.context.support.StandardServletEnvironment["propertySources"]->org.springframework.boot.context.properties.source.ConfigurationPropertySourcesPropertySource["source"]->org.springframework.boot.context.properties.source.SpringIterableConfigurationPropertySource["caching"])
解决方法:配置ObjectMapper这个bean,关闭空bean的报错,使用ObjectMapper时直接注入
package com.example.config; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.SerializationFeature; import org.springframework.context.annotation.Bean; import org.springframework.stereotype.Component; @Component public class ObjectMapperConfiguration { @Bean public ObjectMapper objectMapper() { return new ObjectMapper().disable(SerializationFeature.FAIL_ON_EMPTY_BEANS); } }
package com.example.controller; import com.alibaba.fastjson.JSON; import com.example.config.ApplicationContextTest; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; @RestController @RequestMapping("/hello") public class HelloController { @Autowired ApplicationContextTest applicationContextTest; @Autowired ObjectMapper objectMapper; @GetMapping("/test1") public String test1() { return "hello"; } @GetMapping("/test2") public String test2() throws JsonProcessingException { System.out.println(objectMapper.writeValueAsString(applicationContextTest.getHandlerMapping())); return "hehe"; } }
但是,又报其他错误(死循环了):
Caused by: java.lang.StackOverflowError: null
Jackson使用详解 - 掘金