Mastering Jackson JSON Processing in Java

For Spring Boot applications, configure Jackson settings in application.yml:

spring:
  # jackson configuration
  jackson:
    # date format
    date-format: yyyy-MM-dd HH:mm:ss
    # timezone
    time-zone: GMT+8
    # serialization settings
    serialization:
      # pretty print output
      indent-output: false
      # ignore unconvertible objects
      fail-on-empty-beans: false
    # deserialization settings
    deserialization:
      # allow objects to ignore properties not present in JSON
      fail-on-ignored-properties: false
    # set how nulls are serialized
    default-property-inclusion: non_null
    # parser settings
    parser:
      # allow special characters and escape sequences
      allow-unquoted-control-chars: true
      # allow single quotes
      allow-single-quotes: true

Alternatively, configure using properties:

# date formatting
spring.jackson.date-format = yyyy-MM-dd HH:mm:ss
# timezone
spring.jackson.time-zone = GMT+8
# serialization settings
# pretty print output
spring.jackson.serialization.indent-output = false
# ignore unconvertible objects
spring.jackson.serialization.fail-on-empty-beans = false
# deserialization settings
# allow objects to ignore properties not present in JSON
spring.jackson.deserialization.fail-on-ignored-properties = false
# set how nulls are serialized
spring.jackson.default-property-inclusion = non_null
# allow special characters and escape sequences
spring.jackson.parser.allow-unquoted-control-chars = true
# allow single quotes
spring.jackson.parser.allow-single-quotes = true

Java utility class for ObjectMapper configuration:

static JsonMapper objectMapper = JsonMapper.builder().build();
static {
    // don't fail if JSON contains properties not in the POJO
    objectMapper.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);
    objectMapper.disable(SerializationFeature.FAIL_ON_EMPTY_BEANS);
    objectMapper.setDefaultPropertyInclusion(JsonInclude.Include.NON_NULL);
}

Serialization and Deserialization with Matching Field Names

When JSON field names match Java object field names:

package com.example.json.model;

import com.fasterxml.jackson.databind.ObjectMapper;

public class AuthToken {
    private String tokenValue;
    private long expirationTime;
    
    public String getTokenValue() {
        return tokenValue;
    }
    
    public void setTokenValue(String tokenValue) {
        this.tokenValue = tokenValue;
    }
    
    public long getExpirationTime() {
        return expirationTime;
    }
    
    public void setExpirationTime(long expirationTime) {
        this.expirationTime = expirationTime;
    }
    
    @Override
    public String toString() {
        return "AuthToken [tokenValue=" + tokenValue + ", expirationTime=" + expirationTime + "]";
    }
    
    public static void main(String[] args) {
        AuthToken token = new AuthToken();
        token.setTokenValue("2r5fx9eiyapFxEGgHq");
        token.setExpirationTime(7200);
        
        try {
            ObjectMapper mapper = new ObjectMapper();
            String json = mapper.writeValueAsString(token); // serialization
            System.out.println(json);
            
            AuthToken object = mapper.readValue(json, AuthToken.class); // deserialization
            System.out.println(object);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

Output:

{"tokenValue":"2r5fx9eiyapFxEGgHq","expirationTime":7200}
AuthToken [tokenValue=2r5fx9eiyapFxEGgHq, expirationTime=7200]

Serialization and Deserialization with Different Field Names

When JSON field names differ from Java object field names, use @JsonProperty annotation:

package com.example.json.model;

import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.databind.ObjectMapper;

public class AuthToken {
    private String tokenValue;
    private long expirationTime;
    
    @JsonProperty(value="access_token")
    public String getTokenValue() {
        return tokenValue;
    }
    
    @JsonProperty(value="access_token")
    public void setTokenValue(String tokenValue) {
        this.tokenValue = tokenValue;
    }
    
    @JsonProperty(value="expires_in")
    public long getExpirationTime() {
        return expirationTime;
    }
    
    @JsonProperty(value="expires_in")
    public void setExpirationTime(long expirationTime) {
        this.expirationTime = expirationTime;
    }
    
    @Override
    public String toString() {
        return "AuthToken [tokenValue=" + tokenValue + ", expirationTime=" + expirationTime + "]";
    }
    
    public static void main(String[] args) {
        AuthToken token = new AuthToken();
        token.setTokenValue("2r5fx9eiyapFxEGgHq");
        token.setExpirationTime(7200);
        
        try {
            ObjectMapper mapper = new ObjectMapper();
            String json = mapper.writeValueAsString(token); // serialization
            System.out.println(json);
            
            AuthToken object = mapper.readValue(json, AuthToken.class); // deserialization
            System.out.println(object);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

Output:

{"access_token":"2r5fx9eiyapFxEGgHq","expires_in":7200}
AuthToken [tokenValue=2r5fx9eiyapFxEGgHq, expirationTime=7200]

The @JsonProperty annotation applied to getter methods serializes properties with specified names, and when applied to setter methods, deserializes specified names to properties.

Deserializing List Objects

To deserialize JSON arrays into List objects:

public static void main(String[] args) {
    try {
        List<imagecontent> imageList = new ArrayList<>();
        
        ImageContent content = new ImageContent();
        content.setId(1);
        content.setOrgId(100);
        content.setTitle("google");
        content.setImagePath("/upload/images/1.jpg");
        content.setLinkUrl("http://www.google.com");
        content.setStatus("modify");
        imageList.add(content);
        
        content = new ImageContent();
        content.setId(2);
        content.setOrgId(200);
        content.setTitle("intel");
        content.setImagePath("/upload/images/2.jpg");
        content.setLinkUrl("http://www.intel.com");
        content.setStatus("delete");
        imageList.add(content);
        
        ObjectMapper mapper = new ObjectMapper();
        String json = mapper.writeValueAsString(imageList);
        System.out.println(json);
        
        // Method 1: Using JavaType
        JavaType javaType = mapper.getTypeFactory().constructParametricType(List.class, ImageContent.class);
        List<imagecontent> newList = mapper.readValue(json, javaType);
        
        // Method 2: Using TypeReference
        List<imagecontent> newList2 = mapper.readValue(json, new TypeReference<list>>(){});
        
        System.out.println(newList);
    } catch (Exception e) {
        e.printStackTrace();
    }
}
</list></imagecontent></imagecontent></imagecontent>

Use the public T readValue(String content, JavaType valueType) method with JavaType javaType = mapper.getTypeFactory().constructParametricType(List.class, ImageContent.class) to specify collection type and generic type.

Handling Unrecognized Fields

When JSON contains fields not present in the Java object:

ObjectMapper mapper = new ObjectMapper();
mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
// or
mapper.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);

Alternatively, add the @JsonIgnoreProperties annotation to the class:

@JsonIgnoreProperties(ignoreUnknown=true)
public class MyDataModel {
    // class fields
}

The @JsonIgnore annotation can be used on fields or getter methods to ignore specific fields during serialization/deserialization. When applied to setter methods, it has the same effect as when applied to fields. This annotation is useful when you want to ignore fields that exist in the POJO.

The @JsonIgnoreProperties annotation can specify which fields to ignore:

@JsonIgnoreProperties({ "internalId", "secretKey" })
public class MyDataModel {
    // class fields
}

Custom Serialization Filter - Regular Objects

Define a test POJO:

package com.example.json.model;

/**
 * Test POJO
 */
public class UserProfile {
    private String fullName;
    private String mailingAddress;
    private int age;
    
    public String getFullName() {
        return fullName;
    }
    
    public void setFullName(String fullName) {
        this.fullName = fullName;
    }
    
    public int getAge() {
        return age;
    }
    
    public void setAge(int age) {
        this.age = age;
    }
    
    public String getMailingAddress() {
        return mailingAddress;
    }
    
    public void setMailingAddress(String mailingAddress) {
        this.mailingAddress = mailingAddress;
    }
}

Define a filter interface:

package com.example.json.filter;

import com.fasterxml.jackson.annotation.JsonFilter;

@JsonFilter("UserProfileFilter")
public interface UserProfileFilter {
}

Implement the filter:

package com.example.json.filter;

import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializerProvider;
import com.fasterxml.jackson.databind.ser.FilterProvider;
import com.fasterxml.jackson.databind.ser.PropertyWriter;
import com.fasterxml.jackson.databind.ser.impl.SimpleBeanPropertyFilter;
import com.fasterxml.jackson.databind.ser.impl.SimpleFilterProvider;
import com.example.json.model.UserProfile;

public class SerializationFilterDemo {
    public static void main(String[] args) throws JsonProcessingException {
        UserProfile profile = new UserProfile();
        profile.setFullName("John Doe");
        profile.setMailingAddress("123 Main St, Anytown");
        profile.setAge(30);
        
        // Method 1: Define filter
        SimpleBeanPropertyFilter filter = SimpleBeanPropertyFilter.serializeAllExcept("age");
        
        // Method 2: Override SimpleBeanPropertyFilter's serializeAsField method
        SimpleBeanPropertyFilter customFilter = new SimpleBeanPropertyFilter() {
            @Override
            public void serializeAsField(Object pojo, JsonGenerator jgen, 
                                        SerializerProvider provider, PropertyWriter writer) throws Exception {
                if (!writer.getName().equals("age")) {
                    writer.serializeAsField(pojo, jgen, provider);
                }
            }
        };
        
        // Define provider
        FilterProvider filterProvider = new SimpleFilterProvider()
            .addFilter("UserProfileFilter", filter); // or use customFilter
        
        // Data binding
        ObjectMapper mapper = new ObjectMapper();
        mapper.addMixIn(UserProfile.class, UserProfileFilter.class);
        mapper.setFilterProvider(filterProvider);
        
        String json = mapper.writeValueAsString(profile);
        System.out.println(json);
    }
}

Output:

{"fullName":"John Doe","mailingAddress":"123 Main St, Anytown"}

The mapper.addMixIn(UserProfile.class, UserProfileFilter.class) is crucial. The addMixIn method signature is:

public ObjectMapper addMixIn(Class> target, Class> mixinSource);

This method uses annotations from the mixinSource interface or class to override annotations in the target or its subtypes.

Custom Serialization Filter - List Object Fields

Test POJOs:

package com.example.json.model;

import java.util.List;

public class NewsArticleCollection {
    /**
     * Articles
     */
    private List<newsarticle> articles;

    public List<newsarticle> getArticles() {
        return articles;
    }

    public void setArticles(List<newsarticle> articles) {
        this.articles = articles;
    }
}

package com.example.json.model;

public class NewsArticle {
    /**
     * Title
     */
    private String title;
    /**
     * Cover image media ID (must be permanent media ID)
     */
    private String coverMediaId;
    /**
     * Author
     * [Optional]
     */
    private String author;
    /**
     * Article summary, only available for single articles, empty for multiple articles.
     * If not provided, defaults to first 64 characters of content.
     * [Optional]
     */
    private String summary;
    /**
     * Whether to show cover image, 0 for false, 1 for true
     */
    private boolean showCoverImage;
    /**
     * Article content, supports HTML tags, must be less than 20,000 characters and 1MB.
     * JavaScript will be removed. Image URLs must come from "Upload image in article" interface.
     * External image URLs will be filtered.
     */
    private String content;
    /**
     * Original URL of the article, the URL after clicking "Read more"
     */
    private String sourceUrl;
    
    // Getters and setters
    public String getTitle() {
        return title;
    }
    
    public void setTitle(String title) {
        this.title = title;
    }
    
    public String getCoverMediaId() {
        return coverMediaId;
    }
    
    public void setCoverMediaId(String coverMediaId) {
        this.coverMediaId = coverMediaId;
    }
    
    public String getAuthor() {
        return author;
    }
    
    public void setAuthor(String author) {
        this.author = author;
    }
    
    public String getSummary() {
        return summary;
    }
    
    public void setSummary(String summary) {
        this.summary = summary;
    }
    
    public boolean getShowCoverImage() {
        return showCoverImage;
    }
    
    public void setShowCoverImage(boolean showCoverImage) {
        this.showCoverImage = showCoverImage;
    }
    
    public String getContent() {
        return content;
    }
    
    public void setContent(String content) {
        this.content = content;
    }
    
    public String getSourceUrl() {
        return sourceUrl;
    }
    
    public void setSourceUrl(String sourceUrl) {
        this.sourceUrl = sourceUrl;
    }
}
</newsarticle></newsarticle></newsarticle>

Filter non-required fields (author, summary) in NewsArticle:

package com.example.json.filter;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.ser.FilterProvider;
import com.fasterxml.jackson.databind.ser.impl.SimpleBeanPropertyFilter;
import com.fasterxml.jackson.databind.ser.impl.SimpleFilterProvider;
import com.example.json.model.NewsArticle;
import com.example.json.model.NewsArticleCollection;

public class NewsSerializationDemo {
    public static void main(String[] args) throws JsonProcessingException {
        NewsArticle article = new NewsArticle();
        article.setTitle("Sample Title");
        article.setCoverMediaId("sample_media_id");
        article.setShowCoverImage(true);
        article.setContent("Article content here");
        article.setSourceUrl("https://example.com");
        article.setAuthor("John Doe");
        article.setSummary("This is a summary of the article");
        
        List<newsarticle> articles = new ArrayList<>();
        articles.add(article);
        
        NewsArticleCollection newsCollection = new NewsArticleCollection();
        newsCollection.setArticles(articles);
        
        String json = JsonFilterUtil.toJson(NewsArticle.class, newsCollection, new String[]{"author", "summary"});
        System.out.println(json);
    }
}
</newsarticle>

Utility class for JSON filtering:

/**
 * Serialization with custom filter
 * @param clazz Class of objects in the list
 * @param value Object to serialize
 * @param filterFields Fields to exclude
 * @return JSON string
 */
public static String toJson(Class> clazz, Object value, String[] filterFields) {
    try {
        SimpleBeanPropertyFilter filter = SimpleBeanPropertyFilter.serializeAllExcept(filterFields);
        FilterProvider filterProvider = new SimpleFilterProvider().addFilter("UserProfileFilter", filter);
        ObjectMapper mapper = new ObjectMapper();
        mapper.addMixIn(clazz, UserProfileFilter.class);
        mapper.setFilterProvider(filterProvider);
        return mapper.writeValueAsString(value);
    } catch (Exception e) {
        e.printStackTrace();
        return "";
    }
}

Important: The class in addMixIn should be the class of objects in the list.

Excluding NULL, DEFAULT, EMPTY Values from Serialization

Method 1: Using @JsonInclude annotation

  • Applied to properties: affects only that property
  • Applied to classes: affects all properties of the class including inherited ones
@JsonInclude(Include.NON_NULL) // don't serialize null properties

Method 2: Using code

ObjectMapper mapper = new ObjectMapper();
mapper.setSerializationInclusion(Include.NON_NULL);

Available values:

  • Include.ALWAYS (default) - serialize all properties
  • Include.NON_DEFAULT - don't serialize properties with default values
  • Include.NON_EMPTY - don't serialize empty or null properties
  • Include.NON_NULL - don't serialize null properties

Property Naming Strategies

Different naming strategies for JSON properties:

Organization org = new Organization();
org.setName("apple");
org.setPostalCode("100000");

ObjectMapper mapper = new ObjectMapper();
mapper.setPropertyNamingStrategy(PropertyNamingStrategy.UPPER_CAMEL_CASE);

try {
    String json = mapper.writeValueAsString(org); // serialization
    System.out.println(json);
    
    Organization organization = mapper.readValue(json, Organization.class); // deserialization
    System.out.println(organization.toString());
} catch (Exception e) {
    e.printStackTrace();
}

PropertyNamingStrategy constants:

Serialization Inclusion Settings

Control which property are included in serialization:

Organization org = new Organization();
org.setName("");
org.setPostalCode(null);

ObjectMapper mapper = new ObjectMapper();
mapper.setSerializationInclusion(JsonInclude.Include.ALWAYS);

try {
    String json = mapper.writeValueAsString(org); // serialization
    System.out.println(json);
    
    Organization organization = mapper.readValue(json, Organization.class); // deserialization
    System.out.println(organization.toString());
} catch (Exception e) {
    e.printStackTrace();
}

JsonInclude.Include options:

Date Formatting

Format dates during serialization/deserialization:

import com.fasterxml.jackson.annotation.JsonFormat;
import org.springframework.format.annotation.DateTimeFormat;

@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss",timezone = "GMT+8")
@TableField("timestamp_")
private String timestamp;

Tags: jackson JSON Java serialization Java deserialization Spring Boot

Posted on Thu, 14 May 2026 23:11:37 +0000 by svguerin3