Jackson常用注解
序列化注解
@JsonAnyGetter
像普通屬性一樣序列化Map
public class ExtendableBean {
public String name;
private Map<String, String> properties;
@JsonAnyGetter
public Map<String, String> getProperties() {
return properties;
}
}
序列化示例:
{
"name":"My bean",
"attr2":"val2",
"attr1":"val1"
}
@JsonGetter
將指定的方法標記為
getter方法。可以用來代替@JsonProperty
public class MyBean {
public int id;
private String name;
@JsonGetter("name")
public String getTheName() {
return name;
}
}
序列化示例:
{
"id": 1,
"name":"My bean"
}
@JsonPropertyOrder
用在類上,在序列化的時候自定義屬性輸出順序
@JsonPropertyOrder({ "name", "id" })
public class MyBean {
public int id;
public String name;
}
序列化示例:
{
"name":"My bean",
"id": 1
}
@JsonRawValue
完全按照原樣序列化屬性的值
public class RawBean {
public String name;
@JsonRawValue
public String json;
}
例如:
RawBean bean = new RawBean("My bean", "{\"attr\":false}");
將序列化為:
{
"name":"My bean",
"json":{
"attr":false
}
}
而不是:
{
"name":"My bean",
"json":"{\"attr\":false}"
}
@JsonValue
定義整個實體的序列化方法,Jackson將會使用該方法的輸出作為序列化輸出。
public enum TypeEnumWithValue {
TYPE1(1, "Type A"), TYPE2(2, "Type 2");
private Integer id;
private String name;
// standard constructors
@JsonValue
public String getName() {
return name;
}
}
序列化示例:
{
"name": "Type 2"
}
@JsonRootName
如果需要將實體包裝一層,可以使用
@JsonRootName來指定根包裝器的名稱
@JsonRootName(value = "user")
public class UserWithRoot {
public int id;
public String name;
}
序列化示例:
{
"user": {
"id": 1,
"name": "John"
}
}
如果不用該注解,將會序列化為:
{
"id": 1,
"name": "John"
}
@JsonSerialize
用於指定自定義序列化器來序列化實體
public class Event {
public String name;
@JsonSerialize(using = CustomDateSerializer.class)
public Date eventDate;
}
自定義序列化器如下:
public class CustomDateSerializer extends StdSerializer<Date> {
private static SimpleDateFormat formatter
= new SimpleDateFormat("dd-MM-yyyy hh:mm:ss");
public CustomDateSerializer() {
this(null);
}
public CustomDateSerializer(Class<Date> t) {
super(t);
}
@Override
public void serialize(
Date value, JsonGenerator gen, SerializerProvider arg2)
throws IOException, JsonProcessingException {
gen.writeString(formatter.format(value));
}
}
輸出示例:
{
"name": "test",
"eventDate": "20-12-2014 02:30:00"
}
反序列化注解
@JsonCreator
指定反序列化使用的構造函數或方法
待反序列化Json示例:
{
"id":1,
"theName":"My bean"
}
public class BeanWithCreator {
public int id;
public String name;
@JsonCreator
public BeanWithCreator(@JsonProperty("id") int id, @JsonProperty("theName") String name) {
this.id = id;
this.name = name;
}
}
@JacksonInject
指定某個字段從注入賦值,而不是從Json
public class BeanWithInject {
@JacksonInject
public int id;
public String name;
}
示例用法:
String json = "{\"name\":\"My bean\"}";
InjectableValues inject = new InjectableValues.Std()
.addValue(int.class, 1);
BeanWithInject bean = new ObjectMapper().reader(inject)
.forType(BeanWithInject.class)
.readValue(json);
@JsonAnySetter
在反序列化時,將Map當成普通屬性
待反序列化Json:
{
"name":"My bean",
"attr2":"val2",
"attr1":"val1"
}
public class ExtendableBean {
public String name;
private Map<String, String> properties;
@JsonAnySetter
public void add(String key, String value) {
properties.put(key, value);
}
}
properties字段的值將會是由 attr2 -> val2,attr1 -> val1組成的鍵值對。
@JsonSetter
將方法標記為
setter方法,可以指定屬性名稱
public class MyBean {
public int id;
private String name;
@JsonSetter("name")
public void setTheName(String name) {
this.name = name;
}
}
@JsonDeserialize
用於指定自定義反序列化器來反序列化實體
public class Event {
public String name;
@JsonDeserialize(using = CustomDateDeserializer.class)
public Date eventDate;
}
對應的反序列化器:
public class CustomDateDeserializer
extends StdDeserializer<Date> {
private static SimpleDateFormat formatter
= new SimpleDateFormat("dd-MM-yyyy hh:mm:ss");
public CustomDateDeserializer() {
this(null);
}
public CustomDateDeserializer(Class<?> vc) {
super(vc);
}
@Override
public Date deserialize(
JsonParser jsonparser, DeserializationContext context)
throws IOException {
String date = jsonparser.getText();
try {
return formatter.parse(date);
} catch (ParseException e) {
throw new RuntimeException(e);
}
}
}
Jackson設置屬性是否參與序列化
@JsonIgnoreProperties
在類上指定要忽略的屬性
@JsonIgnoreProperties({ "id" })
public class BeanWithIgnore {
public int id;
public String name;
}
@JsonIgnore
在具體屬性上忽略,使其不參與序列化過程
public class BeanWithIgnore {
@JsonIgnore
public int id;
public String name;
}
與@JsonIgnoreProperties是等效的。
@JsonIgnoreType
用在類上,將忽略該類所有屬性
public class User {
public int id;
public Name name;
@JsonIgnoreType
public static class Name {
public String firstName;
public String lastName;
}
}
@JsonInclude
用於排除值為
empty/null/default的屬性
@JsonInclude(Include.NON_NULL)
public class MyBean {
public int id;
public String name;
}
@JsonAutoDetect
強制序列化私有屬性,不管它有沒有
getter方法
@JsonAutoDetect(fieldVisibility = Visibility.ANY)
public class PrivateBean {
private int id;
private String name;
}
Jackson處理多態
一般都是組合起來使用,有下面三個注解:
- @JsonTypeInfo
指定序列化中包含的類型信息的詳細信息
- @JsonSubTypes
指定帶注釋類型的子類型
- @JsonTypeName
指定用於帶注釋的類的邏輯類型名稱
public class Zoo {
public Animal animal;
@JsonTypeInfo(
use = JsonTypeInfo.Id.NAME,
include = As.PROPERTY,
property = "type")
@JsonSubTypes({
@JsonSubTypes.Type(value = Dog.class, name = "dog"),
@JsonSubTypes.Type(value = Cat.class, name = "cat")
})
public static class Animal {
public String name;
}
@JsonTypeName("dog")
public static class Dog extends Animal {
public double barkVolume;
}
@JsonTypeName("cat")
public static class Cat extends Animal {
boolean likesCream;
public int lives;
}
}
上述例子中,指定屬性type為判斷具體子類的依據,例如:type=dog,將被序列化為Dog類型。
Jackson通用注解(序列化反序列化都生效)
@JsonProperty
指定JSON中的屬性名稱
public class MyBean {
public int id;
private String name;
@JsonProperty("name")
public void setTheName(String name) {
this.name = name;
}
@JsonProperty("name")
public String getTheName() {
return name;
}
}
@JsonFormat
用於在序列化日期/時間值時指定格式。
public class Event {
public String name;
@JsonFormat(
shape = JsonFormat.Shape.STRING,
pattern = "dd-MM-yyyy hh:mm:ss")
public Date eventDate;
}
@JsonUnwrapped
將對象中所有的屬性與當前平級,不太好描述,簡單說就是拆開包裝。
public class UnwrappedUser {
public int id;
@JsonUnwrapped
public Name name;
public static class Name {
public String firstName;
public String lastName;
}
}
序列化示例:
{
"id":1,
"firstName":"John",
"lastName":"Doe"
}
如果不加@JsonUnwrapped注解,將被序列化為:
{
"id":1,
"name": {
"firstName":"John",
"lastName":"Doe"
}
}
@JsonView
指定視圖,類似分組進行序列化/反序列化
定義視圖:
public class Views {
public static class Public {}
public static class Internal extends Public {}
}
定義實體:
public class Item {
@JsonView(Views.Public.class)
public int id;
@JsonView(Views.Public.class)
public String itemName;
@JsonView(Views.Internal.class)
public String ownerName;
}
序列化示例:
String result = new ObjectMapper()
.writerWithView(Views.Public.class)
.writeValueAsString(item);
這時,將只會序列化id和itemName字段
@JsonManagedReference, @JsonBackReference
@JsonManagedReference和@JsonBackReference注釋用於處理父/子關系並解決循環問題。
例如,有兩個相互引用的類:
public class ItemWithRef {
public int id;
public String itemName;
@JsonManagedReference
public UserWithRef owner;
}
public class UserWithRef {
public int id;
public String name;
@JsonBackReference
public List<ItemWithRef> userItems;
}
不加注解,會循環調用,導致內存溢出,這時候可以使用@JsonManagedReference和@JsonBackReference來避免內存溢出。
@JsonIdentityInfo
用於指定在序列化/反序列化值時使用對象標識,例如,處理無限遞歸類型的問題。
@JsonIdentityInfo(
generator = ObjectIdGenerators.PropertyGenerator.class,
property = "id")
public class ItemWithIdentity {
public int id;
public String itemName;
public UserWithIdentity owner;
}
@JsonFilter
指定序列化期間要使用的過濾器。
@JsonFilter("myFilter")
public class BeanWithFilter {
public int id;
public String name;
}
示例代碼:
BeanWithFilter bean = new BeanWithFilter(1, "My bean");
FilterProvider filters
= new SimpleFilterProvider().addFilter(
"myFilter",
SimpleBeanPropertyFilter.filterOutAllExcept("name"));
String result = new ObjectMapper()
.writer(filters)
.writeValueAsString(bean);
自定義Jackson注解
可以使用@JacksonAnnotationsInside來開發自定義注解
@Retention(RetentionPolicy.RUNTIME)
@JacksonAnnotationsInside
@JsonInclude(Include.NON_NULL)
@JsonPropertyOrder({ "name", "id", "dateCreated" })
public @interface CustomAnnotation {}
如何使用自定義注解:
@CustomAnnotation
public class BeanWithCustomAnnotation {
public int id;
public String name;
public Date dateCreated;
}
自定義注解可以增強代碼復用,把一些通用的Jackson注解組合起來,形成一個新注解,新注解可以代替組合的注解。
Jackson MixIn 注解
動態地為某些類型增加統一的Jackson注解
實體:
public class Item {
public int id;
public String itemName;
public User owner;
}
MixIn類:
@JsonIgnoreType
public class MyMixInForIgnoreType {}
我們可以動態地讓User類型不參與序列化:
Item item = new Item(1, "book", null);
ObjectMapper mapper = new ObjectMapper();
mapper.addMixIn(User.class, MyMixInForIgnoreType.class);
result = mapper.writeValueAsString(item);
禁用Jackson注解
假設我們有一個帶Jackson注解的實體:
@JsonInclude(Include.NON_NULL)
@JsonPropertyOrder({ "name", "id" })
public class MyBean {
public int id;
public String name;
}
我們可以這樣來禁用該實體上的所有Jackson注解:
MyBean bean = new MyBean(1, null);
ObjectMapper mapper = new ObjectMapper();
mapper.disable(MapperFeature.USE_ANNOTATIONS);
Jackson的ObjectMapper用法
java類 轉換為 json
可以直接序列化為Json字符串:
objectMapper.writeValueAsString(car);
或者,可以序列化到文件,文件內容是Json字符串:
objectMapper.writeValue(new File("target/car.json"), car);
json 轉換為 java類
從字符串:
String json = "{ \"color\" : \"Black\", \"type\" : \"BMW\" }";
objectMapper.readValue(json, Car.class);
從文件:
objectMapper.readValue(new File("target/json_car.json"), Car.class);
從URL:
objectMapper.readValue(new URL("target/json_car.json"), Car.class);
json轉換為Jackson JsonNode
String json = "{ \"color\" : \"Black\", \"type\" : \"FIAT\" }";
JsonNode jsonNode = objectMapper.readTree(json);
String color = jsonNode.get("color").asText();
// Output: color -> Black
json 轉換為 java集合
String jsonCarArray =
"[{ \"color\" : \"Black\", \"type\" : \"BMW\" }, { \"color\" : \"Red\", \"type\" : \"FIAT\" }]";
List<Car> listCar = objectMapper.readValue(jsonCarArray, new TypeReference<List<Car>>(){});
json 轉換為 Map
String json = "{ \"color\" : \"Black\", \"type\" : \"BMW\" }";
Map<String, Object> map = objectMapper.readValue(json, new TypeReference<Map<String,Object>>(){});
ObjectMapper的常用配置
忽略不識別的字段(json屬性與目標實體存在屬性上的差異):
objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
允許原始值為null:
objectMapper.configure(DeserializationFeature.FAIL_ON_NULL_FOR_PRIMITIVES, false);
允許將枚舉序列化/反序列化為數字:
objectMapper.configure(DeserializationFeature.FAIL_ON_NUMBERS_FOR_ENUMS, false);
配置自定義序列化/反序列化器
假設有一個序列化器:
public class CustomCarSerializer extends StdSerializer<Car> {
public CustomCarSerializer() {
this(null);
}
public CustomCarSerializer(Class<Car> t) {
super(t);
}
@Override
public void serialize(
Car car, JsonGenerator jsonGenerator, SerializerProvider serializer) {
jsonGenerator.writeStartObject();
jsonGenerator.writeStringField("car_brand", car.getType());
jsonGenerator.writeEndObject();
}
}
一個反序列化器:
public class CustomCarDeserializer extends StdDeserializer<Car> {
public CustomCarDeserializer() {
this(null);
}
public CustomCarDeserializer(Class<?> vc) {
super(vc);
}
@Override
public Car deserialize(JsonParser parser, DeserializationContext deserializer) {
Car car = new Car();
ObjectCodec codec = parser.getCodec();
JsonNode node = codec.readTree(parser);
// try catch block
JsonNode colorNode = node.get("color");
String color = colorNode.asText();
car.setColor(color);
return car;
}
}
用ObjectMapper使用他們:
//添加自定義序列化器
module.addSerializer(Car.class, new CustomCarSerializer());
//添加自定義反序列化器
module.addDeserializer(Car.class, new CustomCarDeserializer());
處理日期格式化
ObjectMapper objectMapper = new ObjectMapper();
DateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm a z");
objectMapper.setDateFormat(df);
處理集合
反序列化為數組:
String jsonCarArray =
"[{ \"color\" : \"Black\", \"type\" : \"BMW\" }, { \"color\" : \"Red\", \"type\" : \"FIAT\" }]";
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.configure(DeserializationFeature.USE_JAVA_ARRAY_FOR_JSON_ARRAY, true);
Car[] cars = objectMapper.readValue(jsonCarArray, Car[].class);
反序列化為集合:
String jsonCarArray =
"[{ \"color\" : \"Black\", \"type\" : \"BMW\" }, { \"color\" : \"Red\", \"type\" : \"FIAT\" }]";
ObjectMapper objectMapper = new ObjectMapper();
List<Car> listCar = objectMapper.readValue(jsonCarArray, new TypeReference<List<Car>>(){});
ObjectMapper的基本用法
ObjectMapper可以通過configure方法設置全局序列化/反序列化行為,例如:
objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
常用的一些設置:
DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES:忽略不識別的字段DeserializationFeature.FAIL_ON_NULL_FOR_PRIMITIVES:允許使用屬性的默認值進行反序列化DeserializationFeature.FAIL_ON_NUMBERS_FOR_ENUMS:允許將枚舉值序列化/反序列化為數字
注冊自定義序列化/反序列化程序
//創建一個模塊
SimpleModule module = new SimpleModule("CustomCarSerializer", new Version(1, 0, 0, null, null, null));
//將自定義序列化/反序列化程序注冊到模塊
module.addSerializer(Car.class, new CustomCarSerializer());
//module.addDeserializer(Car.class, new CustomCarDeserializer());
//注冊模塊
mapper.registerModule(module);
處理日期格式
DateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm a z");
mapper.setDateFormat(df);
處理集合
處理數組
String jsonCarArray = "[{ \"color\" : \"Black\", \"type\" : \"BMW\" }, { \"color\" : \"Red\", \"type\" : \"FIAT\" }]";
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.configure(DeserializationFeature.USE_JAVA_ARRAY_FOR_JSON_ARRAY, true);
Car[] cars = objectMapper.readValue(jsonCarArray, Car[].class);
處理集合
String jsonCarArray = "[{ \"color\" : \"Black\", \"type\" : \"BMW\" }, { \"color\" : \"Red\", \"type\" : \"FIAT\" }]";
ObjectMapper objectMapper = new ObjectMapper();
List<Car> listCar = objectMapper.readValue(jsonCarArray, new TypeReference<List<Car>>(){});
Jackson注解擴展
@JsonIdentityReference
使用指定的標識來序列化Java對象,而不是序列化整個對象
例如:
@JsonIdentityInfo(generator = ObjectIdGenerators.PropertyGenerator.class, property = "id")
@JsonIdentityReference(alwaysAsId = true)
public class BeanWithoutIdentityReference {
private int id;
private String name;
}
將被序列化為:
1
@JsonAppend
運行在序列化時添加額外的屬性
@JsonAppend(attrs = {
@JsonAppend.Attr(value = "version")
})
public class BeanWithAppend {
private int id;
private String name;
// constructor, getters and setters
}
例如,我們在序列化時手動增加version = 1.0的屬性
BeanWithAppend bean = new BeanWithAppend(2, "Bean With Append Annotation");
ObjectWriter writer = mapper.writerFor(BeanWithAppend.class).withAttribute("version", "1.0");
String jsonString = writer.writeValueAsString(bean);
序列化結果:
{
"id": 2,
"name": "Bean With Append Annotation",
"version": "1.0"
}
@JsonNaming
指定序列化的時候屬性命名方式
有四種選項:
KEBAB_CASE
由連字符分割,例如:kebab-case
LOWER_CASE
所有的字母都轉換為小寫,例如:lowercase
SNAKE_CASE
所有的字母都轉換為小寫,並且由下划線分割,例如:snake_case
UPPER_CAMEL_CASE
所有名稱元素,包括第一個元素,都以大寫字母開頭,后跟小寫字母,並且沒有分隔符,例如:UpperCamelCase
使用舉例:
@JsonNaming(PropertyNamingStrategy.SnakeCaseStrategy.class)
public class NamingBean {
private int id;
private String beanName;
}
@JsonPropertyDescription
用於生成字段的描述信息
例如,有下面一個實體:
public class PropertyDescriptionBean {
private int id;
@JsonPropertyDescription("This is a description of the name property")
private String name;
}
我們可以輸出該類的信息:
SchemaFactoryWrapper wrapper = new SchemaFactoryWrapper();
mapper.acceptJsonFormatVisitor(PropertyDescriptionBean.class, wrapper);
JsonSchema jsonSchema = wrapper.finalSchema();
String jsonString = mapper.writeValueAsString(jsonSchema);
結果如下:
{
"type": "object",
"id": "urn:jsonschema:com:baeldung:jackson:annotation:extra:PropertyDescriptionBean",
"properties":
{
"name":
{
"type": "string",
"description": "This is a description of the name property"
},
"id":
{
"type": "integer"
}
}
}
@JsonPOJOBuilder
自定義生成器類,來控制json的反序列化行為
@JsonPOJOBuilder有兩個屬性:
buildMethodName
將JSON字段綁定到bean的屬性后,用於實例化預期bean的無參構造的名稱。默認名稱為
build。
withPrefix
用於自動檢測JSON和bean屬性之間匹配的名稱前綴。默認前綴為
with。
假設我們要反序列化的json如下:
{
"id": 5,
"name": "POJO Builder Bean"
}
對應的pojo:
@JsonDeserialize(builder = BeanBuilder.class)
public class POJOBuilderBean {
private int identity;
private String beanName;
// constructor, getters and setters
}
對應的生成器:
@JsonPOJOBuilder(buildMethodName = "createBean", withPrefix = "construct")
public class BeanBuilder {
private int idValue;
private String nameValue;
public BeanBuilder constructId(int id) {
idValue = id;
return this;
}
public BeanBuilder constructName(String name) {
nameValue = name;
return this;
}
public POJOBuilderBean createBean() {
return new POJOBuilderBean(idValue, nameValue);
}
}
使用ObjectMapper反序列化:
String jsonString = "{\"id\":5,\"name\":\"POJO Builder Bean\"}";
POJOBuilderBean bean = mapper.readValue(jsonString, POJOBuilderBean.class);
