第一章 JacksonUtil 序列化与反序列化属性总结

1.json-lib与Jackson

  关于json-lib与Jackson对比总结如下:

  1).性能方面,Jackson的处理能力高出Json-lib10倍左右。

  2).json-lib已经停止更新,最新的版本也是基于JDK1.5,而Jackson的社区则较为活跃。

  3).json-lib依赖commons系列的包及 ezmorph包共 5个,而Jackson除自身的以外只依赖于commons-logging

2.1 Jackson序列化与反序列化方法

 1  public static String encode(Object obj) {
2 try {
3 return objectMapper.writeValueAsString(obj);
4 } catch (Exception e) {
5 logger.error("jackson encode error:", e);
6 }
7 return null;
8 }
9
10 /**
11 * 将json string反序列化成对象
12 *
13 * @param json
14 * @param valueType
15 * @return
16 */
17 public static <T> T decode(String json, Class<T> valueType) {
18 try {
19 return objectMapper.readValue(json, valueType);
20 } catch (Exception e) {
21 logger.error("jackson decode(String, Class<T>) error: ", e);
22 }
23 return null;
24 }
25
26 /**
27 * 将json array反序列化为对象
28 *
29 * @param json
30 * @param typeReference
31 * @return
32 */
33 public static <T> T decode(String json, TypeReference<T> typeReference) {
34 try {
35 return (T) objectMapper.readValue(json, typeReference);
36 } catch (Exception e) {
37 logger.error("decode(String, JsonTypeReference<T>)", e);
38 }
39 return null;
40 }

2.2 Jackson自动检测机制

  jackson默认的字段属性发现规则如下:

    所有被public修饰的字段->所有被public修饰的getter->所有被public修饰的setter

  若类中的一个private属性,且没有设置public的getter和setter方法,则对该类对象进行序列化时,默认不对这个private属性进行序列化。

  若此时任然需要对该private属性进行序列化,可以通过设置自动检测功能来实现:

  2.2.1 通过配置属性实现

1 objectMapper
2 .setVisibility(PropertyAccessor.FIELD, JsonAutoDetect.Visibility.ANY) // 自动检测所有类的全部属性
3 .setVisibility(PropertyAccessor.GETTER, JsonAutoDetect.Visibility.ANY) //自动检测所有类的public getter方法
4        .setVisibility(PropertyAccessor.IS_GETTER, JsonAutoDetect.Visibility.ANY); //自动检测所有类的public setter方法

  2.2.2 使用@JsonAutoDetect(作用在类上)来开启/禁止自动检测  

    fieldVisibility:字段的可见级别

    ANY:任何级别的字段都可以自动识别

    NONE:所有字段都不可以自动识别

    NON_PRIVATE:非private修饰的字段可以自动识别

    PROTECTED_AND_PUBLIC:被protected和public修饰的字段可以被自动识别

    PUBLIC_ONLY:只有被public修饰的字段才可以被自动识别

    DEFAULT:同PUBLIC_ONLY

  @JsonAutoDetect(fieldVisibility = JsonAutoDetect.Visibility.ANY)

3.序列化与反序列化属性总结

  与json-lib相比,Jackson在序列化与反序列时,可以对序列化与反序列化进行配置,是的输出结果满足自己的要求。序列化与反序列化属性很多,下面对一些常用属性进行介绍。

  3.1 序列化属性  

        //这个特性,决定了解析器是否将自动关闭那些不属于parser自己的输入源。
// 如果禁止,则调用应用不得不分别去关闭那些被用来创建parser的基础输入流InputStream和reader;
//默认是true
objectMapper.configure(JsonParser.Feature.AUTO_CLOSE_SOURCE, true);
//是否允许解析使用Java/C++ 样式的注释(包括'/'+'*' 和'//' 变量)
objectMapper.configure(JsonParser.Feature.ALLOW_COMMENTS, true); //设置为true时,属性名称不带双引号
objectMapper.configure(JsonGenerator.Feature.QUOTE_FIELD_NAMES, false);
//反序列化是是否允许属性名称不带双引号
objectMapper.configure(JsonParser.Feature.ALLOW_UNQUOTED_FIELD_NAMES, true); //是否允许单引号来包住属性名称和字符串值
objectMapper.configure(JsonParser.Feature.ALLOW_SINGLE_QUOTES, true); //是否允许JSON字符串包含非引号控制字符(值小于32的ASCII字符,包含制表符和换行符)
objectMapper.configure(JsonParser.Feature.ALLOW_UNQUOTED_CONTROL_CHARS, true); //是否允许JSON整数以多个0开始
objectMapper.configure(JsonParser.Feature.ALLOW_NUMERIC_LEADING_ZEROS, true); //null的属性不序列化
objectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL); //按字母顺序排序属性,默认false
objectMapper.configure(MapperFeature.SORT_PROPERTIES_ALPHABETICALLY,true); //是否以类名作为根元素,可以通过@JsonRootName来自定义根元素名称,默认false
objectMapper.configure(SerializationFeature.WRAP_ROOT_VALUE,true); //是否缩放排列输出,默认false
objectMapper.configure(SerializationFeature.INDENT_OUTPUT,false); //序列化Date日期时以timestamps输出,默认true
objectMapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS,true); //序列化枚举是否以toString()来输出,默认false,即默认以name()来输出
objectMapper.configure(SerializationFeature.WRITE_ENUMS_USING_TO_STRING, true); //序列化枚举是否以ordinal()来输出,默认false
objectMapper.configure(SerializationFeature.WRITE_ENUMS_USING_INDEX,false); //序列化单元素数组时不以数组来输出,默认false
objectMapper.configure(SerializationFeature.WRITE_ENUMS_USING_TO_STRING,true); //序列化Map时对key进行排序操作,默认false
objectMapper.configure(SerializationFeature.ORDER_MAP_ENTRIES_BY_KEYS,true); //序列化char[]时以json数组输出,默认false
objectMapper.configure(SerializationFeature.WRITE_CHAR_ARRAYS_AS_JSON_ARRAYS,true); //序列化BigDecimal时是输出原始数字还是科学计数,默认false,即以toPlainString()科学计数方式来输出
objectMapper.configure(SerializationFeature.WRITE_BIGDECIMAL_AS_PLAIN,true);

  下面写一个Person类,对上面介绍的序列化属性进行测试,并进行直观输出:  

 1 import com.fasterxml.jackson.annotation.JsonRootName;
2 import org.apache.commons.lang3.StringUtils;
3 import java.util.Date;
4
5
6 @JsonRootName("Test")
7 public class Person {
8 // @JsonInclude(JsonInclude.Include.NON_NULL)
9 private String name;
10
11 private int age;
12
13 private SexEnum sex;
14
15 private Date birthDay;
16
17 public enum SexEnum{
18 MAN("M", "m"),
19 WOMAN("F", "f");
20
21 private String merchantCode;
22 private String nativeCode;
23
24 SexEnum(String merchantCode, String nativeCode) {
25 this.merchantCode = merchantCode;
26 this.nativeCode = nativeCode;
27 }
28
29 public String getMerchantCode() {
30 return merchantCode;
31 }
32
33 public void setMerchantCode(String merchantCode) {
34 this.merchantCode = merchantCode;
35 }
36
37 public String getNativeCode() {
38 return nativeCode;
39 }
40
41 public void setNativeCode(String nativeCode) {
42 this.nativeCode = nativeCode;
43 }
44
45 @Override
46 public String toString() {
47 return getMerchantCode();
48 }
49
50 public Person() {
51 }
52
53 public Person(String name, int age) {
54 this.name = name;
55 this.age = age;
56 }
57
58 public String getName() {
59 return name;
60 }
61
62 public void setName(String name) {
63 this.name = name;
64 }
65
66 public int getAge() {
67 return age;
68 }
69
70 public void setAge(int age) {
71 this.age = age;
72 }
73
74 public SexEnum getSex() {
75 return sex;
76 }
77
78 public void setSex(SexEnum sex) {
79 this.sex = sex;
80 }
81
82 public Date getBirthDay() {
83 return birthDay;
84 }
85
86 public void setBirthDay(Date birthDay) {
87 this.birthDay = birthDay;
88 }
89 }

  下面是测试类:

1 import com.alibaba.fastjson.JSONObject;
2 import com.example.myFirstProject.domain.Person;
3 import com.example.myFirstProject.util.JacksonUtil;
4 import org.joda.time.DateTime;
5 import java.math.BigDecimal;
6 import java.util.ArrayList;
7 import java.util.Date;
8 import java.util.List;
9 import static com.example.myFirstProject.domain.Person.SexEnum;
10 import static com.example.myFirstProject.domain.Person.SexEnum.MAN;
11
12
13 /**
14 * Created by bjxiaojian on 2016/10/26.
15 */
16 public class JacksonTest {
17
18 public static void main(String[] args) {
19
20 Person person = new Person();
21
22 Person person1 = new Person("xiaojian", 1);
23 person1.setSex(MAN);
24 person1.setBirthDay(new Date());
25 List personList = new ArrayList();
26 personList.add(person);
27 personList.add(person1);
28 System.out.println(JacksonUtil.encode(person));
29 System.out.println(JacksonUtil.encode(person1));
30 System.out.println(JacksonUtil.encode(personList));
31
32 }
33 }
34
35
36 ---------------------------------输出结果--------------------------------------------
37 {"Test":{"age":0}} null的属性不进行序列化
38 {"Test":{"age":1,"birthDay":1477661674628,"name":"xiaojian","sex":"M"}} date类型的输出为时间戳,枚举类的输出默认为MAN或WOMAN,设置后为SexEnum的toString()的返回值
39 {"ArrayList":[{"age":0},{"age":1,"birthDay":1477661674628,"name":"xiaojian","sex":"M"}]}

  3.2 反序列化属性

1         //当遇到未知属性(没有映射到属性,没有任何setter或者任何可以处理它的handler,是否应该抛出JsonMappingException异常
2 objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); 3 //该特性决定对于json浮点数,是否使用BigDecimal来序列化。如果不允许,则使用Double序列化。 默认为false
4 objectMapper.configure(DeserializationFeature.USE_BIG_DECIMAL_FOR_FLOATS, false); 5 //该特性决定对于json整形(非浮点),是否使用BigInteger来序列化。如果不允许,则根据数值大小来确定 是使用Integer或者Long
6 objectMapper.configure(DeserializationFeature.USE_BIG_INTEGER_FOR_INTS, false); 7 //该特性决定JSON ARRAY是映射为Object[]还是List<Object>。如果开启,都为Object[],false时,则使用List 默认为false
8 objectMapper.configure(DeserializationFeature.USE_JAVA_ARRAY_FOR_JSON_ARRAY, false); 9 //是否使用Enum.toString()的值对json string进行反序列化。这个的设置和WRITE_ENUMS_USING_TO_STRING需要一致。
10 objectMapper.configure(DeserializationFeature.READ_ENUMS_USING_TO_STRING, true);

   3.3 Jackson序列化和反序列化注解 

  上面的配置是针对所有类的反序列化的设置,下面介绍针对某个类的属性和方法的反序列化的注解:

  1. @JsonIgnore:作用在字段或方法上,用来完全忽略被注解的字段和方法对应的属性。

   2.@JsonProperty:作用在字段或方法上,用来对属性的序列化/反序列化,可以用来避免遗漏属性,同时提供对属性名称重命名。

    对属性添加了@JsonProperty注解后,即使该属性为private且没有getter和setter方法,也会进行序列化。

  3.@JsonIgnoreProperties

    作用在类上,用来说明有些属性在序列化/反序列化时需要忽略掉,可以将它看做是@JsonIgnore的批量操作,它还有一个重要的功能是作用在反序列化时解析字段时过滤一些未知的属性,否则通常情况下解析到我们定义的类不认识的属性便会抛出异常。

    可以注明是想要忽略的属性列表如@JsonIgnoreProperties({"name","age","title"}),

    也可以注明过滤掉未知的属性如@JsonIgnoreProperties(ignoreUnknown=true)

  4、@JsonUnwrapped作用在属性字段或方法上,用来将子JSON对象的属性添加到封闭的JSON对象。示例如下:

public void jsonUnwrapped() throws Exception {
TestPOJO testPOJO = new TestPOJO();
testPOJO.setId(111);
TestName testName = new TestName();
testName.setFirstName("张");
testName.setSecondName("三");
testPOJO.setName(testName);
ObjectMapper objectMapper = new ObjectMapper();
String jsonStr = objectMapper.writeValueAsString(testPOJO);
//如果没有@JsonUnwrapped,序列化后将为{"id":111,"name":{"firstName":"张","secondName":"三"}}
//因为在name属性上加了@JsonUnwrapped,所以name的子属性firstName和secondName将不会包含在name中。
Assert.assertEquals("{\"id\":111,\"firstName\":\"张\",\"secondName\":\"三\"}",jsonStr);
String jsonStr2 = "{\"id\":111,\"firstName\":\"张\",\"secondName\":\"三\"}";
TestPOJO testPOJO2 = objectMapper.readValue(jsonStr2,TestPOJO.class);
Assert.assertEquals(111,testPOJO2.getId());
Assert.assertEquals("张",testPOJO2.getName().getFirstName());
Assert.assertEquals("三",testPOJO2.getName().getSecondName());
} public static class TestPOJO{
private int id;
@JsonUnwrapped
private TestName name; //getters、setters省略
}
public static class TestName{
private String firstName;
private String secondName; //getters、setters省略
}

 5.@JsonSerialize和@JsonDeserialize:作用于方法和字段上,通过 using(JsonSerializer)和using(JsonDeserializer)来指定序列化和反序列化的实现。下面的例子中自定义了日期的序列化和反序列化方式,可以将Date和指定日期格式字符串之间相互转换。 

@JsonSerialize(using = MyDateSerializer.class)
@JsonDeserialize(using = MyDateDeserializer.class)
private Date birthday;

  6.@JsonPropertyOrder:作用在类上,被用来指明当序列化时需要对属性做排序。@jsonPropertyOrder(alphabetic = true)

  7.@JsonView:视图模板,作用于方法和属性上,用来指定哪些属性可以被包含在JSON视图中,在前面我们知道已经有@JsonIgnore和@JsonIgnoreProperties可以排除过滤掉不需要序列化的属性,可是如果一个POJO中有h很多个属性,而我们可能只需要概要简单信息即序列化时只想输出其中几个属性,此时使用@JsonIgnore和@JsonIgnoreProperties就显得非常繁琐,而使用@JsonView便会非常方便,只许在你想要输出的属性(或对应的getter)上添加@JsonView即可。

@Test
public void jsonView() throws Exception {
TestPOJO testPOJO = new TestPOJO();
testPOJO.setA("1");
testPOJO.setB("2");
testPOJO.setC("3");
testPOJO.setD("4");
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.configure(MapperFeature.DEFAULT_VIEW_INCLUSION, false);
String jsonStr = objectMapper.writerWithView(FilterView.OutputA.class).writeValueAsString(testPOJO);
Assert.assertEquals("{\"a\":\"1\",\"c\":\"3\"}",jsonStr);
String jsonStr2 = objectMapper.writerWithView(FilterView.OutputB.class).writeValueAsString(testPOJO);
Assert.assertEquals("{\"d\":\"4\",\"b\":\"2\"}",jsonStr2);
} public static class TestPOJO{
@JsonView(FilterView.OutputA.class)
private String a;
@JsonView(FilterView.OutputA.class)
private String c;
@JsonView(FilterView.OutputB.class)
private String d;
@JsonView(FilterView.OutputB.class)
private String b;
//getters、setters忽略
} private static class FilterView {
static class OutputA {}
static class OutputB {}
}

  8.@JsonFilter:Json属性过滤器,作用于类,作用同上面的@JsonView,都是过滤掉不想要的属性,输出自己想要的属性。和@FilterView不同的是@JsonFilter可以动态的过滤属性。eg:

@Test
public void jsonFilter() throws Exception {
TestPOJO testPOJO = new TestPOJO();
testPOJO.setA("1");
testPOJO.setB("2");
testPOJO.setC("3");
testPOJO.setD("4");
ObjectMapper objectMapper = new ObjectMapper();
FilterProvider filters = new SimpleFilterProvider().addFilter("myFilter",SimpleBeanPropertyFilter.filterOutAllExcept("a"));
objectMapper.setFilters(filters);
String jsonStr = objectMapper.writeValueAsString(testPOJO);
Assert.assertEquals("{\"a\":\"1\"}",jsonStr);
} @JsonFilter("myFilter")
public static class TestPOJO{
private String a;
private String c;
private String d;
private String b; //getters、setters省略
}

  定义了一个名为myFilter的SimpleFilterProvider,这个过滤器将会过滤掉所有除a属性以外的属性。

  9.@JsonAnySetter:作用于方法,在反序列化时用来处理遇到未知的属性的时候调用,在本文前面我们知道可以通过注解@JsonIgnoreProperties(ignoreUnknown=true)来过滤未知的属性,但是如果需要这些未知的属性该如何是好?那么@JsonAnySetter就可以派上用场了,它通常会和map属性配合使用用来保存未知的属性, 

@Test
public void jsonAnySetter() throws Exception {
ObjectMapper objectMapper = new ObjectMapper();
String jsonStr = "{\"name\":\"myName\",\"code\":\"12345\",\"age\":12}";
TestPOJO testPOJO = objectMapper.readValue(jsonStr,TestPOJO.class);
Assert.assertEquals("myName",testPOJO.getName());
Assert.assertEquals("12345",testPOJO.getOther().get("code"));
Assert.assertEquals(12,testPOJO.getOther().get("age"));
} public static class TestPOJO{
private String name; private Map other = new HashMap(); @JsonAnySetter
public void set(String name,Object value) {
other.put(name,value);
} //getters、setters省略
}

  3.4 Jackson序列化设置DateTime的输出格式:

  simpleModule.addSerializer(new JodaDateSerializer(DateTime.class));

  JodaDateSerializer类的代码如下:

public class JodaDateSerializer extends StdSerializer<DateTime> {

    private static final Logger logger = LoggerFactory.getLogger(JodaDateSerializer.class);

    protected JodaDateSerializer(Class<DateTime> t) {
super(t);
} @Override
public void serialize(DateTime value, JsonGenerator jgen, SerializerProvider provider) throws IOException, JsonGenerationException {
if ( value == null ) {
jgen.writeString("null");
} else {
try {
//DateTimeUtils是自己定义的进行DateTime和各种String格式转换的工具类
String str = DateTimeUtils.fmtYyyyMMddHHmmss(value);
jgen.writeString(str);
} catch (Exception e) {
logger.error("joda serialize error: ", e);
jgen.writeString("unknown");
} }
} }

 DateTimeUtils是自己定义的进行DateTime和各种String格式转换的工具类,代码见 第二章 DateTime工具类

  参考博客:http://blog.csdn.net/sdyy321/article/details/40298081#t30

上一篇:JVM监控工具介绍


下一篇:CodeForces 719A Vitya in the Countryside 思维题