基礎入門
注意,本文用到的Jackson版本為2.2.3。 Java Object和json之間的轉換(Object -> json為serialize,反之為deserialize)是通過ObjectMapper類來實現,最簡單是實現如下:
//被轉換的對象 public class Person { String firstname; String lastname; String phone; List<Address> addresses = new ArrayList<Address>(); //這里省略setter、getter public Address addNewAddress() { Address address = new Address(); addresses.add(address); return address; } public String getFullName() { return firstname+"/"+lastname; } static class Address{ String street; String city; Integer number; //這里省略setter、getter } } public class JacksonTest { public static void main(String[] args) { try { Person person = new Person(); person.setFirstname("dennis"); person.setLastname("lau"); person.setPhone("123456789"); Person.Address address = person.addNewAddress(); address.setCity("shenzhen"); address.setStreet("renming road"); address.setNumber(1234); ObjectMapper objectMapper = new ObjectMapper(); String json = objectMapper.writeValueAsString(person); System.out.println(json); }catch (Exception e) { e.printStackTrace(System.out); } } }
輸出:{"firstname":"dennis","lastname":"lau","phone":"123456789","addresses":[{"street":"renming road","city":"shenzhen","number":1234}],"fullName":"dennis/lau"}
使用默認構站器的ObjectMapper在默認配置下將會序列化含有getter的值(不一定有真實相對應的變量成員,如Person的getFullName),如果我們只想序列化類對應的field,有兩個解決辦法:
1.使用Jackson Annotations
使用Jackson Annotation的@JsonIgnore,將該注釋加在不想序列化的getter方法,就能達到在序列化時忽略該field的效果:
//其余配置 保持不變
@JsonIgnore public String getFullName() { return firstname+"/"+lastname; }
輸出:{"firstname":"dennis","lastname":"lau","phone":"123456789","addresses":[{"street":"renming road","city":"shenzhen","number":1234}]} //對比未加注釋,這里的fullName不存在了。
2.更改MapperFeature的配置
更改ObjectMapper實例的MapperFeature的AUTO_DETECT_GETTERS為disbale,這樣序列化時所有的getter都不會被檢測(如果filed的訪問范圍為public,還是可見的,能夠被序列化為json的屬性,否則都不會被序列化),再在需要序列化的field對應的getter方法加上Annotation @JsonProperty(因為一般情況下field都是private或者package可見)。
public class Person { String firstname; String lastname; String phone; List<Address> addresses = new ArrayList<Address>(); @JsonProperty public String getFirstname() { return firstname; } @JsonProperty public String getLastname() { return lastname; } @JsonProperty public String getPhone() { return phone; } public void setPhone(String phone) { this.phone = phone; } @JsonProperty public List<Address> getAddresses() { return addresses; } //省略了setter public String getFullName() { return firstname+"/"+lastname; } public class JacksonTest { public static void main(String[] args) { try { Person person = new Person(); person.setFirstname("dennis"); person.setLastname("lau"); person.setPhone("123456789"); Person.Address address = person.addNewAddress(); address.setCity("shenzhen"); address.setStreet("renming road"); address.setNumber(1234); ObjectMapper objectMapper = new ObjectMapper();
//序列化之前,disable getter的自動檢測,默認情況為使能的。 objectMapper.disable(MapperFeature.AUTO_DETECT_GETTERS); String json = objectMapper.writeValueAsString(person); System.out.println(json); }catch (Exception e) { e.printStackTrace(System.out); } } }
輸出:{"firstname":"dennis","lastname":"lau","phone":"123456789"}
Java Object和json相互轉換過程中,保留時區信息
默認情況下,Jackson對Date類型序列化為TimeStamp形式(為long類型的數字)
long now = System.currentTimeMillis(); Date date = new Date(now); ObjectMapper objectMapper = new ObjectMapper(); String s = objectMapper.writeValueAsString(date); System.out.println(now); System.out.println(s);
輸出:1449391557113, 1449391557113
TimeStamps形式可讀性很差,並且對於帶有時區的時間,並不能保留時區信息,造成同樣的時間,經過序列化,再反序列化后時間改變了。為了實現轉換保留時區信息,需要自定義
JsonSerializer和JsonDeserializer:
public class CustomCalendarSerializer extends JsonSerializer<Calendar> {
//序列化時,使用自定義的SimpleDateFormat來格式化時間 private static SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd\'T\'HH:mm:ss.SSSZ"); @Override public void serialize(Calendar calendar, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) throws IOException { sdf.setCalendar(calendar);//時區信息保留在Calendar里面,Date類型是沒有時區信息的哦 jsonGenerator.writeString(sdf.format(calendar.getTime())); } } public class CustomCalenderDeserializer extends JsonDeserializer<Calendar> {
//反序列化時,為了方便,使用org.joda.time.format.DateTimeFormatter,它能夠根據預設的時間格式(注意這里的格式要和序列化時的一致),還原出時間,並可以得到GregorianCalendar
private static DateTimeFormatter stf = DateTimeFormat.forPattern("yyyy-MM-dd\'T\'HH:mm:ss.SSSZ");
@Override
public Calendar deserialize(JsonParser jsonParser, DeserializationContext deserializationContext) throws IOException {
String date = jsonParser.getText();
return stf.withOffsetParsed().parseDateTime(date).toGregorianCalendar();
}
}
現在看看如何使用自定義的序列化及反序列化對象:
public class Test { Calendar calendar; String desc;
//使用Annotation來使用自定義serializer, @JsonSerialize(using = CustomCalendarSerializer.class) public Calendar getCalendar() { return calendar; }
//使用Annotation來使用自定義Deserializer @JsonDeserialize(using = CustomCalenderDeserializer.class) public void setCalendar(Calendar calendar) { this.calendar = calendar; } public String getDesc() { return desc; } public void setDesc(String desc) { this.desc = desc; } } public class JacksonTest { public static void main(String[] args) { try { String date = "2000-10-01T10:10:10.123"; SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd\'T\'HH:mm:ss.SSS"); //創建被轉換的對象calendar,有時區信息 Calendar calendar = new GregorianCalendar(); calendar.setTime(sdf.parse(date)); TimeZone timeZone = TimeZone.getTimeZone("GMT-8:00"); calendar.setTimeZone(timeZone); Test test = new Test(); test.setCalendar(calendar); test.setDesc("test date with timezone to json"); ObjectMapper objectMapper = new ObjectMapper(); String json = objectMapper.writeValueAsString(test); System.out.println(json); Test restore = objectMapper.readValue(json, Test.class); System.out.print(restore.getCalendar().getTimeZone().getDisplayName()); }catch (Exception e) { e.printStackTrace(System.out); } } }
輸出:
before: 970366210123
before: GMT-08:00
{"calendar":"2000-09-30T18:10:10.123-0800","desc":"test date with timezone to json"}
after: 970366210123
after: GMT-08:00
使用了自定義格式的serializer,json的時間格式可讀性就很好了,並且轉換前后時間及時區都沒有改變