本文内容

  • 基本 Jack Marshalling

    • 忽略属性
    • 忽略 Null 字段
    • 改变字段名字
  • 基本 Jackson Marshalling
    • 把 JSON 解析成 JsonNode
    • Unmarshalling 带未知属性的 json
  • 演示
  • 参考资料
  • 术语

本文使用 Jackson 2,包括 jackson-annotations-2.4.0.jar、jackson-core-2.4.1.jar 和 jackson-databind-2.4.1.jar 这三个库。

貌似太理论的东西,看得人也比较少,都喜欢看实际功能的东西,不过啊,只关注功能、理论太弱的人,基本没前途~

下载 Demo

下载 Jackson 2

基本 Jackson Marshalling


如何把一个 Java 实体序列化(serialize)成一个 JSON 字符串,并且如何控制映射的过程,以便获得准确的你想要的 JSON 格式。

忽略属性

当 Jackson 默认值不够,我们就需要准确地控制把什么序列化成 JSON,此时就非常有用了。有很多方式来忽略属性。

  • 在类的级别上忽略字段(field)

通过使用 @JsonIgnoreProperties 注解(annotation)和指定字段名字,我们可以在类的级别上忽略指定的字段:

@JsonIgnoreProperties(value = { "intValue" })
public class MyDto {
 
    private String stringValue;
    private int intValue;
    private boolean booleanValue;
 
    public MyDto() {
        super();
    }
 
    // standard setters and getters are not shown
}

下面的测试会通过。对象被序列化成 JSON 后,里边的确没有 intValue 字段:

@Test
public void givenFieldIsIgnoredByName_whenDtoIsSerialized_thenCorrect()
  throws JsonParseException, IOException {
    ObjectMapper mapper = new ObjectMapper();
    MyDto dtoObject = new MyDto();
 
    String dtoAsString = mapper.writeValueAsString(dtoObject);
 
    assertThat(dtoAsString, not(containsString("intValue")));
}

  • 在字段的级别上忽略字段

也可以通过在字段上使用 @JsonIgnore 注解,直接忽略字段:

public class MyDto {
 
    private String stringValue;
    @JsonIgnore
    private int intValue;
    private boolean booleanValue;
 
    public MyDto() {
        super();
    }
 
    // standard setters and getters are not shown
}

测试代码如下,序列化后的 JSON 不包含 intValue 字段:

@Test
public void givenFieldIsIgnoredDirectly_whenDtoIsSerialized_thenCorrect()
  throws JsonParseException, IOException {
    ObjectMapper mapper = new ObjectMapper();
    MyDto dtoObject = new MyDto();
 
    String dtoAsString = mapper.writeValueAsString(dtoObject);
 
    assertThat(dtoAsString, not(containsString("intValue")));
}

  • 根据类型忽略字段

通过使用 @JsonIgnoreType 注解,我们可以忽略所有指定类型的字段:

@JsonIgnoreType
public class SomeType { ... }

通常情况下,我们不能控制类本身;在这种情况下,我们可以好好利用 Jackson mixins。

首先,我们为类型定义一个 MixIn, 并用 @JsonIgnoreType 注解:

@JsonIgnoreType
public class MyMixInForString {
    //
}

然后,向 mixin 注册在 marshalling 期间忽略掉所有的 String 类型:

mapper.addMixInAnnotations(String.class, MyMixInForString.class);

这样,所有的 String 类型将被忽略,不会被序列化成 JSON:

@Test
public final void givenFieldTypeIsIgnored_whenDtoIsSerialized_thenCorrect()
  throws JsonParseException, IOException {
    ObjectMapper mapper = new ObjectMapper();
    mapper.addMixInAnnotations(String.class, MyMixInForString.class);
    MyDto dtoObject = new MyDto();
    dtoObject.setBooleanValue(true);
 
    String dtoAsString = mapper.writeValueAsString(dtoObject);
 
    assertThat(dtoAsString, containsString("intValue"));
    assertThat(dtoAsString, containsString("booleanValue"));
    assertThat(dtoAsString, not(containsString("stringValue")));
}

  • 使用 Filter 忽略字段

可以使用 Filter 忽略指定的字段。

首先,我们需要在 Java 对象上定义 filter:

@JsonFilter("myFilter")
public class MyDtoWithFilter { ... }

然后,定义一个简单的 filter,忽略 intValue 字段:

SimpleBeanPropertyFilter theFilter = SimpleBeanPropertyFilter.serializeAllExcept("intValue");
FilterProvider filters = new SimpleFilterProvider().addFilter("myFilter", theFilter);

现在序列化对象,确保 intValue 字段不会出现在 JSON 中:

@Test
public final void givenTypeHasFilterThatIgnoresFieldByName_whenDtoIsSerialized_thenCorrect()
  throws JsonParseException, IOException {
    ObjectMapper mapper = new ObjectMapper();
    SimpleBeanPropertyFilter theFilter = SimpleBeanPropertyFilter.serializeAllExcept("intValue");
    FilterProvider filters = new SimpleFilterProvider().addFilter("myFilter", theFilter);
 
    MyDtoWithFilter dtoObject = new MyDtoWithFilter();
    String dtoAsString = mapper.writer(filters).writeValueAsString(dtoObject);
 
    assertThat(dtoAsString, not(containsString("intValue")));
    assertThat(dtoAsString, containsString("booleanValue"));
    assertThat(dtoAsString, containsString("stringValue"));
    System.out.println(dtoAsString);
}

忽略 Null 字段

本小节说明,当序列化一个 Java 类时,如何忽略 null 字段。

  • 在类的级别上忽略 Null 字段

Jackson 允许在类的级别上控制这个行为:

@JsonInclude(Include.NON_NULL)
public class MyDto { ... }

或是,在更小粒度上,字段级别上:

public class MyDto {
 
    @JsonInclude(Include.NON_NULL)
    private String stringValue;
 
    private int intValue;
 
    // standard getters and setters
}

现在测试一下,null 值不会出现在 JSON 文件:

@Test
public void givenNullsIgnoredOnClass_whenWritingObjectWithNullField_thenIgnored()
  throws JsonProcessingException {
    ObjectMapper mapper = new ObjectMapper();
    MyDto dtoObject = new MyDto();
 
    String dtoAsString = mapper.writeValueAsString(dtoObject);
 
    assertThat(dtoAsString, containsString("intValue"));
    assertThat(dtoAsString, not(containsString("stringValue")));
}

  • 全局忽略 Null 字段

Jackson 也允许在 ObjectMapper 上全局配置这一行为:

mapper.setSerializationInclusion(Include.NON_NULL);

现在,在任何类中的 null 字段都不会被序列化:

@Test
public void givenNullsIgnoredGlobally_whenWritingObjectWithNullField_thenIgnored() 
  throws JsonProcessingException {
    ObjectMapper mapper = new ObjectMapper();
    mapper.setSerializationInclusion(Include.NON_NULL);
    MyDto dtoObject = new MyDto();
 
    String dtoAsString = mapper.writeValueAsString(dtoObject);
 
    assertThat(dtoAsString, containsString("intValue"));
    assertThat(dtoAsString, containsString("booleanValue"));
    assertThat(dtoAsString, not(containsString("stringValue")));
}

改变字段名字

如何在序列化时,改变字段名字,映射到另一个 JSON 属性。
下面是一个简单的 Java 实体:

public class MyDto {
    private String stringValue;
 
    public MyDto() {
        super();
    }
 
    public String getStringValue() {
        return stringValue;
    }
 
    public void setStringValue(String stringValue) {
        this.stringValue = stringValue;
    }
}

序列化它会得到如下 JSON:

{"stringValue":"some value"}

若想自定义输出,不想用 stringValue,而是 strValue,我们需要简单地为 getter 添加注解:

@JsonProperty("strVal")
public String getStringValue() {
    return stringValue;
}

现在,序列化后,就能得到我们想要的结果:

{"strValue":"some value"}

下面单元测试能证明这点:

@Test
public void givenNameOfFieldIsChanged_whenSerializing_thenCorrect() 
  throws JsonParseException, IOException {
    ObjectMapper mapper = new ObjectMapper();
    MyDtoFieldNameChanged dtoObject = new MyDtoFieldNameChanged();
    dtoObject.setStringValue("a");
 
    String dtoAsString = mapper.writeValueAsString(dtoObject);
 
    assertThat(dtoAsString, not(containsString("stringValue")));
    assertThat(dtoAsString, containsString("strVal"));
}

基本 Jackson Unmarshalling


如何把一个 JSON 字符串反序列(deserialize)化成一个 Java 实体。无论 JSON 多么“怪异”,我们需要把它映射成一个预先定义的 Java 实体类。

把 JSON 解析成 JsonNode

如何利用 Jackson 2 把 JSON 字符串转换成一个 com.fasterxml.jackson.databind.JsonNode

  • 快速解析

只需要 ObjectMapper 就可以解析 JSON 字符串:

@Test
public void whenParsingJsonStringIntoJsonNode_thenCorrect() 
  throws JsonParseException, IOException {
    String jsonString = "{\"k1\":\"v1\",\"k2\":\"v2\"}";
 
    ObjectMapper mapper = new ObjectMapper();
    JsonNode actualObj = mapper.readTree(jsonString);
 
    assertNotNull(actualObj);
}

  • 底层解析

出于某种原因,我需要使用底层解析,下面示例展示 JsonParser 负责实际 JSON 字符串的解析:

@Test
public void givenUsingLowLevelApi_whenParsingJsonStringIntoJsonNode_thenCorrect() 
  throws JsonParseException, IOException {
    String jsonString = "{\"k1\":\"v1\",\"k2\":\"v2\"}";
 
    ObjectMapper mapper = new ObjectMapper();
    JsonFactory factory = mapper.getFactory();
    JsonParser parser = factory.createParser(jsonString);
    JsonNode actualObj = mapper.readTree(parser);
 
    assertNotNull(actualObj);
}

  • 使用 JsonNode

JSON 被解析成一个 JsonNode 对象后,我们可以使用 Jackson JSON 树模型:

@Test
public void givenTheJsonNode_whenRetrievingDataFromId_thenCorrect() 
  throws JsonParseException, IOException {
    String jsonString = "{\"k1\":\"v1\",\"k2\":\"v2\"}";
    ObjectMapper mapper = new ObjectMapper();
    JsonNode actualObj = mapper.readTree(jsonString);
 
    // When
    JsonNode jsonNode1 = actualObj.get("k1");
    assertThat(jsonNode1.textValue(), equalTo("v1"));
}

Unmarshalling 带未知属性的 json

用 Jackson 2.x 来 unmarshalling,特别是,如何处理未知属性的 JSON。

  • Unmarshall 一个带额外/未知字段的 json

大多数时候,我们需要把 JSON 映射到预先定义的带很多字段的 Java 对象上。现在,我们简单地忽略掉那些不能被映射到现存 Java 字段的任何 JSON 属性。

例如,我们需要 unmarshall JSON 为下面 Java 实体:

public class MyDto {
 
    private String stringValue;
    private int intValue;
    private boolean booleanValue;
 
    public MyDto() {
        super();
    }
 
    // standard getters and setters and not included
}

  • 1,在未知字段上的 UnrecognizedPropertyException 异常

尝试 unmarshall 一个带未知属性的 JSON 到一个简单的 Java 实体,将会导致 com.fasterxml.jackson.databind.exc.UnrecognizedPropertyException 异常:

@Test(expected = UnrecognizedPropertyException.class)
public void givenJsonHasUnknownValues_whenDeserializing_thenException()
  throws JsonParseException, JsonMappingException, IOException {
    String jsonAsString = 
        "{\"stringValue\":\"a\"," +
        "\"intValue\":1," +
        "\"booleanValue\":true," +
        "\"stringValue2\":\"something\"}";
    ObjectMapper mapper = new ObjectMapper();
 
    MyDto readValue = mapper.readValue(jsonAsString, MyDto.class);
 
    assertNotNull(readValue);
}

这个失败将会显示如下异常信息:

com.fasterxml.jackson.databind.exc.UnrecognizedPropertyException: 
Unrecognized field "stringValue2" (class com.ln.basicjacksondemo.ignore.MyDto), 
not marked as ignorable (3 known properties: "stringValue", "booleanValue", "intValue"])

  • 2,Dealing with Unknown Fields on the ObjectMapper

我们可以配置 ObjectMapper 来忽略 JSON 中未知属性:

new ObjectMapper().configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false)

然后,我们就能解析这样的 JSON 到一个 Java 实体:

@Test
public void givenJsonHasUnknownValuesButJacksonIsIgnoringUnknowns_whenDeserializing_thenCorrect()
  throws JsonParseException, JsonMappingException, IOException {
    String jsonAsString = 
        "{\"stringValue\":\"a\"," +
        "\"intValue\":1," +
        "\"booleanValue\":true," +
        "\"stringValue2\":\"something\"}";
    ObjectMapper mapper = 
      new ObjectMapper().configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
 
    MyDto readValue = mapper.readValue(jsonAsString, MyDto.class);
 
    assertNotNull(readValue);
    assertThat(readValue.getStringValue(), equalTo("a"));
    assertThat(readValue.isBooleanValue(), equalTo(true));
    assertThat(readValue.getIntValue(), equalTo(1));
}

  • 3,with Unknown Fields on the Class

我们也可以标记一个类,接受未知字段,而不是在整个 Jackson ObjectMapper:

@JsonIgnoreProperties(ignoreUnknown = true)
public class MyDtoIgnoreUnknown { ... }

现在,测试一下,未知字段会被忽略,只映射能够识别的字段:

@Test
public void givenJsonHasUnknownValuesButIgnoredOnClass_whenDeserializing_thenCorrect() 
  throws JsonParseException, JsonMappingException, IOException {
    String jsonAsString =
        "{\"stringValue\":\"a\"," +
        "\"intValue\":1," +
        "\"booleanValue\":true," +
        "\"stringValue2\":\"something\"}";
    ObjectMapper mapper = new ObjectMapper();
 
    MyDtoIgnoreUnknown readValue = mapper.readValue(jsonAsString, MyDtoIgnoreUnknown.class);
 
    assertNotNull(readValue);
    assertThat(readValue.getStringValue(), equalTo("a"));
    assertThat(readValue.isBooleanValue(), equalTo(true));
    assertThat(readValue.getIntValue(), equalTo(1));
}

  • Unmarshall 一个不完整的 json

与未知字段类似,unmarshalling 一个不完整的 JSON – 一个不包含 Java 类中所有字段的 JSON – 对 Jackson 也不是问题:

@Test
public void givenNotAllFieldsHaveValuesInJson_whenDeserializingAJsonToAClass_thenCorrect() 
  throws JsonParseException, JsonMappingException, IOException {
    String jsonAsString = "{\"stringValue\":\"a\",\"booleanValue\":true}";
    ObjectMapper mapper = new ObjectMapper();
 
    MyDto readValue = mapper.readValue(jsonAsString, MyDto.class);
 
    assertNotNull(readValue);
    assertThat(readValue.getStringValue(), equalTo("a"));
    assertThat(readValue.isBooleanValue(), equalTo(true));
}

演示


图 1 项目结构

  • com.ln.basicjacksondemo.test 包,是单元测试;
  • 其他包,是单元测试需要的相关类;
  • libs 目录,是 Jackson 2 的 Java 包。

参考资料


  • Jackson Ignore Properties on Marshalling
  • Ignore Null Fields with Jackson
  • Jackson – Change Name of Field
  • Jackson – Marshall String to JsonNode
  • Jackson Unmarshalling json with Unknown Properties
  • Jackson JSON Tutorial
  • Jackson Download(注意:下载 Jackson 2 版本),或点击此处下载。
  • Android Jackson 概述
  • Android 基本 Jackson Marshalling(serialize)/Unmarshalling(deserialize)

术语


Marshalling/Unmarshalling

marshalling 是把一个对象的内存描述转换成适合存储或传输的一个数据格式的过程,它通常用于,数据必须在一个计算机程序的不同部分之间,从一个程序移动到另一个。Marshalling 类似于 serialization,用于一个对象跟远程对象通信,在这种情况下,是一个被序列化的对象。这简化了复杂的通信,使用自定义、复杂的对象通信,而不是基本数据类型。与 marshalling 相对的,或逆过程,称为 unmarshalling(demarshalling,类似于 deserialization)。

在 Python 里,marshal 跟 serialize 是一个概念,但是在 Java 中却不是。

具体参看 http://en.wikipedia.org/wiki/Unmarshalling#Comparison_with_serialization

下载 Demo

下载 Jackson 2

转载于:https://www.cnblogs.com/liuning8023/p/3903457.html

Android 基本 Jackson Marshalling(serialize)/Unmarshalling(deserialize)相关推荐

  1. [Java]LeetCode297. 二叉树的序列化与反序列化 | Serialize and Deserialize Binary Tree

    ★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★ ➤微信公众号:山青咏芝(shanqingyongzhi) ➤博客园地址:山青咏芝(https://www.cnblog ...

  2. 序列化和反序列化二叉搜索树 Serialize and Deserialize BST

    2019独角兽企业重金招聘Python工程师标准>>> 问题: Serialization is the process of converting a data structure ...

  3. leetcode 449. Serialize and Deserialize BST | 449. 序列化和反序列化二叉搜索树(BST后序遍历性质)

    题目 https://leetcode.com/problems/serialize-and-deserialize-bst/ 题解 本题的难点在于 利用 BST 的性质. 几个提示 根据后序遍历BS ...

  4. LeetCode 297 Serialize and Deserialize Binary Tree

    题目描述 Serialization is the process of converting a data structure or object into a sequence of bits s ...

  5. 297. Serialize and Deserialize Binary Tree

    Title 序列化是将一个数据结构或者对象转换为连续的比特位的操作,进而可以将转换后的数据存储在一个文件或者内存中,同时也可以通过网络传输到另一个计算机环境,采取相反方式重构得到原数据. 请设计一个算 ...

  6. lc 297. Serialize and Deserialize Binary Tree

    使用任意方法序列化一个二叉树. https://leetcode.com/problems/serialize-and-deserialize-binary-tree/ 原来带有None作为结束标志的 ...

  7. 计算机中的 marshal 是什么意思?(列集:将数据从某种格式存为流格式的操作)(序列化)(marshalling、unmarshalling散集)

    今天看dbus框架,看到一个marshal method call to message不知道是什么意思 IPC进程间通信 D-Bus(Desktop Bus)快速入门(以libdbus-glib库为 ...

  8. Java——serialize与deserialize

    目录 一级目录 二级目录 三级目录 序列化 (对象 ---> 字节流 ) 反序列化 (字节流 --> 对象) 一级目录 二级目录 三级目录 序列化 (对象 -> 字节流 ) 后端传给 ...

  9. SprintBoot开发官方指导文档

    2019独角兽企业重金招聘Python工程师标准>>> http://docs.spring.io/spring-boot/docs/current/reference/html/b ...

最新文章

  1. mysql noinstall_windows mysql noinstall
  2. 如何监控和优化mysql查询性能_如何监视MySQL的性能
  3. 查看Linux下网卡状态或 是否连接(转)
  4. php 应用宝支付,U8SDK——应用宝YSDK新的支付流程
  5. MacDroid for mac(安卓手机数据传输助手)
  6. 24.Creating Customer Groups
  7. 内存泄漏检查工具 Visual Leak Detector(VLD)
  8. ila数据导入matlab,MATLAB读取Xilinx ILA核保存的.ila文件中的两列数据,并输出到文件保存...
  9. 基于protues与keli下贪吃蛇的实现
  10. js调用摄像头拍照上传图片
  11. 调整 Jupyter Notebook 的代码字体
  12. 计算机专业搜题软件免费,QuestionHelper(pc搜题工具)
  13. 大麦路由器刷无线打印服务器,极路由2 大麦22D/203/204刷OPENWRT实现NDR客户端拨号 开机自启动 内网无法访问...
  14. 新谈:为什么你觉得FPGA难学?如何入门?
  15. 工厂车间现场管理必备利器,MES生产管理系统
  16. 360公司2019校招笔试编程题合集答案——python版本
  17. Crontab 每隔整点1小时2小时执行一次任务
  18. 华为在HDC2021发布全新HMS Core 6 宣布跨OS能力开放
  19. MATLAB求复杂函数积分
  20. CCF之小明上学——2018.12 第一题 (java满分代码)

热门文章

  1. 2021-08-27 思考:1000瓶药水,1瓶有毒,老鼠毒发24h,如何用最少的老鼠在24h内找出毒药?
  2. 【深度学习】基于Pytorch进行深度神经网络计算(一)
  3. 【Web安全】DVWA+CSRF跨站请求伪造-生成链接修改password
  4. 用Matplotlib跟踪疫情实时监控2019-nCoV
  5. 解决冲突的拉链法探测的ASL
  6. electron 两个窗口如何通信_关于 Electron 进程间通信的一个小小实践
  7. aggr代码 cellranger_单细胞转录组测序数据分析流程-数据预处理
  8. c#使用正则表达式获取TR中的多个TD_一个 Vue 模板可以有多个根节点(Fragments)?
  9. android 轮播 getWith,NavigationTermSet.GetWithNewView 方法
  10. ElasticSearch 被攻击勒索