Core annotations used for value types, used by Jackson data binding package.
—
Control how objects are created during deserialization, including constructor/factory method selection and dependency injection.
Mark constructor or factory method for object creation during deserialization.
/**
* Mark constructor or factory method for deserialization
* @param mode Creator binding mode controlling how parameters are bound
*/
@JsonCreator(JsonCreator.Mode mode = JsonCreator.Mode.DEFAULT)
public @interface JsonCreator {
enum Mode {
/** Default mode - auto-detect binding based on parameter annotations */
DEFAULT,
/** Delegating mode - single unnanotated parameter receives full JSON */
DELEGATING,
/** Properties mode - parameters bound to JSON properties by name */
PROPERTIES,
/** Disabled - do not use this creator */
DISABLED
}
}Usage Examples:
public class Person {
private final String name;
private final int age;
private final String email;
// Properties-based creator (default mode)
@JsonCreator
public Person(@JsonProperty("name") String name,
@JsonProperty("age") int age,
@JsonProperty("email") String email) {
this.name = name;
this.age = age;
this.email = email;
}
}
// Delegating creator example
public class Wrapper {
private final Map<String, Object> data;
@JsonCreator(mode = JsonCreator.Mode.DELEGATING)
public Wrapper(Map<String, Object> data) {
this.data = new HashMap<>(data);
}
}
// Factory method creator
public class Product {
private final String name;
private final BigDecimal price;
private Product(String name, BigDecimal price) {
this.name = name;
this.price = price;
}
@JsonCreator
public static Product create(@JsonProperty("productName") String name,
@JsonProperty("price") String priceStr) {
return new Product(name, new BigDecimal(priceStr));
}
}Inject values from ObjectReader/ObjectMapper context during deserialization.
/**
* Inject values from deserialization context
* @param value Injection identifier (default: use property/parameter name)
* @param useInput Whether to use input value if available in JSON
*/
@JacksonInject(String value = "",
OptBoolean useInput = OptBoolean.DEFAULT)
public @interface JacksonInject;Usage Examples:
public class AuditableEntity {
private String data;
@JacksonInject
private String createdBy; // Injected from context
@JacksonInject("timestamp")
private LocalDateTime createdAt; // Injected with specific key
@JacksonInject(useInput = OptBoolean.FALSE)
private String tenantId; // Always injected, never from JSON
@JsonCreator
public AuditableEntity(@JsonProperty("data") String data,
@JacksonInject("userId") String userId) {
this.data = data;
this.createdBy = userId;
}
}
// Usage with ObjectMapper:
ObjectMapper mapper = new ObjectMapper();
InjectableValues inject = new InjectableValues.Std()
.addValue("userId", "john.doe")
.addValue("timestamp", LocalDateTime.now())
.addValue("tenantId", "tenant-123");
AuditableEntity entity = mapper.reader(inject)
.readValue(json, AuditableEntity.class);Enable merging of property values during deserialization instead of replacement.
/**
* Enable property value merging during deserialization
* @param value Whether to enable merging (default: true)
*/
@JsonMerge(OptBoolean value = OptBoolean.TRUE)
public @interface JsonMerge;Usage Examples:
public class Configuration {
@JsonMerge
private Map<String, String> settings = new HashMap<>();
@JsonMerge
private List<String> features = new ArrayList<>();
@JsonMerge
private DatabaseConfig database = new DatabaseConfig();
// Getters and setters
}
public class DatabaseConfig {
private String host = "localhost";
private int port = 5432;
private String database = "myapp";
// Getters and setters
}
// Original object: {"settings": {"theme": "dark"}, "features": ["auth"], "database": {"host": "localhost", "port": 5432}}
// JSON update: {"settings": {"language": "en"}, "features": ["logging"], "database": {"port": 3306}}
// Result: {"settings": {"theme": "dark", "language": "en"}, "features": ["auth", "logging"], "database": {"host": "localhost", "port": 3306}}public class User {
private String username;
private String email;
private String fullName;
// Primary creator for full JSON objects
@JsonCreator
public User(@JsonProperty("username") String username,
@JsonProperty("email") String email,
@JsonProperty("fullName") String fullName) {
this.username = username;
this.email = email;
this.fullName = fullName;
}
// Alternative creator for minimal objects
@JsonCreator(mode = JsonCreator.Mode.PROPERTIES)
public static User minimal(@JsonProperty("username") String username) {
return new User(username, null, null);
}
}public class ComplexObject {
private final String name;
private final List<String> tags;
private final Map<String, Object> metadata;
private ComplexObject(Builder builder) {
this.name = builder.name;
this.tags = builder.tags;
this.metadata = builder.metadata;
}
@JsonCreator
public static ComplexObject create(@JsonProperty("name") String name,
@JsonProperty("tags") List<String> tags,
@JsonProperty("metadata") Map<String, Object> metadata) {
return new Builder()
.name(name)
.tags(tags)
.metadata(metadata)
.build();
}
public static class Builder {
private String name;
private List<String> tags = new ArrayList<>();
private Map<String, Object> metadata = new HashMap<>();
public Builder name(String name) {
this.name = name;
return this;
}
public Builder tags(List<String> tags) {
this.tags = tags != null ? new ArrayList<>(tags) : new ArrayList<>();
return this;
}
public Builder metadata(Map<String, Object> metadata) {
this.metadata = metadata != null ? new HashMap<>(metadata) : new HashMap<>();
return this;
}
public ComplexObject build() {
return new ComplexObject(this);
}
}
}public class SecureDocument {
private String content;
private String owner;
private LocalDateTime createdAt;
private String ipAddress;
@JsonCreator
public SecureDocument(@JsonProperty("content") String content,
@JacksonInject("currentUser") String owner,
@JacksonInject("requestTime") LocalDateTime createdAt,
@JacksonInject("clientIp") String ipAddress) {
this.content = content;
this.owner = owner;
this.createdAt = createdAt;
this.ipAddress = ipAddress;
}
}
// Context setup:
InjectableValues context = new InjectableValues.Std()
.addValue("currentUser", getCurrentUser())
.addValue("requestTime", LocalDateTime.now())
.addValue("clientIp", getClientIpAddress());public class ValidatedUser {
private final String email;
private final int age;
@JsonCreator
public ValidatedUser(@JsonProperty("email") String email,
@JsonProperty("age") int age) {
if (email == null || !email.contains("@")) {
throw new IllegalArgumentException("Invalid email format");
}
if (age < 0 || age > 150) {
throw new IllegalArgumentException("Invalid age: " + age);
}
this.email = email;
this.age = age;
}
}Configuration class for programmatic injection control.
/**
* Value class for JacksonInject configuration
*/
public static class JacksonInject.Value implements JacksonAnnotationValue<JacksonInject> {
public static final JacksonInject.Value EMPTY;
public static JacksonInject.Value construct(Object id, Boolean useInput);
public static JacksonInject.Value forId(Object id);
public Object getId();
public Boolean getUseInput();
public JacksonInject.Value withId(Object id);
public JacksonInject.Value withUseInput(Boolean useInput);
}Install with Tessl CLI
npx tessl i tessl/maven-com-fasterxml-jackson-core--jackson-annotations