Jackson入門及java2json轉換保留TimeZone問題


 

基礎入門

  注意,本文用到的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的時間格式可讀性就很好了,並且轉換前后時間及時區都沒有改變

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM