Jackson's Most Common Configurations and Notes

Posted by fred2k7 on Thu, 07 Nov 2019 16:29:23 +0100

1. Beans

import java.util.Date;
import java.util.LinkedList;
import java.util.List;

public class Result<T> {

    private Integer code;
    private String message;
    private Date time;
    private T data;

    public Integer getCode() {
        return code;
    }

    public void setCode(Integer code) {
        this.code = code;
    }

    public String getMessage() {
        return message;
    }

    public void setMessage(String message) {
        this.message = message;
    }

    public Date getTime() {
        return time;
    }

    public void setTime(Date time) {
        this.time = time;
    }

    public T getData() {
        return data;
    }

    public void setData(T data) {
        this.data = data;
    }

    @Override
    public String toString() {
        return "Result{" +
                "code=" + code +
                ", message='" + message + '\'' +
                ", time=" + time +
                ", data=" + data +
                '}';
    }

    static Result getResult(){
        Result<List<String>> result = new Result<>();
        result.setCode(200);
        result.setTime(new Date());
        result.setMessage("Hello Jackson!");
        LinkedList<String> strings = new LinkedList<>();
        strings.add("aa");
        strings.add("bb");
        strings.add("cc");
        result.setData(strings);
        return result;
    }
}

2. Serialization

import com.fasterxml.jackson.core.JsonEncoding;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import org.junit.Test;

import java.io.IOException;
import java.io.StringWriter;

public class JacksonSerTest {

    private static final ObjectMapper objectMapper = new ObjectMapper();

    @Test
    public void writeValueAsString() throws JsonProcessingException {
        //1.8 Newly added time-related class adapters
        objectMapper.registerModule(new JavaTimeModule());
        String value = objectMapper.writeValueAsString(Result.getResult());
        System.out.println(value);
    }

    @Test
    public void writeValue() throws IOException {
        //Write OutputStream directly
        objectMapper.writeValue(System.out,Result.getResult());
    }

    @Test
    public void toWriter() throws IOException {
        StringWriter stringWriter = new StringWriter();
        //Write Writer
        objectMapper.writeValue(stringWriter,Result.getResult());
        System.out.println(stringWriter.toString());
    }

    @Test
    public void jsonGenerator() throws IOException {
        JsonGenerator jsonGenerator = objectMapper.getFactory().createGenerator(System.out, JsonEncoding.UTF8);
        objectMapper.writeValue(jsonGenerator,Result.getResult());
    }

    @Test
    public void writeObject() throws IOException {
        JsonGenerator jsonGenerator = objectMapper.getFactory().createGenerator(System.out, JsonEncoding.UTF8);
        jsonGenerator.writeObject(Result.getResult());
    }

}

3. Deserialization

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.junit.Test;

import java.util.Iterator;
import java.util.Map;

public class JacksonDesTest {

    private static final ObjectMapper objectMapper = new ObjectMapper();

    public static final String content = "{\"code\":200,\"message\":\"Hello Jackson!\",\"time\":1572948614250,\"data\":[\"aa\",\"bb\",\"cc\"]}";

    @Test
    public void readValue() throws JsonProcessingException {
        Result result = objectMapper.readValue(content, Result.class);
        System.out.println(result);
    }

    @Test
    public void readMap() throws JsonProcessingException {
        Map map = objectMapper.readValue(content, Map.class);
        System.out.println(map.get("code"));
        System.out.println(map.get("data"));
    }

    @Test
    public void readTree() throws JsonProcessingException {
        JsonNode jsonNode = objectMapper.readTree(content);
        JsonNode code = jsonNode.get("code");
        System.out.println(code.asInt());
        JsonNode data = jsonNode.get("data");
        Iterator<JsonNode> elements = data.elements();
        while (elements.hasNext()){
            JsonNode next = elements.next();
            System.out.println(next.asText());
        }
    }
}

4. Configuration

parameter Explain Default value
INDENT_OUTPUT Format Output false
WRITE_DATES_AS_TIMESTAMPS Is date serialized as a timestamp true
WRITE_DATE_KEYS_AS_TIMESTAMPS Whether date is serialized as a map key as a time stamp true
WRITE_CHAR_ARRAYS_AS_JSON_ARRAYS Whether char[] converts to string false
WRITE_ENUMS_USING_TO_STRING Enumerate whether to use Enum.toString(), otherwise Enum.name() false
WRITE_ENUMS_USING_INDEX Is the enumeration value serialized to a number false
WRITE_ENUM_KEYS_USING_INDEX Map key s are numbers when enumerating false

Configuration in 2

ObjectMapper mapper = new ObjectMapper();
// Modes are equivalent in the following 2
objectMapper.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS,true);
objectMapper.enable(SerializationFeature.FAIL_ON_EMPTY_BEANS);
// Modes are equivalent in the following 2
objectMapper.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS,false);
objectMapper.disable(SerializationFeature.FAIL_ON_EMPTY_BEANS);
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import org.junit.Test;

import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

public class JacksonConfigTest {

    private static final ObjectMapper objectMapper = new ObjectMapper();

    @Test
    public void config() throws JsonProcessingException {
        SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmss");
        objectMapper.setDateFormat(sdf);
        // Format Output
        objectMapper.configure(SerializationFeature.INDENT_OUTPUT,true);
        // Date Do Not Convert to Timestamp
        objectMapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS,false);
        //Time stamp when Map key is Date
        objectMapper.configure(SerializationFeature.WRITE_DATE_KEYS_AS_TIMESTAMPS,true);
        //char[] Array to String
        objectMapper.configure(SerializationFeature.WRITE_CHAR_ARRAYS_AS_JSON_ARRAYS,false);
        //Enumeration values use ordinal (number), and Enum.name is used by default
        objectMapper.configure(SerializationFeature.WRITE_ENUMS_USING_INDEX,true);
        //Use Enum.toString when you need to customize the enumeration output
        objectMapper.configure(SerializationFeature.WRITE_ENUMS_USING_TO_STRING,true);
        // Map key s are numbers when enumerating
        objectMapper.configure(SerializationFeature.WRITE_ENUM_KEYS_USING_INDEX,true);
        String result = objectMapper.writeValueAsString(getConfigBean());
        System.out.println(result);
    }

    @Test
    public void include() throws JsonProcessingException {
        // Property Null is not serialized
        objectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
        // Property is default value not serialized
        objectMapper.setSerializationInclusion(JsonInclude.Include.NON_DEFAULT);
        // Property is''or NULL is not serialized
        objectMapper.setSerializationInclusion(JsonInclude.Include.NON_EMPTY);
        String result = objectMapper.writeValueAsString(getConfigBean());
        System.out.println(result);
    }

    private static ConfigBean getConfigBean(){
        ConfigBean configBean = new ConfigBean();
        configBean.setChars("Jackson".toCharArray());
        Date date = new Date();
        configBean.setDate(date);
//        configBean.setNoGetter("noSetter");
        HashMap<Status, Integer> statusMap = new HashMap<>();
        statusMap.put(Status.SUCCESS,1);
        statusMap.put(Status.FAIL,2);
        configBean.setEnumMap(statusMap);
        HashMap<Date, Integer> dateMap = new HashMap<>();
        dateMap.put(date,1);
        dateMap.put(new Date(),null);
        configBean.setDateMap(dateMap);
        configBean.setStatus(Status.SUCCESS);
        return configBean;
    }

    static class ConfigBean{
        private Date date;
        private char[] chars;
        private Map<Status,Integer> enumMap;
        private Map<Date,Integer> dateMap;
        private String noGetter;
        private Status status;

        public Status getStatus() {
            return status;
        }

        public void setStatus(Status status) {
            this.status = status;
        }

        public Date getDate() {
            return date;
        }

        public void setDate(Date date) {
            this.date = date;
        }

        public char[] getChars() {
            return chars;
        }

        public void setChars(char[] chars) {
            this.chars = chars;
        }

        public Map<Status, Integer> getEnumMap() {
            return enumMap;
        }

        public void setEnumMap(Map<Status, Integer> enumMap) {
            this.enumMap = enumMap;
        }

        public Map<Date, Integer> getDateMap() {
            return dateMap;
        }

        public void setDateMap(Map<Date, Integer> dateMap) {
            this.dateMap = dateMap;
        }
    }

    enum Status{
        SUCCESS(200,"success"),
        FAIL(500,"fail");

        private Integer code;

        private String msg;

        Status(int code, String msg) {
            this.code = code;
            this.msg = msg;
        }

        public Integer getCode() {
            return code;
        }

        public String getMsg() {
            return msg;
        }
    }
}

Most commonly used

INDENT_OUTPUT: Format, check to avoid using other formatting tools when debugging

WRITE_DATES_AS_TIMESTAMPS: Clients sometimes need time stamps and sometimes format strings

WRITE_ENUMS_USING_INDEX: Clients are often not interested in enumeration names

WRITE_ENUMS_USING_TO_STRING: Used when customizing the output of an enumeration, rewriting the toString of the enumeration is possible, with a lower priority than WRITE_ENUMS_USING_INDEX

JsonInclude.Include.NON_NULL: No null output, very common

objectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
objectMapper.configure(SerializationFeature.INDENT_OUTPUT,true);
objectMapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS,false);
objectMapper.configure(SerializationFeature.WRITE_ENUMS_USING_INDEX,true);
objectMapper.configure(SerializationFeature.WRITE_ENUMS_USING_TO_STRING,true);

5. Comments

@JsonProperty: name and location can be set

@JsonIgnore: Exclude attributes

@JsonPropertyOrder: Attribute serialization location

@JsonFormat: Set formatting

@JsonInclude: Contains only if the condition is met

@JsonRootName: class annotation, specifying the JSON root attribute name

@JsonIgnoreProperties: class annotation, serialization ignores properties.Deserialization can configure @JsonIgnoreProperties(ignoreUnknown=true) to ignore unknown properties

import com.fasterxml.jackson.annotation.*;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import org.junit.Test;

import java.util.Date;

public class JacksonAnnotationTest {

    private static final ObjectMapper objectMapper = new ObjectMapper();

    @Test
    public void config() throws JsonProcessingException {
        objectMapper.configure(SerializationFeature.INDENT_OUTPUT,true);
        objectMapper.configure(SerializationFeature.WRAP_ROOT_VALUE,true);
        String result = objectMapper.writeValueAsString(getConfigBean());
        System.out.println(result);
    }

    private static AnnotationBean getConfigBean(){
        AnnotationBean annotationBean = new AnnotationBean();
        annotationBean.setStatus(true);
        annotationBean.setCode(200);
        annotationBean.setDate(new Date());
        annotationBean.setIgnoreA("ignoreA");
        annotationBean.setIgnoreB("ignoreB");
        annotationBean.setMessage("message");
        annotationBean.setIgnore("ignore");
        return annotationBean;
    }

    @JsonRootName("root")
    @JsonIgnoreProperties({"ignoreA","ignoreB"})
//    @JsonPropertyOrder(alphabetic=true)
    @JsonPropertyOrder({ "code", "message" })
    static class AnnotationBean<T>{
        @JsonFormat(pattern = "yyyy-MM-dd")
        private Date date;

        private Integer code;

        @JsonProperty("msg")
        private String message;

        private boolean status;
        @JsonIgnore
        private String ignore;

        private String ignoreA;

        private String ignoreB;

        @JsonInclude(JsonInclude.Include.NON_NULL)
        private T data;

        public Date getDate() {
            return date;
        }

        public void setDate(Date date) {
            this.date = date;
        }

        public Integer getCode() {
            return code;
        }

        public void setCode(Integer code) {
            this.code = code;
        }

        public String getMessage() {
            return message;
        }

        public void setMessage(String message) {
            this.message = message;
        }

        public boolean isStatus() {
            return status;
        }

        public void setStatus(boolean status) {
            this.status = status;
        }

        public String getIgnoreA() {
            return ignoreA;
        }

        public void setIgnoreA(String ignoreA) {
            this.ignoreA = ignoreA;
        }

        public String getIgnoreB() {
            return ignoreB;
        }

        public void setIgnoreB(String ignoreB) {
            this.ignoreB = ignoreB;
        }

        public T getData() {
            return data;
        }

        public void setData(T data) {
            this.data = data;
        }

        public String getIgnore() {
            return ignore;
        }

        public void setIgnore(String ignore) {
            this.ignore = ignore;
        }
    }
}

The @JsonRootName annotation must be set to true for SerializationFeature.WRAP_ROOT_VALUE to take effect

@JsonPropertyOrder(alphabetic=true): sorted alphabetically

@JsonPropertyOrder ({"code", "message"}):code, message These two attributes precede other attributes

Topics: Programming Java Junit Attribute JSON