Jackson使用指南


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);

這時,將只會序列化iditemName字段

@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);

常用的一些設置:

  1. DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES:忽略不識別的字段
  2. DeserializationFeature.FAIL_ON_NULL_FOR_PRIMITIVES:允許使用屬性的默認值進行反序列化
  3. 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);

👉 代碼倉庫
👉 Jackson JSON Tutorial


免責聲明!

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



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