Jackson Tutorial for Xiaobai (1) Basic Concepts and Use

Time:2022-10-7

In the era of front-end and back-end separation, the basic data format for the interaction between the server and the front-end is json. In Java, it is the world of objects, but in Java, it is the world of objects. Under Spring MVC, what is the object we “return”? What about into json? To add, using Spring MVC, we can directly use the object to receive the parameters passed by the front end. Who will complete this conversion process? This is Jackson. In this article, we still use the Q&A style to introduce Jackson.

foreword

We still invite Xiao Chen and Lao Chen, the guests of the interview series. Xiao Chen is still an intern, and Lao Chen is Xiao Chen’s leader. One day, when Xiao Chen was busy, he felt it was necessary to read the interview questions, and suddenly received a WeChat message from the leader:

Jackson Tutorial for Xiaobai (1) Basic Concepts and Use

Jackson Tutorial for Xiaobai (1) Basic Concepts and Use

Jackson Tutorial for Xiaobai (1) Basic Concepts and Use

what is Jackson?

Xiao Chen, who was in front of the computer, scratched his head, still learning from the sea. Open Jackson’s repository on Github and see:

Jackson has been known as “the Java JSON library” or “the best JSON parser for Java”. Or simply as “JSON for Java”.

Jackson is probably best known as Java’s JSON library, or the best JSON parser in Java, or simply Java’s JSON

More than that, Jackson is a suite of data-processing tools for Java (and the JVM platform), including the flagship streaming JSON parser / generator library, matching data-binding library (POJOs to and from JSON) and additional data format modules to process data encoded in Avro, BSON, CSV, Smile, (Java) Properties, Protobuf ,TOML, XML or YAML and even the large set of data format modules to support data types of widely used data types such as Guava, Joda, PCollections and many, many more (see below).

But Jackson is more than that. Jackson is also a set of data processing tools for the JVM platform: JSON parsing and generation, data binding (JSON to object, object JSON), and processing Avro, BSON, CSV, Smile, (Java) Properties , Protobuf , TOML, XML or YAML and other data format modules, and a large number of data modules support more general data type processing such as: Guava, Joda Collections and so on.

To sum up, Jackson is not just a JSON library. Jackson positions itself as a data processing tool on the JVM platform, not only parsing JSON, but basically supporting the parsing and generation of mainstream data formats. So my most direct appeal now is JSON to object, how to realize object to JSON? The answer is ObjectMapper.

object to JSON

The core class of Jackson for data processing is ObjectMapper. What methods does ObjectMapper provide to convert objects into JSON? We go in and find the beginning of the write method.

public class ObjectMapperDemo {
    public static void objToJson() throws Exception{
        Map<String,Object> stringObjectMap = new HashMap<>();
        stringObjectMap.put("name","zs");
        stringObjectMap.put("date",new Date());
        ObjectMapper objectMapper = new ObjectMapper();
        System.out.println(objectMapper.writeValueAsString(stringObjectMap));
    }
    public static void main(String[] args) throws Exception {
        objToJson();
    }
}

Output result:Jackson Tutorial for Xiaobai (1) Basic Concepts and Use

Xiao Chen looked at the output. Why didn’t the Date field change to the timestamp format? Is this the default time format? If it is the default, is there any way to change it? Xiao Chen began to search for the method of ObjectMapper. Sure enough, there is a setDateFormat method in ObjectMapper. Just re-specify the format:

public class ObjectMapperDemo {

    public static void objToJson() throws Exception{
        Map<String,Object> stringObjectMap = new HashMap<>();
        stringObjectMap.put("name","zs");
        stringObjectMap.put("date",new Date());
        ObjectMapper objectMapper = new ObjectMapper();
        objectMapper.setDateFormat(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"));
        System.out.println(objectMapper.writeValueAsString(stringObjectMap));
    }
    public static void main(String[] args) throws Exception {
        objToJson();
    }
}

Output result:Jackson Tutorial for Xiaobai (1) Basic Concepts and Use

At this point, Xiao Chen suddenly remembered that the Date type fields returned by the company to the front end have become yyyy-MM-dd HH:mm:ss. Could it be that the web in Spring Boot registered it by itself? So Xiao Chen quickly set up a Spring Boot web project, wrote an interface at will, and wanted to verify his conjecture:

@RestController
public class HelloWorldController {
    @GetMapping("hello")
    public Map<String,Object> test(String name) {
        Map<String,Object> map = new HashMap<>();
        map.put("aa",new Date());
        return map;
    }
}

Jackson Tutorial for Xiaobai (1) Basic Concepts and Use

Looking at the results of the browser, Xiao Chen thinks that the company has actually modified the default ObjectMapper, which should be somewhere in the project, but he just didn’t see it.

JSON to Object

Since the object to JSON is the method at the beginning of the write, then I have reason to believe that the json to the object is the beginning of the read method.

Jackson Tutorial for Xiaobai (1) Basic Concepts and Use

It is divided into 9 groups according to the first parameter type:

  1. The first parameter is a byte array
  2. The first parameter is DataInput
  3. The first parameter is the File object
  4. The first parameter is InputStream
  5. The first parameter is JsonParser
  6. The first parameter is Reader
  7. The first parameter is String
  8. The first parameter is the URL
  9. The first parameter is JsonParser

Let’s study the case where the first parameter is byte. We can understand the type of the first parameter as how to send JSON to ObjectMapper.

public class ObjectMapperDemo {

    private  static ObjectMapper objectMapper = new ObjectMapper();

    private  static  void  initObjectMapper(){
        objectMapper.setDateFormat(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"));
    }

    public static String  objToJson() throws Exception{
        Map<String,Object> stringObjectMap = new HashMap<>();
        stringObjectMap.put("name","zs");
        stringObjectMap.put("date",new Date());
        initObjectMapper();
        return  objectMapper.writeValueAsString(stringObjectMap);
    }
    public static void main(String[] args) throws Exception {
        String json = objToJson();
        jsonToObj(json);
    }
    
    private static void jsonToObj(String json) throws Exception {
        Map<String,Object> map = objectMapper.readValue(json, Map.class);
        System.out.println(map);
    }
}

What is JavaType used for? Let’s take a look at JavaType:

Jackson Tutorial for Xiaobai (1) Basic Concepts and Use

This is an abstract class, look at its subclasses:

Jackson Tutorial for Xiaobai (1) Basic Concepts and Use

What’s the point of these classes? , Have you ever thought of Java’s generic erasure? Officially it’s called type erasure. Generics were introduced in JDK 5. Before that, there were no generics. The main purpose of introducing generics at that time was to parameterize types, but one of Java’s excellent features is forward compatibility, so when Java implements generics The choice of type erasure, to some extent you can understand that Java’s generics are not brought to the bytecode. So what if I want to do the following:

private static void jsonToObj(String json) throws Exception {
    // This will report an error directly
    Map<String,Object> map = objectMapper.readValue(json, Map<String,Date>.class);
    System.out.println(map);
}

In order to achieve the above effect, Jackson decided to save the country by curve, and launched JavaType. So how to use it, let’s use CollectionType as an example to introduce:

// omit get/set
public class Student {
    private int id;
    private String name;
    private String number;
    private Boolean status;
    private Map<String,Object> map;
}
private static <E> List<E> jsonToObj(String json, Class<? extends List> collectionType ,Class<E> elementType) throws Exception{
        CollectionType javaType = TypeFactory.defaultInstance().constructCollectionType(collectionType, elementType);
        return objectMapper.readValue(json,javaType);
}

What are CollectionLikeType and MapLikeType used for? This Like means like, we can get a glimpse of the clues in the annotations of these two classes:

  • CollectionLikeType:

Type that represents things that act similar to Collection; but may or may not be instances of that interface. This specifically allows framework to check for configuration and annotation settings used for Map types, and pass these to custom handlers that may be more familiar with actual type.

This type handles which behavior is similar to the Collections framework, but is not an instance of the Collections framework. In particular, the framework is allowed to inspect the configuration and annotations for the Map type and pass it to the more appropriate handler.
No collections matching this requirement have been found yet

  • MapLikeType:

Type that represents Map-like types; things that consist of key/value pairs but that do not necessarily implement Map, but that do not have enough introspection functionality to allow for some level of generic handling. This specifically allows framework to check for configuration and annotation settings used for Map types, and pass these to custom handlers that may be more familiar with actual type.
Handles types like Map, stores key-value pairs, but does not implement the Map interface.

Up to now, the built-in collection framework of JDK meets our requirements. Apache Collections provides extensions to the collection framework of JDK:

MultiValuedMap is a top-level interface that allows storing key-value pairs with the same key

Now let’s talk about TypeReference, another way of “getting around generic erasure”, the comment says:

This generic abstract class is used for obtaining full generics type information by sub-classing; it must be converted to ResolvedType implementation (implemented by JavaType from “databind” bundle) to be used. Class is based on ideas from http://gafter.blogspot.com/20… , Additional idea (from a suggestion made in comments of the article) is to require bogus implementation of Comparable (any such generic interface would do, as long as it forces a method with generic type to be implemented). to ensure that a Type argument is indeed given.
Usage is by sub-classing: here is one way to instantiate reference to generic type List<Integer>:

TypeReference ref = new TypeReference<List<Integer>>() { };which can be passed to methods that accept TypeReference, or resolved using TypeFactory to obtain

Complete generic information is available through a subclass of TypeReference, whose design was inspired by the article in the link. Through this class we can directly convert json to List<Student> .

Example of use:

 studentList  = objectMapper.readValue("", new TypeReference<List<Student>>() {});

Let’s also appreciate this article. The author of this article is the famous NEAL GAFTER (participated in the design of JDK 1.4 to 5 and Lambda expressions). This article is short and concise, and briefly discusses how to use generic Under erasure, solve the generic type in the collection generic type. Under the mechanism of generic type erasure, we cannot write

List<Student>.class

, This is the origin of TypeReference. TypeReference is an abstract class. By instantiating this class, we can get the generic information filled in through reflection:

TypeReference<List<String>> x = new TypeReference<List<String>>() {};

Among the above parameters, we don’t know JsonParser. From the class name, it can be inferred that this class is responsible for Json parsing. The annotation on the class says:

Base class that defines public API for reading JSON content. Instances are created using factory methods of a JsonFactory instance.

Define a set of APIs for reading JSON content and instantiate them through JsonFactory.

Relatively speaking, the method inside is more primitive. The above method of reading json and ObjectMapper is done with the help of JsonParser, which defines some underlying methods of reading json. This article will not introduce in detail, but only understand.

JSON feature configuration

So far, we have a general understanding of reading and writing JSON, so if I want to configure some features, for example, in order to save bandwidth, if the field is null, it will not be returned to the front end. How to configure it?

// Configure in ObjectMapper
objectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);

More features can be configured in the configure method of ObjectMapper, the following is the method signature:

// JSON to object
// DeserializationFeature is an enumeration class
// Common features are: ACCEPT_EMPTY_ARRAY_AS_NULL_OBJECT This feature is to serialize an empty string into an object as a null value
public ObjectMapper configure(DeserializationFeature f, boolean state)
// Object to JSON 
public ObjectMapper configure(SerializationFeature f, boolean state)

in conclusion

In Jackson, we use read to convert json to object, write to convert object to json, if we need to configure some features, configure it through configure.

References

Recommended Today

NutUI invites you to build together, Contributor hello

foreword NutUISince its birth, NutUI has been keeping up with the development of technology and constantly introducing new ones. NutUI has experienced three technological innovations and transformations: v1.0, v2.0, and v3.0. It has always maintained a steady development trend, from a single basic component library to a multi-terminal UI component library serving thousands of developers. […]