public class Book implements Serializable { private String title; private int year; public String getTitle() { return this.title; } public void setTitle(String title) { this.title = title; } public int getYear() { return this.year; } public void setYear(int year) { this.year = year; } @SuppressWarnings("unchecked") public static void main(String[] args) throws IOException { Book b = new Book(); b.setTitle("Jackson"); b.setYear(2017); String json = new ObjectMapper().writeValueAsString(b); System.out.println(json); // {"title":"Jackson","year":2017} Map<String, String> m = new ObjectMapper().readValue(json, Map.class); System.out.println(m); // {title=Jackson, year=2017} } }但聽說它有非常多特別的 Annotation。
@JsonIgnoreProperties & @JsonIgnore
使用 Jackson 最常見的需求就是,不要輸出某些欄位,可能原因有:安全考量(密碼欄位)、資料量(大物件或者 List / Map)、遞迴參考(會當掉?)以及 Lazy 屬性(Hibernate 未初始化的關聯屬性)。有四種設定方式。
Class Level - @JsonIgnoreProperties
@JsonIgnoreProperties({ "contractAmt" }) public class Book implements Serializable { private String title; private int contractAmt; public String getTitle() { return this.title; } public void setTitle(String title) { this.title = title; } public int getContractAmt() { return this.contractAmt; } public void setContractAmt(int contractAmt) { this.contractAmt = contractAmt; } public static void main(String[] args) throws IOException { Book b = new Book(); b.setTitle("Jackson"); b.setContractAmt(1099); System.out.println(new ObjectMapper().writeValueAsString(b)); // {"title":"Jackson"} } }
Field Level - @JsonIgnore
public class Book8 implements Serializable { private String title; private int contractAmt; public String getTitle() { return this.title; } public void setTitle(String title) { this.title = title; } @JsonIgnore public int getContractAmt() { return this.contractAmt; } public void setContractAmt(int contractAmt) { this.contractAmt = contractAmt; } public static void main(String[] args) throws IOException { Book8 b = new Book8(); b.setTitle("Jackson"); b.setContractAmt(1099); System.out.println(new ObjectMapper().writeValueAsString(b)); // {"title":"Jackson"} } }
特定 Java Type - @JsonIgnoreType
public class Book implements Serializable { private String title; private Address address; public String getTitle() { return this.title; } public void setTitle(String title) { this.title = title; } public Address getAddress() { return this.address; } public void setAddress(Address address) { this.address = address; } public static void main(String[] args) throws IOException { Book b = new Book(); b.setTitle("Jackson"); System.out.println(new ObjectMapper().writeValueAsString(b)); // {"title":"Jackson"} } } @JsonIgnoreType class Address { }但是當你「摸不到」別人家的 Java type 時,可以改用 Mixin(混搭)的方式 - addMixIn。
public class Book implements Serializable { private String title; private Date signedDate; public String getTitle() { return this.title; } public void setTitle(String title) { this.title = title; } public Date getSignedDate() { return this.signedDate; } public void setSignedDate(Date signedDate) { this.signedDate = signedDate; } public static void main(String[] args) throws IOException { Book b = new Book(); b.setTitle("Jackson"); b.setSignedDate(new Date(117, 11, 31)); ObjectMapper mapper = new ObjectMapper(); System.out.println(mapper.writeValueAsString(b)); // {"title":"Jackson","signedDate":1514649600000} mapper = new ObjectMapper(); mapper.addMixIn(Date.class, SqlDateMixin.class); System.out.println(mapper.writeValueAsString(b)); // {"title":"Jackson"} } } @JsonIgnoreType class SqlDateMixin { }
Filter - @JsonFilter
@JsonFilter("secret") public class Book implements Serializable { private String title; private Date signedDate; public String getTitle() { return this.title; } public void setTitle(String title) { this.title = title; } public Date getSignedDate() { return this.signedDate; } public void setSignedDate(Date signedDate) { this.signedDate = signedDate; } public static void main(String[] args) throws IOException { Book b = new Book(); b.setTitle("Jackson"); b.setSignedDate(new Date(117, 11, 31)); ObjectMapper mapper = new ObjectMapper(); SimpleFilterProvider filters = new SimpleFilterProvider(); filters.addFilter("secret", SimpleBeanPropertyFilter.serializeAllExcept("signedDate")); mapper.setFilterProvider(filters); System.out.println(mapper.writeValueAsString(b)); // {"title":"Jackson"} } }
@JsonProperty & @JsonGetter
預設狀況下,JSON 的屬性名稱是使用 Java Bean 的 property name,@JsonProperty 可以在不修改 Java Bean 的情況下自訂JSON 的屬性名稱,也可以用更為通用的 @JsonGetter 達成一樣的目的。public class Book implements Serializable { private String title; private int year; @JsonProperty("name") public String getTitle() { return this.title; } public void setTitle(String title) { this.title = title; } public int getYear() { return this.year; } public void setYear(int year) { this.year = year; } public static void main(String[] args) throws IOException { Book b = new Book(); b.setTitle("Jackson"); b.setYear(2017); System.out.println(new ObjectMapper().writeValueAsString(b)); // {"year":2017,"name":"Jackson"} } }
Include.NON_NULL
不要輸出 null 值的欄位,有三個設定 level:global、class 與 field 。Global Level - setSerializationInclusion(Include.NON_NULL)
public class Book implements Serializable { private String title; private String author; public String getTitle() { return this.title; } public void setTitle(String title) { this.title = title; } public String getAuthor() { return this.author; } public void setAuthor(String author) { this.author = author; } public static void main(String[] args) throws IOException { Book b = new Book(); b.setTitle("Jackson"); // b.setAuthor("MJ"); System.out.println(new ObjectMapper().writeValueAsString(b)); // {"title":"Jackson","author":null} System.out.println(new ObjectMapper().setSerializationInclusion(Include.NON_NULL).writeValueAsString(b)); // {"title":"Jackson"} } }
Class Level - @JsonInclude(Include.NON_NULL)
@JsonInclude(Include.NON_NULL) public class Book implements Serializable { private String title; private String author; public String getTitle() { return this.title; } public void setTitle(String title) { this.title = title; } public String getAuthor() { return this.author; } public void setAuthor(String author) { this.author = author; } public static void main(String[] args) throws IOException { Book b = new Book(); b.setTitle("Jackson"); // b.setAuthor("MJ"); System.out.println(new ObjectMapper().writeValueAsString(b)); // {"title":"Jackson"} } }
Field Level - @JsonInclude(Include.NON_NULL)
public class Book implements Serializable { private String title; private String author; public String getTitle() { return this.title; } public void setTitle(String title) { this.title = title; } @JsonInclude(Include.NON_NULL) public String getAuthor() { return this.author; } public void setAuthor(String author) { this.author = author; } public static void main(String[] args) throws IOException { Book b = new Book(); b.setTitle("Jackson"); // b.setAuthor("MJ"); System.out.println(new ObjectMapper().writeValueAsString(b)); // {"title":"Jackson"} } }@JsonInclude 雖然名為 include,但實際上卻是用來 exclude 的,Include 除了 NON_NULL,還有 ALWAYS(預設)、NON_ABSENT、NON_EMPTY 與 NON_DEFAULT。
@JsonAnyGetter
預設狀況下,Map 物件會轉成 JSON 物件。public class Book implements Serializable { private String title; private Map<String, String> histories = new HashMap<String, String>(); public String getTitle() { return this.title; } public void setTitle(String title) { this.title = title; } public Map<String, String> getHistories() { return this.histories; } public void setHistories(Map<String, String> histories) { this.histories = histories; } public static void main(String[] args) throws IOException { Book b = new Book(); b.setTitle("Jackson"); b.getHistories().put("rev1", "20170101..."); b.getHistories().put("rev2", "20170201..."); System.out.println(new ObjectMapper().writeValueAsString(b)); // {"title":"Jackson","histories":{"rev2":"20170201...","rev1":"20170101..."}} } }@JsonAnyGetter 可以將 Map 裡的名值對抽出來,有點 flatten 的味道。
public class Book implements Serializable { private String title; private Map<String, String> histories = new HashMap<String, String>(); public String getTitle() { return this.title; } public void setTitle(String title) { this.title = title; } @JsonAnyGetter public Map<String, String> getHistories() { return this.histories; } public void setHistories(Map<String, String> histories) { this.histories = histories; } public static void main(String[] args) throws IOException { Book b = new Book(); b.setTitle("Jackson"); b.getHistories().put("rev1", "20170101..."); b.getHistories().put("rev2", "20170201..."); System.out.println(new ObjectMapper().writeValueAsString(b)); // {"title":"Jackson","rev2":"20170201...","rev1":"20170101..."} } }
@JsonRawValue
直接輸出原始內容,不去處理 JSON 專用的雙引號,可以用來輸出手打的 JSON 字串。public class Book13 implements Serializable { private String title; private String json; public String getTitle() { return this.title; } public void setTitle(String title) { this.title = title; } @JsonRawValue public String getJson() { return this.json; } public void setJson(String json) { this.json = json; } public static void main(String[] args) throws IOException { Book13 b = new Book13(); b.setTitle("Jackson"); b.setJson("{\"title\":\"Jackson\"}"); System.out.println(new ObjectMapper().writeValueAsString(b)); // 一般欄位 - {"title":"Jackson","json":"{\"title\":\"Jackson\"}"} // @JsonRawValue - {"title":"Jackson","json":{"title":"Jackson"}} } }
@JsonValue
效果類似 toString(),用該 method 回傳的值表示該 instance,適合用於enum。public class Book14 implements Serializable { private String title; private BookType type; public String getTitle() { return this.title; } public void setTitle(String title) { this.title = title; } public BookType getType() { return this.type; } public void setType(BookType type) { this.type = type; } public static void main(String[] args) throws IOException { Book14 b = new Book14(); b.setTitle("Jackson"); b.setType(BookType.Computer); System.out.println(new ObjectMapper().writeValueAsString(b)); // 一般欄位 - {"title":"Jackson","type":"Computer"} // @JsonValue - {"title":"Jackson","type":"COMPUTER"} } } enum BookType { Computer("COMPUTER"), Science("SCIENCE"); private String name; BookType(String name) { this.name = name; } @JsonValue public String getName() { return name; } }
@JsonRootName
Jackson 可以透過 SerializationFeature.WRAP_ROOT_VALUE 將自身也輸出,但自身預設為 class name,可以用 @JsonRootName 自訂自身名稱。@JsonRootName("book") public class Book15 implements Serializable { private String title; public String getTitle() { return this.title; } public void setTitle(String title) { this.title = title; } public static void main(String[] args) throws IOException { Book15 b = new Book15(); b.setTitle("Jackson"); ObjectMapper mapper = new ObjectMapper(); mapper.enable(SerializationFeature.WRAP_ROOT_VALUE); System.out.println(mapper.writeValueAsString(b)); // 一般欄位 - {"Book15":{"title":"Jackson"}} // @JsonRootName - {"book":{"title":"Jackson"}} } }
@JsonSerialize
自訂物件輸出的內容。public class Book16 implements Serializable { private String title; private Date publishDate; public String getTitle() { return this.title; } public void setTitle(String title) { this.title = title; } public Date getPublishDate() { return this.publishDate; } @JsonSerialize(using = DateSerialize.class) public Date getPublishDateFormatted() { return this.publishDate; } public void setPublishDate(Date publishDate) { this.publishDate = publishDate; } public static void main(String[] args) throws IOException { Book16 b = new Book16(); b.setTitle("Jackson"); b.setPublishDate(new Date()); ObjectMapper mapper = new ObjectMapper(); System.out.println(mapper.writeValueAsString(b)); // {"title":"Jackson","publishDate":1514390929846,"publishDateFormatted":2017-12-28 00:08:49} } } class DateSerialize extends JsonSerializer<Date> { private SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); @Override public void serialize(Date value, JsonGenerator gen, SerializerProvider serializers) throws IOException { gen.writeRawValue(df.format(value)); } }---
---
---
沒有留言:
張貼留言