简介
本文介绍Jackson的配置方式。(配置ObjectMapper)。
配置示例
ObjectMapper objectMapper = new ObjectMapper(); // 反序列化:JSON字段中有Java对象中没有的字段时不报错 objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); // 反序列化:不允许基本类型为null //objectMapper.configure(DeserializationFeature.FAIL_ON_NULL_FOR_PRIMITIVES, true); // 序列化:序列化BigDecimal时不使用科学计数法输出 objectMapper.configure(JsonGenerator.Feature.WRITE_BIGDECIMAL_AS_PLAIN, true); // 序列化:Java对象为空的字段不拼接JSON //objectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
反序列化的配置
忽略未知的JSON字段
有时候,Java对象的字段比JSON字符串中的字段少。 默认情况下,Jackson会抛出异常,报不知道xxx字段异常,因为在Java对象中找不到该字段。
大多数情况下,我们想允许JSON中的字段多于相应的Java对象中的字段。 例如,要从REST服务解析JSON,而该REST服务包含的数据远远超出所需的。 在这种情况下,可以使用Jackson配置忽略这些额外的字段。
objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
不允许基本类型为null
简介
将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"; } }
测试
后端结果:
实例:修改配置
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"; } }
测试
后端结果
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]
自定义反序列化
可以将自定义反序列化器添加到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; } }
请先
!