Master Jackson in Spring Boot: Essential Annotations and Extension Points
This article provides a comprehensive guide to Jackson’s most frequently used annotations, core modules, and extension points in Spring Boot, illustrating each feature with concrete Java code examples that show how to customize serialization, deserialization, property handling, and polymorphic type processing.
1. Common Jackson Annotations
@JsonSerialize / @JsonDeserialize
@JsonProperty
@JsonIgnore
@JsonFormat
@JsonUnwrapped
@JsonAnyGetter
@JsonInclude
@JsonAlias
@JsonIgnoreProperties
@JsonManagedReference / @JsonBackReference
@JsonCreator
@JsonTypeInfo
@JsonFilter
@JsonAnySetter
@JsonAppend
@JsonIgnoreType
@JsonGetter / @JsonSetter
@JsonPropertyOrder
@JsonSerialize and @JsonDeserialize
These annotations let you plug in custom serializer and deserializer classes to control how an object is converted to and from JSON.
import com.fasterxml.jackson.annotation.JsonDeserialize;
import com.fasterxml.jackson.annotation.JsonSerialize;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
@JsonSerialize(using = CustomSerializer.class)
@JsonDeserialize(using = CustomDeserializer.class)
public class Person {
private String name;
private int age;
// constructors, getters, setters omitted
public static void main(String[] args) throws Exception {
ObjectMapper mapper = new ObjectMapper();
Person person = new Person("John", 30);
String json = mapper.writeValueAsString(person);
System.out.println(json); // {"fullName":"John","years":30}
Person deserialized = mapper.readValue(json, Person.class);
System.out.println(deserialized); // Person{name='John', age=30}
}
}
class CustomSerializer extends JsonSerializer<Person> {
@Override
public void serialize(Person person, JsonGenerator gen, SerializerProvider serializers) throws IOException {
gen.writeStartObject();
gen.writeStringField("fullName", person.getName());
gen.writeNumberField("years", person.getAge());
gen.writeEndObject();
}
}
class CustomDeserializer extends JsonDeserializer<Person> {
@Override
public Person deserialize(JsonParser p, DeserializationContext ctxt) throws IOException {
JsonNode node = p.getCodec().readTree(p);
String fullName = node.get("fullName").asText();
int years = node.get("years").asInt();
return new Person(fullName, years);
}
}@JsonProperty
Specifies the JSON field name used during serialization and deserialization.
public class MyClass {
@JsonProperty("customName")
private String property;
// getters and setters omitted
}@JsonIgnore
Marks a property to be ignored by both serialization and deserialization.
public class MyClass {
@JsonIgnore
private String secret;
// getters and setters omitted
}@JsonFormat
Controls formatting of dates, times, or other special types.
public class Event {
@JsonFormat(pattern = "yyyy-MM-dd")
private Date eventDate;
}
public class Payment {
@JsonFormat(shape = JsonFormat.Shape.STRING,
pattern = "yyyy-MM-dd'T'HH:mm:ss.SSSZ",
timezone = "GMT+8")
private LocalDateTime paymentTime;
}@JsonUnwrapped
Flattens a nested object’s properties into the outer JSON object. Optional prefix and suffix can be used to add a prefix or suffix to the flattened fields.
public class Employee {
private String name;
@JsonUnwrapped
private Address address;
}
public class Address {
private String city;
private String street;
}
// Serializing an Employee instance yields:
// {"name":"John Doe","city":"New York","street":"123 Main St"}@JsonAnyGetter
Exposes a Map<String, Object> as additional JSON properties, allowing dynamic key‑value pairs.
public class MyClass {
private Map<String, Object> properties = new HashMap<>();
@JsonAnyGetter
public Map<String, Object> getProperties() { return properties; }
public void addProperty(String key, Object value) { properties.put(key, value); }
}@JsonInclude
Controls inclusion of null or empty values. Example uses Include.NON_NULL to omit null fields.
@JsonInclude(JsonInclude.Include.NON_NULL)
public class Person {
private String name;
private Integer age; // may be null
private String address; // may be null
}
// Serializing a Person with null age and address produces: {"name":"John"}@JsonAlias
Defines alternative names for a property during deserialization.
public class MyClass {
@JsonAlias({"name", "fullName"})
private String property;
}@JsonIgnoreProperties
Ignores a set of properties globally for a class.
@JsonIgnoreProperties({"property1", "property2"})
public class MyClass {
private String property1;
private String property2;
private String property3;
}@JsonManagedReference and @JsonBackReference
Breaks circular references by designating the forward and back sides of a parent‑child relationship.
public class Parent {
private String name;
@JsonManagedReference
private List<Child> children;
}
public class Child {
private String name;
@JsonBackReference
private Parent parent;
}@JsonCreator
Marks a constructor or static factory method to be used for deserialization, often combined with @JsonProperty to bind JSON fields.
public class MyClass {
private String property;
@JsonCreator
public MyClass(@JsonProperty("property") String property) {
this.property = property;
}
}@JsonTypeInfo (with @JsonSubTypes)
Enables polymorphic type handling by adding type metadata to JSON.
@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = "type")
@JsonSubTypes({
@JsonSubTypes.Type(value = Dog.class, name = "dog"),
@JsonSubTypes.Type(value = Cat.class, name = "cat")
})
public abstract class Animal { /* common fields */ }
public class Dog extends Animal { /* dog specific */ }
public class Cat extends Animal { /* cat specific */ }@JsonFilter
Allows dynamic inclusion/exclusion of properties at runtime.
@JsonFilter("myFilter")
public class MyDto {
private String name;
private int age;
private String email;
}
ObjectMapper mapper = new ObjectMapper();
SimpleFilterProvider fp = new SimpleFilterProvider();
fp.addFilter("myFilter", SimpleBeanPropertyFilter.filterOutAllExcept("name", "age"));
mapper.setFilterProvider(fp);
String json = mapper.writer(fp).writeValueAsString(new MyDto()); // only name and age appear@JsonAnySetter
Collects unknown JSON fields into a map, enabling flexible deserialization of extra data.
public class MyClass {
private Map<String, Object> additionalProperties = new HashMap<>();
@JsonAnySetter
public void setAdditionalProperty(String key, Object value) {
additionalProperties.put(key, value);
}
}@JsonAppend
Appends virtual properties to the JSON output, either via static attributes or by implementing a custom VirtualBeanPropertyWriter.
@JsonAppend(attrs = {@JsonAppend.Attr(value = "age"), @JsonAppend.Attr(value = "height")},
props = {@JsonAppend.Prop(value = TestWriter.class, type = String.class, name = "version")})
public class JsonPropertyPojo {
private String sex;
private String name;
private String unknown;
}
// Example serialization adds "age", "height", and a computed "version" field.@JsonIgnoreType
Completely excludes a type from serialization and deserialization.
@JsonIgnoreType
public class AdditionalInfo {
private String info;
}
public class MyEntity {
private String name;
private AdditionalInfo additionalInfo;
}
// Serializing MyEntity yields {"name":"John"} – the AdditionalInfo field is omitted.@JsonGetter and @JsonSetter
Define custom getter and setter method names for JSON properties.
public class Person {
private String firstName;
private String lastName;
@JsonGetter("full_name")
public String getFullName() { return firstName + " " + lastName; }
@JsonSetter("first_name")
public void setFirstName(String firstName) { this.firstName = firstName; }
@JsonSetter("last_name")
public void setLastName(String lastName) { this.lastName = lastName; }
}@JsonPropertyOrder
Specifies the order of properties in the generated JSON string.
@JsonPropertyOrder({"id", "name", "email"})
public class User { /* fields */ }2. Jackson Core Modules
databind : Core serialization/deserialization engine.
annotations : Provides the annotation set used throughout Jackson.
coreutils : Utility classes for type conversion, tree model handling, and byte‑array operations.
datatype‑jsr310 : Adds support for Java 8 date‑time types (e.g., LocalDateTime).
jaxrs‑json‑provider : Implements JAX‑RS JSON message conversion for REST services.
3. Jackson Extension Points
JsonSerializer / JsonDeserializer : Custom (de)serialization logic for specific types.
StdConverter : Generic type conversion, useful for annotation processing.
JsonNodeFactory : Custom factory for creating JsonNode instances.
JsonSerializerModifier / JsonDeserializerModifier : Hook to replace or modify default (de)serializers.
ValueInstantiator : Custom object creation strategy (e.g., factory methods).
ObjectIdResolver : Maps objects to identifiers, handling circular references.
ObjectIdentityGenerator : Generates unique identifiers for objects during serialization.
By combining these annotations, modules, and extension points, developers can fully control how Java objects are represented as JSON in Spring Boot applications, enabling features such as field masking, custom naming, polymorphic handling, and dynamic property injection.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
Programmer1970
Formerly called 'Code to 35'. Add our main WeChat ID to access a wealth of shared resources (algorithms, interview prep, tech stacks: Java, Python, Go, big data). We mainly share serious development techniques, focusing on output-driven input. Occasionally we post life snippets and gossip. Our aim is to attract precise traffic and test advertising opportunities.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
