本文内容

  • 基本 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")));

}

.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, "Courier New", courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }

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

也可以通过在字段上使用 @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 包。

 

参考资料


 

术语


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

Android 基本 Jackson Marshalling(serialize)/Unmarshalling(deserialize)的更多相关文章

  1. Android 高级 Jackson Marshalling(serialize)/Unmarshalling(deserialize)

    本文内容 高级 Jackson Marshalling 只序列化符合自定义标准的字段 把 Enums 序列化成 JSON 对象 JsonMappingException(没有找到类的序列化器) Jac ...

  2. [LeetCode] Serialize and Deserialize BST 二叉搜索树的序列化和去序列化

    Serialization is the process of converting a data structure or object into a sequence of bits so tha ...

  3. [LeetCode] Serialize and Deserialize Binary Tree 二叉树的序列化和去序列化

    Serialization is the process of converting a data structure or object into a sequence of bits so tha ...

  4. U家面试prepare: Serialize and Deserialize Tree With Uncertain Children Nodes

    Like Leetcode 297, Serialize and Deserialize Binary Tree, the only difference, this is not a binary ...

  5. Leetcode: Serialize and Deserialize BST

    Serialization is the process of converting a data structure or object into a sequence of bits so tha ...

  6. [LeetCode] Serialize and Deserialize Binary Tree

    Serialize and Deserialize Binary Tree Serialization is the process of converting a data structure or ...

  7. LeetCode——Serialize and Deserialize Binary Tree

    Description: Serialization is the process of converting a data structure or object into a sequence o ...

  8. android.os.BadParcelableException: ClassNotFoundException when unmarshalling:解决办法

    例如在用AlarmManager的时候 AlarmManager alarmMgr = (AlarmManager) mContext .getSystemService(Context.ALARM_ ...

  9. Serialize and Deserialize Binary Tree

    Design an algorithm and write code to serialize and deserialize a binary tree. Writing the tree to a ...

随机推荐

  1. 高速排序C++实现

    //高速排序 #include<iostream> #include<functional> #include<Windows.h> using namespace ...

  2. MongoDB 安装 Windows XP

    〇.  一个提供MonogoDB丰富资料的中文网站 http://www.cnblogs.com/hoojo/archive/2012/02/17/2355384.html 一. http://www ...

  3. 5日均线MACD

    1.5日均线: 5日均线是股市术语,就是股票5天的成交价格或指数的平均值,所对应的是股价的5日均线和指数的5日均线(5MA).均线指标实际上是移动平均线指标的简称. 一般在K 线图中会有3 条或4 条 ...

  4. centos7虚拟机(vmware)通过U盘传文件

    centos7虚拟机(vmware)通过U盘传文件 centos7虚拟机安装以后,WINDOWS给CENTOS7传文件,除了在CENTOS7安装SAMBA外,其实通过U盘也是可以的. CENTOS7对 ...

  5. Blocks Programming Topics

    最近的工作中比较频繁的用到了Block,不在是以前当做函数指针的替代或者某些API只有Blocks形式的接口才不得已用之了,发现自己对其了解还是太浅,特别是变量的生存期,按惯例还是翻译官方文档,原文链 ...

  6. C++点和箭头操作符用

    http://www.cnblogs.com/ManMonth/archive/2013/09/05/3302873.html C++点和箭头操作符用法区别 变量是对象的时候用“.”访问 变量是对象指 ...

  7. Eclipse断点调试(DBG)Android应用

    1.添加断点 双击左侧边框便可添加断点,右击也能添加断点. 2.进入调试模式 点击虫子,然后选择工程运行,快捷键为单击F11 ,如果是正常运行就是Ctrl+F11 3.单步调试+跳到下一个断点 运行到 ...

  8. 3分钟搞定SpringBoot+Mybatis+druid多数据源和分布式事务

    文章来自: https://blog.csdn.net/qq_29242877/article/details/79033287 在一些复杂的应用开发中,一个应用可能会涉及到连接多个数据源,所谓多数据 ...

  9. 选中TreeView的某节点,并加背景颜色

    一:按钮事件,遍历所有节点 private void button2_Click(object sender, EventArgs e) { foreach (TreeNode n in TreeVi ...

  10. 架构模式数据源模式之:表数据入口(Table Data Gateway)、行数据入口(Row Data Gateway)、活动记录(Active Record)

    一:表数据入口(Table Data Gateway) 表数据入口提供了用于访问单个表或者视图(也包含了联表查询)的所有SQL,通常一个表一个类.其它代码通过它来实现对数据库的交互.基于这个特点,表数 ...