This is the 8th day of my participation in the August More Text Challenge. For details, see:August is more challenging

Jackson practical posture summary

Using JSON for data interaction can be said to be very common, in The Java side, the common JSON parsing framework is also many, such as GSON, FastJSON and Spring MVC default Jackson; In this article, we will focus on the basic Jackson gestures, as well as the things you should know in everyday development, such as the common ones

  • Normal object to JSON string
  • Json string to POJO, to Map/List
  • Generic support
  • Hump/underline interturn, custom mapping
  • Bean compliance specification
  • Serialize/deserialize the exception scenario

1. Project dependency

To build a project with Maven, you need to use Jackson for serialization, and the core introduces the following packages

<dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-databind</artifactId>
    <version>2.12.4</version>
</dependency>
Copy the code

2. Basic posture

In Jackson, ObjectMapper is essential if you want to serialize/deserialize

Like turning an object into a Json String

public static <T> String encode(T obj) {
    try {
        return new ObjectMapper().writeValueAsString(obj);
    } catch (Exception e) {
        throw newUnsupportedOperationException(e); }}Copy the code

deserialization

public static <T> T decode(String str, Class<T> clz) {
    try {
        return new ObjectMapper().readValue(str, clz);
    } catch (Exception e) {
        throw newUnsupportedOperationException(e); }}Copy the code

Pay attention to

  • One significant difference between Jackson and Gson/FastJSON is that its serialization/deserialization has declared exceptions that need to be declared or actively caught (which is not very friendly).
  • Second, it is not recommended to create an ObjectMapper object every time, and reuse can be considered

3. Generic deserialization

For generic deserialization, using the above, passing in a class object, does not work very well. As with Gson/FastJson, Jackson also supports back serialization by Type

public static <T> T decode(String str, Type type) {
    try {
        return objectMapper.readValue(str, objectMapper.getTypeFactory().constructType(type));
    } catch (Exception e) {
        throw newUnsupportedOperationException(e); }}Copy the code

Focus on the above parameter, through objectMapper. GetTypeFactory () constructType JavaType objects (type) to create a need

A demo posture is as follows

GenericBean<Map> gbean2 = JacksonUtil.decode(str, new com.fasterxml.jackson.core.type
      .TypeReference<GenericBean<Map>>() {}.getType());
System.out.println(gbean2);
Copy the code

4. Turn the Map/List

What’s special about turning to a normal Map/List

public static Map toMap(String str) {
    try {
        return objectMapper.readValue(str, Map.class);
    } catch (JsonProcessingException e) {
        throw newUnsupportedOperationException(e); }}public static List toList(String str) {
    try {
        return objectMapper.readValue(str, List.class);
    } catch (JsonProcessingException e) {
        throw newUnsupportedOperationException(e); }}Copy the code

5. JsonNode

JsonNode is a node object defined for Jackson, similar to Gson’s JsonObject/JsonArray and FastJson’s JsonObject/JsonArray. You can use it to manipulate JSON objects in a more user-friendly way (of course, going directly to JAVA beans is more recommended)

public static JsonNode toObj(String str) {
    try {
        return objectMapper.readTree(str);
    } catch (JsonProcessingException e) {
        throw newUnsupportedOperationException(e); }}Copy the code

Use demo as follows

String str = 12, "{\" userId \ ": \" the userName \ ": \" yh \ "and \" userMoney \ ": 12.3, \" userSkills \ ": [\" 1 \ ", \ "2 \", \ "3 \], \" extra \ ": {\" a \ ": \" 123 \ ", \ \ "b" : 345, \ \ "c" : [\ "1 \" and \ "2 \", \ "3 \], \" d \ ": 35.1}, \" hello \ ": \" hello \ "}";
JsonNode bean = JacksonUtil.toObj(str);
int userId = bean.get("userId").asInt();
Copy the code

6. Humps and underscores

Jackson conveniently supports a common case in which a JSON string key is underlined and a Java bean is named after its hump

/** * Hump down line change **@param obj
 * @return* /
public static String toUnderStr(Object obj) {
    ObjectMapper objectMapper = new ObjectMapper();
    // The hump is underlined
    objectMapper.setPropertyNamingStrategy(PropertyNamingStrategies.SNAKE_CASE);
    try {
        return objectMapper.writerWithDefaultPrettyPrinter().writeValueAsString(obj);
    } catch (JsonProcessingException e) {
        throw newUnsupportedOperationException(e); }}/** * String in underline format, convert to hump format Java bean */ 
public static <T> T fromUnderStr(String str, Class<T> clz) {
    ObjectMapper objectMapper = new ObjectMapper();
    // The hump is underlined
    objectMapper.setPropertyNamingStrategy(PropertyNamingStrategies.SNAKE_CASE);
    try {
        return objectMapper.readValue(str, clz);
    } catch (JsonProcessingException e) {
        throw newUnsupportedOperationException(e); }}Copy the code

As you can see from the code above, the transfer between humps and underscores is supported mainly by setting PropertyNamingStrategies, which in Jackson support the following configurations

  • LOWER_CAMEL_CASE
  • UPPER_CAMEL_CASE
  • SNAKE_CASE
  • LOWER_CASE
  • KEBAB_CASE
  • LOWER_DOT_CASE

What if I only want to do this for a single class, using the underline/hump conversion that works globally?

This can be done using the annotation @jsonnaming

@JsonNaming(PropertyNamingStrategies.SnakeCaseStrategy.class)
public class SimpleBean implements Serializable {
    private static final long serialVersionUID = -9111747337710917591L;

    private Integer userId;

    private String userName;

    private double userMoney;
}
Copy the code

In this case, if we serialize the SimpleBean object as a JSON string, even if we call the basic new ObjectMapper().writevalueasString (SimpleBean), The output is also an underlined JSON string; Similarly, when deserializing, the underscore is turned into a hump

7. Field alias

The hump and underline names are described above, but there are other special scenarios where you can alias a field, which you can annotate with @jsonProperties

@JsonProperty("user")
private String userName;
Copy the code

When serialized as a JSON string, the key corresponding to userName is user

8. The field is ignored

When serializing, it is inevitable that some fields will not be serialized/deserialized, and there are two common ways to do so

8.1 @ JsonIgnore annotation

Simply add the @jsonignore annotation to the fields you want to ignore, such as

@Data
public class SimpleBean implements Serializable {
    private static final long serialVersionUID = -9111747337710917591L;
    @JsonIgnore
    private SimpleBean self;
}
Copy the code

8.2 transient keyword

In addition to using the above annotations, you can also use the NATIVE JDK keyword TRANSIENT to declare fields that you want to ignore

private transient SimpleBean self;
Copy the code

Important note:

  • In Jackson, the default scenario is even if the field is decoratedtransientKeywords that will not be ignored also need to be processed as follows
objectMapper = new ObjectMapper();
// Ignore the transient keyword
// case1
objectMapper.configure(MapperFeature.PROPAGATE_TRANSIENT_MARKER, true);

// case2
objectMapper.setVisibility(objectMapper.getSerializationConfig()
        .getDefaultVisibilityChecker()
        .withFieldVisibility(JsonAutoDetect.Visibility.ANY)
        .withGetterVisibility(JsonAutoDetect.Visibility.NONE)
        .withIsGetterVisibility(JsonAutoDetect.Visibility.NONE));
Copy the code

In both of the above methods, object serialization can be achieved without the transient keyword modification

Java Bean conventions

9.1 Get /set Must be available

The Java Bean’s GET /set method must exist, otherwise the serialization and deserialization will only handle the public modified members

public class SimpleBean {
  private String name;
  private Long userId;
  public String desc = "hello world";
  public SimpleBean(a) {
      name = "yhh";
      userId = 10L; }}Copy the code

{“desc”:”hello world”}; Deserialization does not update name, userId;

In particular, if all members of a Java Bean object are private and there is no GET method, an exception will be thrown during serialization with the following message

No serializer found for class com.git.hui.spring.json.bean.SimpleBean and no properties discovered to create BeanSerializer (to avoid exception, disable SerializationFeature.FAIL_ON_EMPTY_BEANS)
Copy the code

9.2 No-parameter constructors are mandatory

If a Java bean does not have a default parameterless constructor, an exception will be thrown when deserialized and cannot be instantiated

An exception message as follows

Cannot construct instance of `com.git.hui.spring.json.bean.SimpleBean` (although at least one Creator exists): cannot deserialize from Object value (no delegate- or property-based Creator)
Copy the code

10. Json string has undefined Bean fields. Ignore Settings

By default, an exception will be thrown if there is an undefined KV in the json string, as shown in the following example

Unrecognized field "xxx" (class com.git.hui.spring.json.bean.GenericBean), not marked as ignorable
Copy the code

If you want to ignore this scenario, you need to disable the FAIL_ON_UNKNOWN_PROPERTIES configuration

new ObjectMapper().disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES)
    .readValue(str, Xxx.class)
Copy the code

Expand knowledge

  • For Spring MVC, the Jackson serialization framework is used by default. If we define the receiving parameter as a JSON string, will an exception be thrown if the current end passes an undefined field?

11. Ignore null when serializing output

By default, serializing a bean object to a JSON string will be output even if the member variable is null, as shown below

{
  "userId" : null."userName" : null."userMoney" : 0.0."userSkills" : null."extra" : null
}
Copy the code

This case is appropriate for some scenarios. For example, when generating an interface document example, you are more concerned with the parameter description, even if it is null. But there are other scenarios where you want to ignore it, because you can save on object size

To ignore the NULL field, set it as follows

new ObjectMapper().setSerializationInclusion(JsonInclude.Include.NON_NULL)
    .writerWithDefaultPrettyPrinter().writeValueAsString(xxx)
Copy the code

Key point is to configure setSerializationInclusion (JsonInclude. Include. NON_NULL)

12. The key is null

For ordinary Java beans, there is no such thing as a null key, but it can happen when you output a Map object as a JSON string, such as

Map<String, String> map = new HashMap<>();
map.put(null."123");
new ObjectMapper().writeValueAsString(map);
Copy the code

The execution above throws an exception directly

Null key for a Map not allowed in JSON (use a converting NullKeySerializer?)
Copy the code

If you want to be compatible with this scenario, you can do so as follows

ObjectMapper objectMapper = new ObjectMapper();
objectMapper.getSerializerProvider().setNullKeySerializer(new JsonSerializer<Object>() {
    @Override
    public void serialize(Object value, JsonGenerator gen, SerializerProvider serializers) throws IOException {
        gen.writeFieldName("null"); }});Copy the code

So what we’re doing here is we’re replacing a null string with a null key

instructions

  • Since the key can be null, of course it can be of any other type, but when the output is serialized, it will be converted to String

Take the following case

Map map = new HashMap();
map.put(new ArrayList<>(), 123);
new ObjectMapper().writeValueAsString(map);
Copy the code

The output string is

{"[]":123}
Copy the code

13 other

The above information covers 95% of the scenarios in which Jackson is used for serialization and deserialization. As for the other relatively rare gestures, such as custom Name policy, default value type for deserialization, type conversion, json annotation support, etc., we will see if there is time to fill in later

II. The other

1. A gray Blog:liuyueyi.github.io/hexblog

A gray personal blog, record all study and work in the blog, welcome everyone to visit

2. Statement

The above content is not as good as the letter, purely the words of a family, due to the limited personal ability, there are inevitably omissions and mistakes, such as found bugs or better suggestions, welcome criticism and correction, not grudging gratitude

  • Micro-blog address: small gray Blog
  • QQ: A gray /3302797840

Wechat official account: a gray blog