Core annotations used for value types, used by Jackson data binding package.
—
Annotations that modify how objects are structured in JSON, including unwrapping nested objects and controlling value representation.
Unwrap nested object properties into the parent object.
/**
* Unwrap nested object properties into parent object
* @param enabled Whether to enable unwrapping (default: true)
* @param prefix Prefix to add to unwrapped property names
* @param suffix Suffix to add to unwrapped property names
*/
@JsonUnwrapped(boolean enabled = true,
String prefix = "",
String suffix = "")
public @interface JsonUnwrapped;Usage Examples:
public class Person {
private String firstName;
private String lastName;
@JsonUnwrapped
private Address address;
@JsonUnwrapped(prefix = "work_")
private Address workAddress;
}
public class Address {
private String street;
private String city;
private String zipCode;
}
// Without @JsonUnwrapped:
// {"firstName": "John", "lastName": "Doe", "address": {"street": "123 Main St", "city": "NYC", "zipCode": "10001"}}
// With @JsonUnwrapped:
// {"firstName": "John", "lastName": "Doe", "street": "123 Main St", "city": "NYC", "zipCode": "10001", "work_street": "456 Office Blvd", "work_city": "NYC", "work_zipCode": "10002"}Use a single method or field value as the JSON representation of the entire object.
/**
* Use single value as JSON representation of entire object
* @param value Whether to use this as the JSON value (default: true)
*/
@JsonValue(boolean value = true)
public @interface JsonValue;Usage Examples:
public enum Status {
ACTIVE("active"),
INACTIVE("inactive"),
PENDING("pending");
private final String code;
Status(String code) {
this.code = code;
}
@JsonValue
public String getCode() {
return code;
}
}
// Serializes as: "active" instead of {"code": "active"}
public class Money {
private final BigDecimal amount;
private final String currency;
public Money(BigDecimal amount, String currency) {
this.amount = amount;
this.currency = currency;
}
@JsonValue
public String toString() {
return amount + " " + currency;
}
}
// Serializes as: "100.50 USD" instead of {"amount": 100.50, "currency": "USD"}Serialize string value as raw JSON without quotes or escaping.
/**
* Serialize string value as raw JSON without quotes/escaping
* @param value Whether to use raw value serialization (default: true)
*/
@JsonRawValue(boolean value = true)
public @interface JsonRawValue;Usage Examples:
public class JsonContainer {
private String name;
@JsonRawValue
private String jsonData;
@JsonRawValue
private String configJson;
}
// If jsonData contains: {"settings": {"theme": "dark"}, "count": 42}
// Result: {"name": "container", "jsonData": {"settings": {"theme": "dark"}, "count": 42}, "configJson": {...}}
// Instead of: {"name": "container", "jsonData": "{\"settings\": {\"theme\": \"dark\"}, \"count\": 42}"}Use property value as Map key during serialization.
/**
* Use property value as Map key during serialization
* @param value Whether to use this property as key (default: true)
*/
@JsonKey(boolean value = true)
public @interface JsonKey;Usage Examples:
public class KeyedItem {
@JsonKey
private String identifier;
private String name;
private String description;
}
// When used in a collection context, the identifier becomes the map key:
// List<KeyedItem> items -> Map<String, KeyedItem> structure
// [{"identifier": "item1", "name": "First"}, {"identifier": "item2", "name": "Second"}]
// becomes: {"item1": {"name": "First"}, "item2": {"name": "Second"}}Handle dynamic properties with Map-based storage.
/**
* Mark method returning Map to serialize as additional properties
* @param enabled Whether to enable any-getter behavior (default: true)
*/
@JsonAnyGetter(boolean enabled = true)
public @interface JsonAnyGetter;
/**
* Mark method/field as fallback for unrecognized properties during deserialization
* @param enabled Whether to enable any-setter behavior (default: true)
*/
@JsonAnySetter(boolean enabled = true)
public @interface JsonAnySetter;Usage Examples:
public class FlexibleObject {
private String name;
private String type;
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);
}
}
// JSON: {"name": "test", "type": "sample", "customField": "value", "count": 42}
// additionalProperties will contain: {"customField": "value", "count": 42}
// Serialization includes all additional properties at the top levelpublic class Employee {
private String employeeId;
@JsonUnwrapped
private PersonalInfo personal;
@JsonUnwrapped(prefix = "contact_")
private ContactInfo contact;
@JsonUnwrapped(prefix = "work_", suffix = "_info")
private WorkInfo work;
}
public class PersonalInfo {
private String firstName;
private String lastName;
private LocalDate birthDate;
}
public class ContactInfo {
private String email;
private String phone;
}
public class WorkInfo {
private String department;
private String position;
}
// Result: {
// "employeeId": "E123",
// "firstName": "John", "lastName": "Doe", "birthDate": "1990-01-15",
// "contact_email": "john@company.com", "contact_phone": "555-0123",
// "work_department_info": "Engineering", "work_position_info": "Senior Developer"
// }public class ConfigurableResponse {
private String status;
private String message;
@JsonRawValue
@JsonInclude(JsonInclude.Include.NON_NULL)
private String rawData; // Only included if not null, and as raw JSON
@JsonRawValue
private String getFormattedConfig() {
// Method can return formatted JSON string
return configService.getJsonConfig();
}
}public class Coordinate {
private final double x;
private final double y;
@JsonCreator
public Coordinate(@JsonProperty("x") double x, @JsonProperty("y") double y) {
this.x = x;
this.y = y;
}
@JsonValue
public String toWktString() {
return String.format("POINT(%f %f)", x, y);
}
// Custom deserializer would be needed to parse the WKT string back
}
// Serializes as: "POINT(10.500000 20.300000)"public class ApiResource {
private String id;
private String type;
// Store metadata separately
@JsonIgnore
private Map<String, Object> metadata = new HashMap<>();
// Store dynamic fields separately
@JsonIgnore
private Map<String, Object> dynamicFields = new HashMap<>();
@JsonAnyGetter
public Map<String, Object> getDynamicFields() {
Map<String, Object> all = new HashMap<>(metadata);
all.putAll(dynamicFields);
return all;
}
@JsonAnySetter
public void setDynamicField(String key, Object value) {
if (key.startsWith("meta_")) {
metadata.put(key.substring(5), value);
} else {
dynamicFields.put(key, value);
}
}
}public class ApiResponse<T> {
private String status;
private String message;
@JsonUnwrapped
private T data; // Unwrap the actual data into the response
private Map<String, Object> meta;
}
// Usage:
ApiResponse<User> response = new ApiResponse<>();
response.setData(new User("john", "john@email.com"));
// Result: {"status": "success", "message": "OK", "username": "john", "email": "john@email.com", "meta": {...}}Install with Tessl CLI
npx tessl i tessl/maven-com-fasterxml-jackson-core--jackson-annotations