Jackson,实现Bean和JSON之间的灵活转换(SpringMVC默认的JSON转换器)

待我称王封你为后i 2023-09-30 13:31 15阅读 0赞

Jackson介绍

Jackson是Java最受欢迎的JSON类库之一,包含两个不同的解析器:

  1. Jackson ObjectMapper,将JSON转化为Java对象,或者转换为Jackson特定的树结构
  2. Jackson JsonParser,JSON流解析器,每次只解析一个JSON标记(不做讲解)

Jackson还包含两个不同的生成器:

  1. Jackson ObjectMapper,可以从Java对象生成JSON,或者是从Jackson的树结构生成JSON
  2. Jackson Generator,每次生成一个JSON标记(不做讲解)

在springMVC中的具体应用

在spring项目中如何实现自定义类型的转换,例如如何将数字类型的属性转换为特定的枚举类型。一般来说,项目都会使用不同的数字来代表属性的不同含义,如果在代码中直接用数字类型表示可读性比较差,因此都会定义一个枚举来表示。但是如果每次都需要手工将数字转换为枚举那就太麻烦了,而且估计没人喜欢这样做。那解决方法是什么呢?

那就是让Jackson来替我们完成这个工作。来看下如何做,有如下代码:

  1. @RestController
  2. @RequestMapping("/json/exam")
  3. public class ExamController {
  4. @PostMapping("/getExamList")
  5. public Result<List<GetExamListResVo>> getExamList(@Validated @RequestBody GetExamListReqVo reqVo,
  6. @AuthenticationPrincipal UserDetails userDetails)
  7. throws IOException {
  8. //......
  9. }
  10. }

GetExamListReqVo类:

  1. public class GetExamListReqVo {
  2. private ExamTypeEnum examType;
  3. // get set......
  4. }

ExamStatusEnum枚举类:

  1. public enum ExamTypeEnum implements EnumBase {
  2. UNKNOWN(0, ""),
  3. EXAM_INDEPENDENT(1, "独立考试"),
  4. EXAM_COURSE_SUITE(2, "关联课程");
  5. private final int code;
  6. private final String msg;
  7. ExamTypeEnum(int code, String msg) {
  8. this.code = code;
  9. this.msg = msg;
  10. }
  11. // get......
  12. }
  13. /**
  14. * 枚举类的公共接口,所有枚举均实现了此接口
  15. */
  16. public interface EnumBase {
  17. int getCode();
  18. String getMsg();
  19. static <E extends Enum<?> & EnumBase> E codeOf(Class<E> enumClass, Integer code) {
  20. E[] enumConstants = enumClass.getEnumConstants();
  21. for (E e : enumConstants) {
  22. if (e.getCode() == code) {
  23. return e;
  24. }
  25. }
  26. throw new IllegalArgumentException("the code didn't match any enum,code:" + code + ",enum class:" + enumClass.getName());
  27. }
  28. }

目标:将入参:{“examType”:1} 正确转换为 GetExamListReqVo 对象

为了完成这个目标,只需要编写三个类:

  1. /**
  2. * 实现了EnumBase接口的枚举类对象序列化和反序列化
  3. */
  4. public class EnumBaseModule extends SimpleModule {
  5. public EnumBaseModule() {
  6. super(PackageVersion.VERSION);
  7. // 找到EnumBase接口所在的包下所有实现该接口的枚举类
  8. Set<Class> set = ClassUtils.getAllClassesFromPackage(EnumBase.class.getPackage().getName())
  9. .stream()
  10. .filter(clz -> clz.isEnum() && EnumBase.class.isAssignableFrom(clz))
  11. .collect(Collectors.toSet());
  12. // 动态注册所有实现了EnumBase接口枚举类的序列化器和反序列化器到Jackson
  13. set.forEach(enumClass -> {
  14. addDeserializer(enumClass, new EnumBaseDeserializer(enumClass));
  15. addSerializer(enumClass, new EnumBaseSerializer());
  16. });
  17. }
  18. }
  19. /**
  20. * 用来序列化实现了EnumBase接口的枚举类
  21. */
  22. public class EnumBaseSerializer extends JsonSerializer<EnumBase> {
  23. @Override
  24. public void serialize(EnumBase value, JsonGenerator gen, SerializerProvider serializers)
  25. throws IOException {
  26. if (value != null) {
  27. gen.writeNumber(value.getCode());
  28. } else {
  29. gen.writeNull();
  30. }
  31. }
  32. }
  33. /**
  34. * 将前端传过来的数字转换为实现了EnumBase接口的枚举类对象
  35. */
  36. public class EnumBaseDeserializer<E extends Enum<?> & EnumBase>
  37. extends JsonDeserializer<EnumBase> implements ContextualDeserializer {
  38. private Class<E> targetClass;
  39. public EnumBaseDeserializer() {
  40. }
  41. public EnumBaseDeserializer(Class<E> targetClass) {
  42. this.targetClass = targetClass;
  43. }
  44. @Override
  45. public E deserialize(JsonParser p, DeserializationContext ctxt) throws IOException {
  46. return EnumBase.codeOf(targetClass, p.getIntValue());
  47. }
  48. @Override
  49. public JsonDeserializer<?> createContextual(DeserializationContext ctxt,
  50. BeanProperty property) throws JsonMappingException {
  51. targetClass = (Class<E>) ctxt.getContextualType().getRawClass();
  52. return new EnumBaseDeserializer<>(targetClass);
  53. }
  54. }

然后配置一下springMVC:

  1. @Configuration
  2. public class WebMvcConfig implements WebMvcConfigurer {
  3. @Override
  4. public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
  5. for (HttpMessageConverter<?> converter : converters) {
  6. if (converter instanceof StringHttpMessageConverter) {
  7. ((StringHttpMessageConverter) converter).setDefaultCharset(StandardCharsets.UTF_8);
  8. } else if (converter instanceof MappingJackson2HttpMessageConverter) {
  9. MappingJackson2HttpMessageConverter messageConverter =
  10. (MappingJackson2HttpMessageConverter) converter;
  11. messageConverter.setObjectMapper(objectMapper());
  12. }
  13. }
  14. }
  15. @Bean
  16. public ObjectMapper objectMapper() {
  17. ObjectMapper objectMapper = new ObjectMapper();
  18. objectMapper.setSerializationInclusion(JsonInclude.Include.ALWAYS);
  19. objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
  20. objectMapper.configure(DeserializationFeature.FAIL_ON_INVALID_SUBTYPE, false);
  21. objectMapper.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false);
  22. // 注册所有实现了EnumBase接口的枚举类处理器
  23. objectMapper.registerModule(new EnumBaseModule());
  24. return objectMapper;
  25. }
  26. }

ObjectMapper解析JSON的原理

默认情况下,Jackson通过Java bean的get,set方法,通过去掉get,set再把首字母小写得到的名字去和JSON的属性进行匹配。例如对于getBrand()和setBrand()经过处理得到brand,就会匹配到JSON的brand属性,从而把JSON brand属性的值赋给bean的brand字段。通过一系列这样的处理,就将JSON转换成了Java bean。如果需要以不同的方式来匹配,那么就得使用定制的serializer和deserializer,或者使用Jackson提供的众多的注解。

ObjectMapper创建Java对象的多种方式

Car类定义:

  1. public class Car {
  2. private String brand = null;
  3. private Integer doors = 0;
  4. // get set......
  5. }

测试代码:

  1. String carJson = "{ \"brand\" : \"Mercedes\", \"doors\" : 5 }";
  2. // 从字符串创建
  3. Car car = objectMapper.readValue(carJson, Car.class);
  4. System.out.println(objectMapper.writeValueAsString(car));
  5. // 从Reader创建
  6. Reader reader = new StringReader(carJson);
  7. car = objectMapper.readValue(reader, Car.class);
  8. System.out.println(objectMapper.writeValueAsString(car));
  9. File file = ResourceUtils.getFile("classpath:car.json");
  10. // 从文件创建
  11. car = objectMapper.readValue(file, Car.class);
  12. System.out.println(objectMapper.writeValueAsString(car));
  13. URL url = ResourceUtils.getFile("classpath:car.json").toURI().toURL();
  14. // 从URL创建
  15. car = objectMapper.readValue(url, Car.class);
  16. System.out.println(objectMapper.writeValueAsString(car));
  17. InputStream input = new FileInputStream(file);
  18. // 从InputStream创建
  19. car = objectMapper.readValue(input, Car.class);
  20. System.out.println(objectMapper.writeValueAsString(car));
  21. String jsonArray = "[{\"brand\":\"ford\"}, {\"brand\":\"Fiat\"}]";
  22. // 解析为数组
  23. Car[] cars = objectMapper.readValue(jsonArray, Car[].class);
  24. System.out.println(objectMapper.writeValueAsString(cars));
  25. // 解析为list
  26. List<Car> carList = objectMapper.readValue(jsonArray, new TypeReference<List<Car>>() {
  27. });
  28. System.out.println(objectMapper.writeValueAsString(carList));
  29. String jsonObjectStr = "{\"brand\":\"ford\", \"doors\":5}";
  30. // 解析为Map
  31. Map<String, Object> map = objectMapper.readValue(jsonObjectStr,
  32. new TypeReference<Map<String, Object>>() {
  33. });
  34. System.out.println(objectMapper.writeValueAsString(map));

配置ObjectMapper的工作方式

有时JSON会拥有比Java对象更多的属性,这种情况下Jackson默认会抛出异常,大概意思是说JSON某个属性未知因为在Java bean中未找到该属性。

然而,有时我们的确会遇到JSON属性比Java对象多的情况。例如我们从REST service获取的JSON会包含更多不需要的属性,这种情况下,Jackson允许通过配置来忽略未知的属性,像这样:

  1. objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);

原始类型的null处理

  1. public class Car {
  2. private String brand = null;
  3. private int doors = 0;// 原始类型int
  4. // get set......
  5. }

对于{ “brand”:“Toyota”, “doors”:null }

Car类的doors是原始类型int,不能被赋值为null,因此Jackson对于原始类型的null值默认会忽略,然而我们也可以配置Jackson在这种情况下做失败处理:

  1. objectMapper.configure(DeserializationFeature.FAIL_ON_NULL_FOR_PRIMITIVES, true);

设为true后对于试图解析原始类型的null就会抛出异常。还有其他更多的配置等等,例如:

  1. // 遇到无效的子类型也不会解析失败
  2. objectMapper.configure(DeserializationFeature.FAIL_ON_INVALID_SUBTYPE, false);
  3. // 对于空的bean也不会失败
  4. objectMapper.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false);

更多配置请查阅API说明

Jackson对于Date类的处理

默认情况下Date类型属性会被序列化long的毫秒数,然而Jackson也支持将Date序列化成特定格式的日期字符串

  1. public class Transaction {
  2. /**
  3. * 单独指定序列化后的格式和反序列化时以此格式来解析日期字符串
  4. */
  5. @JsonFormat(pattern = "yyyyMMdd HH:mm:ssSSS", locale = "zh_CN", timezone = "GMT+8")
  6. private Date date = null;
  7. private Date create = null;
  8. // get set......
  9. }

测试代码:

  1. Transaction transaction = new Transaction();
  2. transaction.setCreate(new Date());
  3. transaction.setDate(new Date());
  4. String resJson = objectMapper.writeValueAsString(transaction);
  5. // 默认把时间序列化为long
  6. // {"date":"20190618 11:33:42845","create":1560828822845}
  7. System.out.println(resJson);

可以改为序列化成日期字符串:

  1. SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.SIMPLIFIED_CHINESE);
  2. dateFormat.setTimeZone(TimeZone.getTimeZone("GMT+8"));
  3. // 设置这个会影响所有Bean的Date序列化和反序列化
  4. objectMapper.setDateFormat(dateFormat);
  5. resJson = objectMapper.writeValueAsString(transaction);
  6. // {"date":"20190618 11:33:42845","create":"2019-06-18 11:33:42"}
  7. System.out.println(resJson);
  8. String transactionJsonStr = "{\"type\":\"transfer\",\"date\":\"20190118 14:27:52052\",\"create\":\"2019-01-18 14:27:52\"," +
  9. "\"transactionTypeEnum\":\"TICKET\",\"transactionType\":2,\"carTypeEnum\":3}";
  10. transaction = objectMapper.readValue(transactionJsonStr, Transaction.class);
  11. System.out.println(transaction);

Jackson的树模型JsonNode

Jackson内置有树模型用来代表JSON对象,这个树模型具体有什么用呢?当你不知道要解析的JSON的结构你就会发现它会很有用,或者由于某种原因你没法创建一个类来表示这个JSON对象。另外一个好处是你可以在使用这个JSON对象之前操纵这个JSON对象,核心类是JsonNode。

  1. String carJson =
  2. "{ \"brand\" : \"Mercedes\", \"doors\" : 5," +
  3. " \"owners\" : [\"John\", \"Jack\", \"Jill\"]," +
  4. " \"nestedObject\" : { \"field\" : \"value\" } }";
  5. JsonNode jsonNode = objectMapper.readValue(carJson, JsonNode.class);
  6. // 或者
  7. jsonNode = objectMapper.readTree(carJson);
  8. // 取JSON属性值
  9. JsonNode brandNode = jsonNode.get("brand");
  10. String brand = brandNode.asText();
  11. System.out.println("brand = " + brand);
  12. JsonNode doorsNode = jsonNode.get("doors");
  13. int doors = doorsNode.asInt();
  14. System.out.println("doors = " + doors);
  15. // 取JSON数组
  16. JsonNode jsonArray = jsonNode.get("owners");
  17. JsonNode jsonArrayNode = jsonArray.get(0);
  18. String john = jsonArrayNode.asText();
  19. System.out.println("john = " + john);
  20. // 取JSON内嵌对象
  21. JsonNode childNode = jsonNode.get("nestedObject");
  22. JsonNode childField = childNode.get("field");
  23. String field = childField.asText();
  24. System.out.println("field = " + field);

JsonNode类是不可变的,意味着我们不能直接创建该类的对象,然而可以使用JsonNode的子类ObjectNode来构建对象:

  1. // 创建ObjectNode
  2. ObjectNode objectNode = objectMapper.createObjectNode();
  3. objectNode.put("brand", "Mercedes");
  4. objectNode.put("doors", 5);
  5. ObjectNode nestNode = objectMapper.createObjectNode();
  6. nestNode.put("field", "value");
  7. objectNode.set("nestedObject", nestNode);
  8. System.out.println(objectMapper.writeValueAsString(objectNode));

Jackson注解

主要可分为三类:

读写注解(同时影响序列化和反序列化过程)

  • @JsonIgnore
  • @JsonIgnoreProperties
  • @JsonIgnoreType
  • @JsonAutoDetect
  • @JsonProperty
  • @JsonTypeInfo
  • @JsonSubTypes

读注解(只影响反序列化过程)

  • @JsonSetter
  • @JsonAnySetter
  • @JsonCreator
  • @JsonDeserialize

写注解(只影响序列化过程)

  • @JsonInclude
  • @JsonGetter
  • @JsonAnyGetter
  • @JsonPropertyOrder
  • @JsonRawValue
  • @JsonValue
  • @JsonSerialize

@JsonIgnore用于需要忽略的属性(不参与序列化和反序列化)

  1. public class PersonIgnore {
  2. @JsonIgnore
  3. private long personId = 0;
  4. private String name = null;
  5. // get set......
  6. }
  7. PersonIgnore obj = new PersonIgnore(1,"John");
  8. // {"name":"John"}
  9. System.out.println(objectMapper.writeValueAsString(obj));

@JsonIgnoreProperties用于需要忽略的一系列属性

  1. @JsonIgnoreProperties({
  2. "firstName", "lastName"})
  3. public class PersonIgnoreProperties {
  4. private long personId = 0;
  5. private String firstName = null;
  6. private String lastName = null;
  7. // get set......
  8. }
  9. PersonIgnoreProperties personIgnoreProperties = new PersonIgnoreProperties(1,"John","Rod");
  10. // {"personId":1}
  11. System.out.println(objectMapper.writeValueAsString(personIgnoreProperties));;

@JsonIgnoreType表明所有用到此类的地方都会被忽略

  1. public class PersonIgnoreType {
  2. private long personId = 0;
  3. private String name = null;
  4. private Address address = null;
  5. //get set......
  6. }
  7. @JsonIgnoreType
  8. public class Address {
  9. private String streetName = null;
  10. private String houseNumber = null;
  11. private String zipCode = null;
  12. private String city = null;
  13. private String country = null;
  14. // get set......
  15. }
  16. PersonIgnoreType obj = new PersonIgnoreType(1, "John", new Address("China"));
  17. // {"personId":1,"name":"John"}
  18. System.out.println(objectMapper.writeValueAsString(obj));

@JsonAutoDetect用于检测需要将哪类访问权限的属性参与序列化和反序列化

  1. @JsonAutoDetect(fieldVisibility = JsonAutoDetect.Visibility.ANY )
  2. public class PersonAutoDetect {
  3. private long personId = 123;
  4. private String name = null;
  5. // get set......
  6. }

JsonAutoDetect.Visibility用于指明可见性级别,包括ANY, DEFAULT, NON_PRIVATE, NONE, PROTECTED_AND_PRIVATE and PUBLIC_ONLY

@JsonProperty表明序列化和反序列化时以注解指明的为准

  1. public class Person {
  2. @JsonProperty("id")
  3. private long personId = 0;
  4. private String name = null;
  5. // get set......
  6. }

JSON:{ “id” : 1234, “name” : “John”}

@JsonTypeInfo和@JsonSubTypes用来处理多态类型的序列化及反序列化,这样说有点抽象,来看下具体例子

抽象父类:

  1. @JsonTypeInfo(use = JsonTypeInfo.Id.CLASS)
  2. @JsonSubTypes({
  3. @JsonSubTypes.Type(value = MemberInformation.class),
  4. @JsonSubTypes.Type(value = EcardUserInformation.class)})
  5. @JsonIgnoreProperties(ignoreUnknown = true)
  6. public abstract class LoginUserInformation implements Serializable {
  7. private static final long serialVersionUID = -933578885036345619L;
  8. private String userType = "1";
  9. private String ip = "127.0.0.1";
  10. // get set......
  11. }

两个具体子类:

  1. public class MemberInformation extends LoginUserInformation implements Serializable {
  2. private static final long serialVersionUID = 3334937746962893477L;
  3. private String fpcardno = "513712340023";
  4. private String passwd = "12346";
  5. // get set......
  6. }
  7. public class EcardUserInformation extends LoginUserInformation implements Serializable {
  8. private static final long serialVersionUID = -8191715041208933113L;
  9. private String aid;
  10. private String cellPhone;
  11. private String email;
  12. // get set......
  13. }

测试代码:

  1. LoginUserInformation loginUserInformation = new EcardUserInformation();
  2. ((EcardUserInformation) loginUserInformation).setAid("124124124");
  3. // {"@class":"org.javamaster.b2c.test.model.jackson.EcardUserInformation","userType":"1","ip":"127.0.0.1",
  4. // "aid":"124124124","cellPhone":null,"email":null}
  5. System.out.println(objectMapper.writeValueAsString(loginUserInformation));
  6. LoginUserInformation memberInformation = new MemberInformation();
  7. ((MemberInformation) memberInformation).setPasswd("qq123123");
  8. // {"@class":"org.javamaster.b2c.test.model.jackson.MemberInformation","userType":"1","ip":"127.0.0.1",
  9. // "fpcardno":"513712340023","passwd":"qq123123"}
  10. System.out.println(objectMapper.writeValueAsString(memberInformation));
  11. String jsonStr = "{\"@class\":\"org.javamaster.b2c.core.model.jackson.MemberInformation\",\"userType\":\"1\"," +
  12. "\"ip\":\"127.0.0.1\",\"fpcardno\":\"513712340023\",\"passwd\":\"qq123123\"}";
  13. memberInformation = objectMapper.readValue(jsonStr, LoginUserInformation.class);
  14. System.out.println(objectMapper.writeValueAsString(memberInformation));

@JsonSetter用于表明set方法应该匹配的JSON的属性,当Java bean的属性名和JSON的属性名不一致时就可以使用此注解

  1. public class Person {
  2. private long personId = 0;
  3. private String name = null;
  4. @JsonSetter("id") // 应该和JSON的id属性匹配
  5. public void setPersonId(long personId) {
  6. this.personId = personId; }
  7. // get set......
  8. }

JSON:{ “id” : 1234, “name” : “John”}

@JsonAnySetter用于指明将所有JSON未知的属性都收集在一起

  1. public class Bag {
  2. private Map<String, Object> properties = new HashMap<>();
  3. @JsonAnySetter
  4. public void set(String fieldName, Object value){
  5. this.properties.put(fieldName, value);
  6. }
  7. public Object get(String fieldName){
  8. return this.properties.get(fieldName);
  9. }
  10. }

所有JSON未知的属性都会收集到Bag类的properties属性里

@JsonCreator用于表明Java bean有一个构造方法能够匹配JSON的属性和bean的属性,对于一些没有set方法的bean(不可变对象)来说这个注解是很有用的。

  1. public class PersonImmutable {
  2. private final long id;
  3. private final String name;
  4. @JsonCreator
  5. public PersonImmutable(@JsonProperty("id")long id, @JsonProperty("name")String name) {
  6. this.id = id;
  7. this.name = name;
  8. }
  9. // get set......
  10. }

JSON:{ “id” : 1234, “name” : “John”}

@JsonDeserialize用于定制bean属性的反序列化过程

  1. public class PersonDeserialize {
  2. private long id = 0;
  3. private String name = null;
  4. // 这里我们想把1映射为true,0映射为false
  5. @JsonDeserialize(using = OptimizedBooleanDeserializer.class)
  6. private boolean enabled = false;
  7. // get set......
  8. }
  9. public class OptimizedBooleanDeserializer extends JsonDeserializer<Boolean> {
  10. @Override
  11. public Boolean deserialize(JsonParser jsonParser, DeserializationContext deserializationContext) throws IOException {
  12. String text = jsonParser.getText();
  13. if ("0".equals(text)) {
  14. return false;
  15. } else {
  16. return true;
  17. }
  18. }
  19. }

JSON:{“id” : 1234, “name” : “John”,“enabled”: 0}

@JsonInclude用于表明值满足特定条件的属性才会被序列化

  1. // 说明值不为null且不为空字符串的属性才会被序列化
  2. @JsonInclude(JsonInclude.Include.NON_EMPTY)
  3. public class PersonInclude {
  4. private long personId = 0;
  5. private String name = null;
  6. private String name1 = "";
  7. private String name2 = "John";
  8. // get set......
  9. }

JSON:{“personId” : 0, “name2” : “John”}

@JsonGetter用于指明序列化后的属性名而不是用bean的字段名

  1. public class PersonGetter {
  2. private long personId = 0;
  3. @JsonGetter("id")
  4. public long personId() {
  5. return this.personId; }
  6. @JsonSetter("id")
  7. public void personId(long personId) {
  8. this.personId = personId; }
  9. }

序列化后: {“id”: 0}

@JsonAnyGetter能够让你使用一个Map作为容器包含任何你想要序列化的属性

  1. public class PersonAnyGetter {
  2. private Map<String, Object> properties = new HashMap<>();
  3. @JsonAnyGetter
  4. public Map<String, Object> properties() {
  5. return properties;
  6. }
  7. public Map<String, Object> getProperties() {
  8. return properties;
  9. }
  10. }

@JsonPropertyOrder用于指明bean属性序列化的顺序

  1. @JsonPropertyOrder({
  2. "name", "personId"})
  3. public class PersonPropertyOrder {
  4. private long personId = 0;
  5. private String name = "John";
  6. // get set......
  7. }

序列化后: {“name”:“John”,“personId”,0}

@JsonRawValue用于表明属性值不做任何处理原样输出,String类型的值序列化后会被双引号括住,使用此注解后将不会加上双引号

  1. public class PersonRawValue {
  2. private long personId = 0;
  3. @JsonRawValue
  4. private String address = "$#";
  5. // get set......
  6. }

不加此注解时输出是这样的:{“personId”:0,“address”:”KaTeX parse error: Expected ‘EOF’, got ‘#‘ at position 1: #̲”},加了后输出是这样的:{“…#},这很明显是非法的JSON结构,所以我们为什么要这么做呢?这么做的理由是address属性的值是JSON字符串来的,像这样:

  1. public class PersonRawValue {
  2. private long personId = 0;
  3. @JsonRawValue
  4. private String address = "{ \"street\" : \"Wall Street\", \"no\":1}";
  5. // get set......
  6. }

序列化后是这样的:{“personId”:0,“address”:{ “street” : “Wall Street”, “no”:1}}

不加注解时序列化后是这样的:{“personId”:0,“address”:“{ “street” : “Wall Street”, “no”:1}”}

@JsonValue表明Jackson不做序列化,由此注解标注的方法完成序列化工作

  1. public class PersonValue {
  2. private long personId = 0;
  3. private String name = null;
  4. @JsonValue
  5. public String toJson(){
  6. return this.personId + "," + this.name;
  7. }
  8. }

序列化后是这样的:“0,null”

@JsonSerialize用于定制bean属性的序列化过程

  1. public class PersonSerializer {
  2. private long personId = 0;
  3. private String name = "John";
  4. // 这里希望把false序列化成0,true序列化成1
  5. @JsonSerialize(using = OptimizedBooleanSerializer.class)
  6. private boolean enabled = false;
  7. // get set......
  8. }
  9. public class OptimizedBooleanSerializer extends JsonSerializer<Boolean> {
  10. @Override
  11. public void serialize(Boolean aBoolean, JsonGenerator jsonGenerator,
  12. SerializerProvider serializerProvider)
  13. throws IOException {
  14. if (aBoolean) {
  15. jsonGenerator.writeNumber(1);
  16. } else {
  17. jsonGenerator.writeNumber(0);
  18. }
  19. }
  20. }

完全定制类的序列化和反序列化过程

  1. // 完全定制类的序列化和反序列化过程
  2. SimpleModule carModule = new CarModule();
  3. // 注册针对这个类型的处理模块
  4. objectMapper.registerModule(carModule);
  5. Car car = new Car();
  6. car.setBrand("BMW");
  7. car.setDoors(4);
  8. String json = objectMapper.writeValueAsString(car);
  9. System.out.println(json);
  10. car = objectMapper.readValue(json, Car.class);
  11. System.out.println(objectMapper.writeValueAsString(car));

其中CarModule CarSerializer CarDeserializer的定义:

  1. // 类型处理模块
  2. public class CarModule extends SimpleModule {
  3. public CarModule() {
  4. super(PackageVersion.VERSION);
  5. addDeserializer(Car.class, new CarDeserializer(Car.class));
  6. addSerializer(Car.class, new CarSerializer(Car.class));
  7. }
  8. }
  9. // 序列化器
  10. public class CarSerializer extends StdSerializer<Car> {
  11. private static final long serialVersionUID = 2807109332342106505L;
  12. public CarSerializer(Class<Car> c) {
  13. super(c);
  14. }
  15. @Override
  16. public void serialize(Car car, JsonGenerator jsonGenerator,
  17. SerializerProvider serializerProvider)
  18. throws IOException {
  19. jsonGenerator.writeStartObject();
  20. if (car.getBrand() != null) {
  21. jsonGenerator.writeStringField("brand", car.getBrand());
  22. } else {
  23. jsonGenerator.writeNullField("brand");
  24. }
  25. if (car.getDoors() != null) {
  26. jsonGenerator.writeNumberField("doors", car.getDoors());
  27. } else {
  28. jsonGenerator.writeNullField("doors");
  29. }
  30. jsonGenerator.writeEndObject();
  31. }
  32. }
  33. // 反序列化器
  34. public class CarDeserializer extends StdDeserializer<Car> {
  35. private static final long serialVersionUID = 4977601024588834191L;
  36. public CarDeserializer(Class<?> c) {
  37. super(c);
  38. }
  39. @Override
  40. public Car deserialize(JsonParser parser, DeserializationContext deserializer) throws IOException {
  41. Car car = new Car();
  42. while (!parser.isClosed()) {
  43. JsonToken jsonToken = parser.nextToken();
  44. if (JsonToken.FIELD_NAME == jsonToken) {
  45. String fieldName = parser.getCurrentName();
  46. parser.nextToken();
  47. if ("doors".equals(fieldName)) {
  48. car.setDoors(parser.getValueAsInt());
  49. } else if ("brand".equals(fieldName)) {
  50. car.setBrand(parser.getValueAsString());
  51. }
  52. }
  53. }
  54. return car;
  55. }
  56. }

发表评论

表情:
评论列表 (有 0 条评论,15人围观)

还没有评论,来说两句吧...

相关阅读