General data-binding functionality for Jackson: works on core streaming API
—
Jackson Databind provides extensive annotation support for controlling serialization and deserialization behavior. These annotations allow fine-grained control over property naming, visibility, formatting, validation, and custom processing without modifying the underlying Java classes.
Controls serialization aspects of properties and classes.
@Target({ElementType.ANNOTATION_TYPE, ElementType.METHOD, ElementType.FIELD, ElementType.TYPE, ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
@JacksonAnnotation
public @interface JsonSerialize {
// Custom serializer
Class<? extends JsonSerializer> using() default JsonSerializer.None.class;
Class<? extends JsonSerializer> contentUsing() default JsonSerializer.None.class;
Class<? extends JsonSerializer> keyUsing() default JsonSerializer.None.class;
Class<? extends JsonSerializer> nullsUsing() default JsonSerializer.None.class;
// Type specification
Class<?> as() default Void.class;
Class<?> keyAs() default Void.class;
Class<?> contentAs() default Void.class;
// Inclusion control
JsonSerialize.Inclusion include() default JsonSerialize.Inclusion.DEFAULT_INCLUSION;
// Static/dynamic typing
JsonSerialize.Typing typing() default JsonSerialize.Typing.DEFAULT_TYPING;
// Converter
Class<? extends Converter> converter() default Converter.None.class;
Class<? extends Converter> contentConverter() default Converter.None.class;
// Nested enums
public enum Inclusion {
ALWAYS,
NON_NULL,
NON_ABSENT,
NON_EMPTY,
NON_DEFAULT,
CUSTOM,
USE_DEFAULTS;
}
public enum Typing {
DYNAMIC,
STATIC,
DEFAULT_TYPING;
}
}Controls deserialization aspects of properties and classes.
@Target({ElementType.ANNOTATION_TYPE, ElementType.METHOD, ElementType.FIELD, ElementType.TYPE, ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
@JacksonAnnotation
public @interface JsonDeserialize {
// Custom deserializer
Class<? extends JsonDeserializer> using() default JsonDeserializer.None.class;
Class<? extends JsonDeserializer> contentUsing() default JsonDeserializer.None.class;
Class<? extends KeyDeserializer> keyUsing() default KeyDeserializer.None.class;
// Builder support
Class<?> builder() default Void.class;
// Type specification
Class<?> as() default Void.class;
Class<?> keyAs() default Void.class;
Class<?> contentAs() default Void.class;
// Converter
Class<? extends Converter> converter() default Converter.None.class;
Class<? extends Converter> contentConverter() default Converter.None.class;
}Controls property-level serialization and deserialization.
@Target({ElementType.ANNOTATION_TYPE, ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
@JacksonAnnotation
public @interface JsonProperty {
// Property name (default is auto-detected)
String value() default USE_DEFAULT_NAME;
// Namespace (for XML, etc.)
String namespace() default "";
// Required property
boolean required() default false;
// Property index (for order)
int index() default INDEX_UNKNOWN;
// Default value as string
String defaultValue() default "";
// Access control
JsonProperty.Access access() default JsonProperty.Access.AUTO;
// Constants
String USE_DEFAULT_NAME = "";
int INDEX_UNKNOWN = -1;
// Access enum
public enum Access {
AUTO,
READ_ONLY,
WRITE_ONLY,
READ_WRITE;
}
}Control property visibility and ignoring.
@Target({ElementType.ANNOTATION_TYPE, ElementType.METHOD, ElementType.CONSTRUCTOR, ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
@JacksonAnnotation
public @interface JsonIgnore {
// Whether to ignore (default true)
boolean value() default true;
}
@Target({ElementType.ANNOTATION_TYPE, ElementType.TYPE, ElementType.METHOD, ElementType.CONSTRUCTOR, ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
@JacksonAnnotation
public @interface JsonIgnoreProperties {
// Property names to ignore
String[] value() default {};
// Whether to ignore unknown properties
boolean ignoreUnknown() default false;
// Whether to allow getters for ignored setters
boolean allowGetters() default false;
// Whether to allow setters for ignored getters
boolean allowSetters() default false;
}Controls when properties are included in serialization.
@Target({ElementType.ANNOTATION_TYPE, ElementType.METHOD, ElementType.FIELD, ElementType.TYPE, ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
@JacksonAnnotation
public @interface JsonInclude {
// Inclusion strategy
JsonInclude.Include value() default JsonInclude.Include.ALWAYS;
// Content inclusion (for collections/maps)
JsonInclude.Include content() default JsonInclude.Include.ALWAYS;
// Custom value filter
Class<?> valueFilter() default Void.class;
Class<?> contentFilter() default Void.class;
// Include enum
public enum Include {
ALWAYS,
NON_NULL,
NON_ABSENT,
NON_EMPTY,
NON_DEFAULT,
CUSTOM,
USE_DEFAULTS;
}
}Controls deserialization settings for properties.
@Target({ElementType.ANNOTATION_TYPE, ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
@JacksonAnnotation
public @interface JsonSetter {
// Property name
String value() default "";
// Null handling
JsonSetter.Nulls nulls() default JsonSetter.Nulls.DEFAULT;
JsonSetter.Nulls contentNulls() default JsonSetter.Nulls.DEFAULT;
// Null handling enum
public enum Nulls {
DEFAULT,
SET,
SKIP,
FAIL,
AS_EMPTY;
}
}@Target({ElementType.ANNOTATION_TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@JacksonAnnotation
public @interface JsonGetter {
// Property name (default derived from method name)
String value() default "";
}
@Target({ElementType.ANNOTATION_TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@JacksonAnnotation
public @interface JsonSetter {
// Property name (default derived from method name)
String value() default "";
// Null handling
JsonSetter.Nulls nulls() default JsonSetter.Nulls.DEFAULT;
JsonSetter.Nulls contentNulls() default JsonSetter.Nulls.DEFAULT;
}Controls formatting of values during serialization/deserialization.
@Target({ElementType.ANNOTATION_TYPE, ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@JacksonAnnotation
public @interface JsonFormat {
// Format pattern (dates, numbers, etc.)
String pattern() default "";
// Shape of serialized value
JsonFormat.Shape shape() default JsonFormat.Shape.ANY;
// Locale specification
String locale() default "##default";
// Timezone specification
String timezone() default "##default";
// Leniency for parsing
JsonFormat.OptBoolean lenient() default JsonFormat.OptBoolean.DEFAULT;
// Features for formatting
JsonFormat.Feature[] with() default {};
JsonFormat.Feature[] without() default {};
// Shape enum
public enum Shape {
ANY,
NATURAL,
SCALAR,
ARRAY,
OBJECT,
STRING,
NUMBER,
NUMBER_FLOAT,
NUMBER_INT,
BOOLEAN,
BINARY;
}
// Optional boolean enum
public enum OptBoolean {
TRUE, FALSE, DEFAULT;
}
// Format features
public enum Feature {
ACCEPT_SINGLE_VALUE_AS_ARRAY,
ACCEPT_CASE_INSENSITIVE_PROPERTIES,
ACCEPT_CASE_INSENSITIVE_VALUES,
WRITE_DATE_TIMESTAMPS_AS_NANOSECONDS,
WRITE_DATES_WITH_ZONE_ID,
WRITE_SINGLE_ELEM_ARRAYS_UNWRAPPED,
ADJUST_DATES_TO_CONTEXT_TIME_ZONE;
}
}@Target({ElementType.ANNOTATION_TYPE, ElementType.TYPE, ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
@JacksonAnnotation
public @interface JsonTypeInfo {
// How type information is included
JsonTypeInfo.Id use() default JsonTypeInfo.Id.CLASS;
// Where type information is included
JsonTypeInfo.As include() default JsonTypeInfo.As.PROPERTY;
// Property name for type information
String property() default "";
// Default implementation class
Class<?> defaultImpl() default JsonTypeInfo.None.class;
// Visibility of type property
boolean visible() default false;
// Type identification strategies
public enum Id {
NONE,
CLASS,
MINIMAL_CLASS,
NAME,
DEDUCTION,
CUSTOM;
}
// Type inclusion strategies
public enum As {
PROPERTY,
WRAPPER_OBJECT,
WRAPPER_ARRAY,
EXTERNAL_PROPERTY,
EXISTING_PROPERTY;
}
// Marker class
abstract class None { }
}
@Target({ElementType.ANNOTATION_TYPE, ElementType.TYPE, ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
@JacksonAnnotation
public @interface JsonSubTypes {
// Subtype specifications
JsonSubTypes.Type[] value();
// Type specification
@Target({})
@Retention(RetentionPolicy.RUNTIME)
public @interface Type {
// Subtype class
Class<?> value();
// Type name/id
String name() default "";
// Alternative names
String[] names() default {};
}
}
@Target({ElementType.ANNOTATION_TYPE, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@JacksonAnnotation
public @interface JsonTypeName {
// Type name for this class
String value() default "";
}Marks constructors and factory methods for deserialization.
@Target({ElementType.ANNOTATION_TYPE, ElementType.METHOD, ElementType.CONSTRUCTOR})
@Retention(RetentionPolicy.RUNTIME)
@JacksonAnnotation
public @interface JsonCreator {
// Creation mode
JsonCreator.Mode mode() default JsonCreator.Mode.DEFAULT;
// Creation modes
public enum Mode {
DEFAULT,
DELEGATING,
PROPERTIES,
DISABLED;
}
}Marks a method as providing the serialized value for an object.
@Target({ElementType.ANNOTATION_TYPE, ElementType.METHOD, ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
@JacksonAnnotation
public @interface JsonValue {
// Whether annotation is active
boolean value() default true;
}Controls unwrapping of nested objects.
@Target({ElementType.ANNOTATION_TYPE, ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
@JacksonAnnotation
public @interface JsonUnwrapped {
// Whether to unwrap
boolean enabled() default true;
// Prefix for unwrapped properties
String prefix() default "";
// Suffix for unwrapped properties
String suffix() default "";
}Handle dynamic properties that aren't known at compile time.
@Target({ElementType.ANNOTATION_TYPE, ElementType.METHOD, ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
@JacksonAnnotation
public @interface JsonAnySetter {
// Whether annotation is enabled
boolean enabled() default true;
}
@Target({ElementType.ANNOTATION_TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@JacksonAnnotation
public @interface JsonAnyGetter {
// Whether annotation is enabled
boolean enabled() default true;
}Handle bidirectional relationships to prevent infinite recursion.
@Target({ElementType.ANNOTATION_TYPE, ElementType.FIELD, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@JacksonAnnotation
public @interface JsonManagedReference {
// Reference name (for matching with back reference)
String value() default "defaultReference";
}
@Target({ElementType.ANNOTATION_TYPE, ElementType.FIELD, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@JacksonAnnotation
public @interface JsonBackReference {
// Reference name (must match managed reference)
String value() default "defaultReference";
}Handles object identity to avoid duplication and cycles.
@Target({ElementType.ANNOTATION_TYPE, ElementType.TYPE, ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
@JacksonAnnotation
public @interface JsonIdentityInfo {
// ID generator class
Class<? extends ObjectIdGenerator> generator();
// Property name for ID
String property() default "@id";
// Whether to resolve references automatically
boolean resolver() default false;
// Custom resolver class
Class<? extends ObjectIdResolver> resolver() default ObjectIdResolver.class;
// Identity scope
Class<?> scope() default Object.class;
}Configures builder classes for deserialization.
@Target({ElementType.ANNOTATION_TYPE, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@JacksonAnnotation
public @interface JsonPOJOBuilder {
// Name of build method
String buildMethodName() default "build";
// Prefix for builder methods
String withPrefix() default "with";
}Controls auto-detection of properties, getters, setters, etc.
@Target({ElementType.ANNOTATION_TYPE, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@JacksonAnnotation
public @interface JsonAutoDetect {
// Visibility settings
JsonAutoDetect.Visibility getterVisibility() default JsonAutoDetect.Visibility.DEFAULT;
JsonAutoDetect.Visibility isGetterVisibility() default JsonAutoDetect.Visibility.DEFAULT;
JsonAutoDetect.Visibility setterVisibility() default JsonAutoDetect.Visibility.DEFAULT;
JsonAutoDetect.Visibility creatorVisibility() default JsonAutoDetect.Visibility.DEFAULT;
JsonAutoDetect.Visibility fieldVisibility() default JsonAutoDetect.Visibility.DEFAULT;
// Visibility enum
public enum Visibility {
ANY,
NON_PRIVATE,
PROTECTED_AND_PUBLIC,
PUBLIC_ONLY,
NONE,
DEFAULT;
}
}Specifies property naming strategy.
@Target({ElementType.ANNOTATION_TYPE, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@JacksonAnnotation
public @interface JsonNaming {
// Naming strategy class
Class<? extends PropertyNamingStrategy> value();
}Controls the order of properties in serialization.
@Target({ElementType.ANNOTATION_TYPE, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@JacksonAnnotation
public @interface JsonPropertyOrder {
// Property names in desired order
String[] value() default {};
// Whether to order alphabetically
boolean alphabetic() default false;
}Specifies enum naming strategy.
@Target({ElementType.ANNOTATION_TYPE, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@JacksonAnnotation
public @interface EnumNaming {
// Enum naming strategy class
Class<? extends EnumNamingStrategy> value();
}Associates a filter ID with a class.
@Target({ElementType.ANNOTATION_TYPE, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@JacksonAnnotation
public @interface JsonFilter {
// Filter ID
String value();
}Controls which properties are included in different views.
@Target({ElementType.ANNOTATION_TYPE, ElementType.METHOD, ElementType.FIELD, ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
@JacksonAnnotation
public @interface JsonView {
// View classes
Class<?>[] value();
}Adds virtual properties during serialization.
@Target({ElementType.ANNOTATION_TYPE, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@JacksonAnnotation
public @interface JsonAppend {
// Attribute properties
JsonAppend.Attr[] attrs() default {};
// Regular properties
JsonAppend.Prop[] props() default {};
// Prepend vs append
boolean prepend() default false;
// Attribute property
@Target({})
@Retention(RetentionPolicy.RUNTIME)
public @interface Attr {
String value();
boolean required() default false;
Class<? extends JsonSerializer> serializer() default JsonSerializer.None.class;
}
// Virtual property
@Target({})
@Retention(RetentionPolicy.RUNTIME)
public @interface Prop {
Class<?> value();
String name() default "";
String namespace() default "";
boolean required() default false;
int index() default -1;
}
}Specifies root element name for root wrapping.
@Target({ElementType.ANNOTATION_TYPE, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@JacksonAnnotation
public @interface JsonRootName {
// Root element name
String value() default "";
// Namespace
String namespace() default "";
}Provides description for schema generation.
@Target({ElementType.ANNOTATION_TYPE, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@JacksonAnnotation
public @interface JsonClassDescription {
// Description text
String value();
}
@Target({ElementType.ANNOTATION_TYPE, ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
@JacksonAnnotation
public @interface JsonPropertyDescription {
// Description text
String value();
}import com.fasterxml.jackson.annotation.*;
public class User {
// Custom property name
@JsonProperty("user_id")
private Long id;
// Required property
@JsonProperty(required = true)
private String username;
// Read-only property
@JsonProperty(access = JsonProperty.Access.READ_ONLY)
private Date createdAt;
// Ignored property
@JsonIgnore
private String password;
// Conditional inclusion
@JsonInclude(JsonInclude.Include.NON_NULL)
private String email;
// Custom format
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private Date lastLogin;
// Constructor for deserialization
@JsonCreator
public User(@JsonProperty("user_id") Long id,
@JsonProperty("username") String username) {
this.id = id;
this.username = username;
}
// Custom getter name
@JsonGetter("full_name")
public String getDisplayName() {
return firstName + " " + lastName;
}
// Custom setter with null handling
@JsonSetter(value = "email", nulls = JsonSetter.Nulls.SKIP)
public void setEmailAddress(String email) {
this.email = email != null ? email.toLowerCase() : null;
}
}// Custom serializers and property ordering
@JsonPropertyOrder({"id", "name", "status", "createdAt"})
@JsonInclude(JsonInclude.Include.NON_EMPTY)
public class Product {
private Long id;
private String name;
// Custom serialization
@JsonSerialize(using = MoneySerializer.class)
private BigDecimal price;
// Custom deserialization
@JsonDeserialize(using = StatusDeserializer.class)
private ProductStatus status;
// Converter usage
@JsonSerialize(converter = CategoryToStringConverter.class)
@JsonDeserialize(converter = StringToCategoryConverter.class)
private Category category;
// Null handling
@JsonSetter(nulls = JsonSetter.Nulls.AS_EMPTY)
private List<String> tags = new ArrayList<>();
// Builder support
@JsonPOJOBuilder(withPrefix = "set", buildMethodName = "create")
public static class Builder {
private Product product = new Product();
public Builder setId(Long id) {
product.id = id;
return this;
}
public Builder setName(String name) {
product.name = name;
return this;
}
public Product create() {
return product;
}
}
}
// Custom serializer
public class MoneySerializer extends JsonSerializer<BigDecimal> {
@Override
public void serialize(BigDecimal value, JsonGenerator gen, SerializerProvider serializers) throws IOException {
gen.writeString("$" + value.setScale(2, RoundingMode.HALF_UP));
}
}// Base class with type information
@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = "type")
@JsonSubTypes({
@JsonSubTypes.Type(value = Circle.class, name = "circle"),
@JsonSubTypes.Type(value = Rectangle.class, name = "rectangle"),
@JsonSubTypes.Type(value = Triangle.class, name = "triangle")
})
public abstract class Shape {
@JsonProperty
protected String color;
// Common properties and methods
}
@JsonTypeName("circle")
public class Circle extends Shape {
@JsonProperty
private double radius;
@JsonCreator
public Circle(@JsonProperty("radius") double radius) {
this.radius = radius;
}
}
@JsonTypeName("rectangle")
public class Rectangle extends Shape {
@JsonProperty
private double width;
@JsonProperty
private double height;
@JsonCreator
public Rectangle(@JsonProperty("width") double width, @JsonProperty("height") double height) {
this.width = width;
this.height = height;
}
}
// Usage
Shape shape = new Circle(5.0);
String json = mapper.writeValueAsString(shape);
// Result: {"type":"circle","color":null,"radius":5.0}
Shape parsed = mapper.readValue(json, Shape.class); // Returns Circle instance// Using object identity to handle circular references
@JsonIdentityInfo(generator = ObjectIdGenerators.PropertyGenerator.class, property = "id")
public class Department {
private Long id;
private String name;
@JsonManagedReference("department-employees")
private List<Employee> employees = new ArrayList<>();
}
@JsonIdentityInfo(generator = ObjectIdGenerators.PropertyGenerator.class, property = "id")
public class Employee {
private Long id;
private String name;
@JsonBackReference("department-employees")
private Department department;
@JsonManagedReference("employee-tasks")
private List<Task> tasks = new ArrayList<>();
}
public class Task {
private Long id;
private String description;
@JsonBackReference("employee-tasks")
private Employee assignee;
}
// This prevents infinite recursion and duplicate serialization
Department dept = new Department();
dept.setId(1L);
Employee emp = new Employee();
emp.setId(100L);
emp.setDepartment(dept);
dept.getEmployees().add(emp);
String json = mapper.writeValueAsString(dept);
// Uses object IDs to represent relationships efficientlypublic class FlexibleEntity {
private String name;
private String type;
// Store unknown properties
private Map<String, Object> additionalProperties = new HashMap<>();
@JsonAnyGetter
public Map<String, Object> getAdditionalProperties() {
return additionalProperties;
}
@JsonAnySetter
public void setAdditionalProperty(String key, Object value) {
additionalProperties.put(key, value);
}
// Getters/setters for known properties
}
// This class can handle JSON with unknown properties:
String json = """
{
"name": "Sample",
"type": "test",
"customField1": "value1",
"customField2": 123,
"nested": {"key": "value"}
}
""";
FlexibleEntity entity = mapper.readValue(json, FlexibleEntity.class);
// entity.getAdditionalProperties() contains the unknown propertiespublic class Address {
private String street;
private String city;
private String zipCode;
// getters/setters
}
public class Person {
private String name;
private int age;
// Unwrap address fields directly into person JSON
@JsonUnwrapped
private Address address;
// Unwrap with prefix
@JsonUnwrapped(prefix = "work_")
private Address workAddress;
}
// Serialization result:
// {
// "name": "John",
// "age": 30,
// "street": "123 Main St", // from address
// "city": "Springfield",
// "zipCode": "12345",
// "work_street": "456 Office Blvd", // from workAddress with prefix
// "work_city": "Business City",
// "work_zipCode": "67890"
// }// Define view classes
public class Views {
public static class Public {}
public static class Internal extends Public {}
public static class Admin extends Internal {}
}
public class UserRecord {
@JsonView(Views.Public.class)
private String name;
@JsonView(Views.Public.class)
private String email;
@JsonView(Views.Internal.class)
private String department;
@JsonView(Views.Admin.class)
private BigDecimal salary;
@JsonView(Views.Admin.class)
private String ssn;
}
// Usage with different views
ObjectWriter publicWriter = mapper.writerWithView(Views.Public.class);
ObjectWriter internalWriter = mapper.writerWithView(Views.Internal.class);
ObjectWriter adminWriter = mapper.writerWithView(Views.Admin.class);
UserRecord user = new UserRecord("John", "john@example.com", "Engineering", new BigDecimal("75000"), "123-45-6789");
String publicJson = publicWriter.writeValueAsString(user);
// Only name and email
String internalJson = internalWriter.writeValueAsString(user);
// name, email, and department
String adminJson = adminWriter.writeValueAsString(user);
// All fields// Create custom annotation
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@JsonSerialize(using = SensitiveDataSerializer.class)
public @interface SensitiveData {
// Masking strategy
MaskStrategy strategy() default MaskStrategy.ASTERISK;
enum MaskStrategy {
ASTERISK, HASH, REDACTED
}
}
// Custom serializer that reads the annotation
public class SensitiveDataSerializer extends JsonSerializer<String> {
@Override
public void serialize(String value, JsonGenerator gen, SerializerProvider serializers) throws IOException {
// Get the property being serialized
BeanProperty property = (BeanProperty) serializers.getAttribute("CURRENT_PROPERTY");
if (property != null) {
SensitiveData annotation = property.getAnnotation(SensitiveData.class);
if (annotation != null) {
String masked = maskValue(value, annotation.strategy());
gen.writeString(masked);
return;
}
}
gen.writeString(value);
}
private String maskValue(String value, SensitiveData.MaskStrategy strategy) {
if (value == null || value.length() < 3) {
return "***";
}
return switch (strategy) {
case ASTERISK -> value.substring(0, 2) + "*".repeat(value.length() - 2);
case HASH -> value.substring(0, 2) + "#".repeat(value.length() - 2);
case REDACTED -> "[REDACTED]";
};
}
}
// Usage
public class Account {
private String accountNumber;
@SensitiveData(strategy = SensitiveData.MaskStrategy.ASTERISK)
private String creditCardNumber;
@SensitiveData(strategy = SensitiveData.MaskStrategy.REDACTED)
private String ssn;
}// Base Jackson annotation interface
public interface JacksonAnnotation {
// Marker interface for all Jackson annotations
}
// Converter interface for @JsonSerialize/@JsonDeserialize converter elements
public interface Converter<IN, OUT> {
OUT convert(IN value);
JavaType getInputType(TypeFactory typeFactory);
JavaType getOutputType(TypeFactory typeFactory);
// Marker class for no converter
public static abstract class None implements Converter<Object, Object> { }
}
// Standard converter implementations
public abstract class StdConverter<IN, OUT> implements Converter<IN, OUT> {
public abstract OUT convert(IN value);
public JavaType getInputType(TypeFactory typeFactory);
public JavaType getOutputType(TypeFactory typeFactory);
}
// Object ID generators for @JsonIdentityInfo
public abstract class ObjectIdGenerator<T> implements Serializable {
public abstract Class<?> getScope();
public abstract boolean canUseFor(ObjectIdGenerator<?> gen);
public abstract ObjectIdGenerator<T> forScope(Class<?> scope);
public abstract ObjectIdGenerator<T> newForSerialization(Object context);
public abstract IdKey key(Object key);
public abstract T generateId(Object forPojo);
}
// Standard object ID generators
public class ObjectIdGenerators {
public static class IntSequenceGenerator extends ObjectIdGenerator<Integer> { }
public static class PropertyGenerator extends ObjectIdGenerator<Object> { }
public static class StringIdGenerator extends ObjectIdGenerator<String> { }
public static class UUIDGenerator extends ObjectIdGenerator<UUID> { }
}
// Property naming strategies for @JsonNaming
public abstract class PropertyNamingStrategy implements Serializable {
public String nameForField(MapperConfig<?> config, AnnotatedField field, String defaultName);
public String nameForGetterMethod(MapperConfig<?> config, AnnotatedMethod method, String defaultName);
public String nameForSetterMethod(MapperConfig<?> config, AnnotatedMethod method, String defaultName);
public String nameForConstructorParameter(MapperConfig<?> config, AnnotatedParameter ctorParam, String defaultName);
}
// Standard naming strategies
public abstract class PropertyNamingStrategies {
public static final PropertyNamingStrategy LOWER_CAMEL_CASE;
public static final PropertyNamingStrategy UPPER_CAMEL_CASE;
public static final PropertyNamingStrategy SNAKE_CASE;
public static final PropertyNamingStrategy UPPER_SNAKE_CASE;
public static final PropertyNamingStrategy LOWER_CASE;
public static final PropertyNamingStrategy KEBAB_CASE;
public static final PropertyNamingStrategy LOWER_DOT_CASE;
}
// Enum naming strategies for @EnumNaming
public interface EnumNamingStrategy {
String convertEnumToExternalName(String enumName);
}
public class EnumNamingStrategies {
public static final EnumNamingStrategy LOWER_CAMEL_CASE;
public static final EnumNamingStrategy UPPER_CAMEL_CASE;
public static final EnumNamingStrategy SNAKE_CASE;
public static final EnumNamingStrategy UPPER_SNAKE_CASE;
public static final EnumNamingStrategy LOWER_CASE;
public static final EnumNamingStrategy KEBAB_CASE;
}Install with Tessl CLI
npx tessl i tessl/maven-com-fasterxml-jackson-core--jackson-databind