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