AnnotationPurpose
@JsonProperty("name")Rename a field in JSON
@JsonIgnoreExclude a field from serialisation and deserialisation
@JsonIgnoreProperties({"f1","f2"})Ignore named fields on the class
@JsonIgnoreProperties(ignoreUnknown=true)Silently ignore unknown JSON fields
@JsonInclude(Include.NON_NULL)Omit null fields from output
@JsonInclude(Include.NON_EMPTY)Omit null, empty collections, empty strings
@JsonFormat(pattern="yyyy-MM-dd")Date/time format for a field
@JsonCreatorMark a constructor or factory method for deserialisation
@JsonValueSerialise the object as the return value of this method
@JsonAlias({"alt1","alt2"})Accept alternative field names during deserialisation
@JsonUnwrappedInline nested object's fields into the parent JSON object
@JsonAnyGetter / @JsonAnySetterSerialise/deserialise dynamic/unknown fields into a Map
@JsonTypeInfo / @JsonSubTypesPolymorphic type handling
import com.fasterxml.jackson.annotation.*; import java.time.LocalDate; import java.util.Map; import java.util.HashMap; @JsonIgnoreProperties(ignoreUnknown = true) // tolerate extra JSON fields @JsonInclude(JsonInclude.Include.NON_NULL) // omit null fields globally public class User { @JsonProperty("user_id") // output field name: "user_id" private Long id; @JsonProperty("full_name") private String name; @JsonIgnore // never serialised or deserialised private String passwordHash; @JsonFormat(pattern = "yyyy-MM-dd") private LocalDate createdAt; @JsonAlias({"emailAddress", "email_address"}) // accept any of these on input private String email; // Dynamic extra fields private Map<String, Object> extra = new HashMap<>(); @JsonAnyGetter public Map<String, Object> getExtra() { return extra; } @JsonAnySetter public void addExtra(String key, Object value) { extra.put(key, value); } // Required no-arg constructor for Jackson (or use @JsonCreator on constructor) public User() {} }

Use @JsonCreator to tell Jackson which constructor or static factory method to use when deserialising. Pair it with @JsonProperty to map JSON fields to constructor parameters.

import com.fasterxml.jackson.annotation.*; public final class Money { private final long cents; private final String currency; @JsonCreator public Money( @JsonProperty("cents") long cents, @JsonProperty("currency") String currency) { this.cents = cents; this.currency = currency; } // Static factory variant @JsonCreator(mode = JsonCreator.Mode.DELEGATING) public static Money fromString(String value) { String[] parts = value.split(":"); return new Money(Long.parseLong(parts[0]), parts[1]); } @JsonValue public String toValue() { return cents + ":" + currency; } // serialised as "1234:USD" public long getCents() { return cents; } public String getCurrency() { return currency; } }

If you cannot add Jackson annotations to a class (e.g., a library type), create a mixin class/interface that mirrors the target's API with annotations, then register it.

import com.fasterxml.jackson.annotation.*; import com.fasterxml.jackson.databind.ObjectMapper; // Third-party class you cannot touch class ThirdPartyUser { public Long id; public String name; public String internalSecret; // should not be exposed public String firstName; public String lastName; } // Mixin — abstract class mirroring ThirdPartyUser @JsonIgnoreProperties(ignoreUnknown = true) abstract class ThirdPartyUserMixin { @JsonIgnore abstract String getInternalSecret(); // exclude this field @JsonProperty("full_name") abstract String getName(); // rename name → full_name // Inline firstName/lastName instead of as nested object @JsonUnwrapped // (if they were in a nested Name object) abstract String getFirstName(); } // Register the mixin ObjectMapper mapper = new ObjectMapper(); mapper.addMixIn(ThirdPartyUser.class, ThirdPartyUserMixin.class); ThirdPartyUser user = new ThirdPartyUser(); user.id = 1L; user.name = "Alice"; user.internalSecret = "secret-token"; String json = mapper.writeValueAsString(user); // {"id":1,"full_name":"Alice"} — internalSecret excluded Mixins are ideal for serialising JDK types (like java.security.Principal), third-party domain objects, or any class where you want to keep Jackson annotations out of your domain model.
import com.fasterxml.jackson.annotation.*; @JsonTypeInfo( use = JsonTypeInfo.Id.NAME, // embed a "type" field include = JsonTypeInfo.As.PROPERTY, property = "type") // the discriminator field name @JsonSubTypes({ @JsonSubTypes.Type(value = Dog.class, name = "dog"), @JsonSubTypes.Type(value = Cat.class, name = "cat") }) abstract class Animal { public String name; } class Dog extends Animal { public String breed; } class Cat extends Animal { public boolean indoor; } // Serialise ObjectMapper mapper = new ObjectMapper(); Animal dog = new Dog(); ((Dog)dog).name = "Rex"; ((Dog)dog).breed = "Labrador"; String json = mapper.writeValueAsString(dog); // {"type":"dog","name":"Rex","breed":"Labrador"} // Deserialise — Jackson reads "type" field and creates the right subtype Animal restored = mapper.readValue(json, Animal.class); System.out.println(restored.getClass().getSimpleName()); // Dog

Jackson's SerializationConfig and JavaType system lets you inspect how a class will be serialised without actually serialising it.

import com.fasterxml.jackson.databind.*; import com.fasterxml.jackson.databind.introspect.*; ObjectMapper mapper = new ObjectMapper(); // Get the serialisation bean description for a class JavaType type = mapper.getTypeFactory().constructType(User.class); BeanDescription desc = mapper.getSerializationConfig() .introspect(type); // List all serialisable properties for (BeanPropertyDefinition prop : desc.findProperties()) { System.out.printf("Field: %-20s JSON name: %s%n", prop.getInternalName(), prop.getName()); } // Check if a field would be ignored AnnotationIntrospector ai = mapper.getSerializationConfig().getAnnotationIntrospector();