JsonProperty
Java
Programming
JSON Data
Software Development

When is the @JsonProperty property used and what is it used for?

Master System Design with Codemia

Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.

@JsonProperty is a Jackson annotation that controls how Java fields map to JSON property names during serialization and deserialization. You use it when the default name-based mapping is insufficient: to rename fields, to bind constructor parameters for immutable objects, to restrict access direction, or to mark a field as required. Without it, Jackson relies on field names and JavaBean conventions, which often do not match external API contracts.

Renaming Fields Between Java and JSON

The most common use case is bridging naming conventions. Java uses camelCase; many REST APIs use snake_case. @JsonProperty lets you keep Java conventions in your code while matching the external contract exactly.

java
1import com.fasterxml.jackson.annotation.JsonProperty;
2
3public class UserDto {
4    @JsonProperty("first_name")
5    private String firstName;
6
7    @JsonProperty("last_name")
8    private String lastName;
9
10    @JsonProperty("created_at")
11    private Instant createdAt;
12
13    // getters and setters omitted for brevity
14}

Serialization output:

json
1{
2  "first_name": "Ada",
3  "last_name": "Lovelace",
4  "created_at": "2026-01-15T10:30:00Z"
5}

Without the annotation, Jackson would emit firstName, lastName, and createdAt, which might break client integrations that expect snake_case.

Global naming strategy vs per-field annotation

If every field in your API follows snake_case, configuring the ObjectMapper globally is cleaner than annotating every field:

java
ObjectMapper mapper = new ObjectMapper();
mapper.setPropertyNamingStrategy(PropertyNamingStrategies.SNAKE_CASE);

Use @JsonProperty when only specific fields deviate from the default, or when you need a name that no naming strategy can generate automatically (like mapping type to __type or class to _class).

Constructor Binding for Immutable Objects

When a class has final fields and no default constructor, Jackson needs explicit guidance on how to bind JSON keys to constructor parameters. @JsonProperty on constructor arguments provides that mapping.

java
1import com.fasterxml.jackson.annotation.JsonCreator;
2import com.fasterxml.jackson.annotation.JsonProperty;
3
4public final class OrderEvent {
5    private final String orderId;
6    private final String status;
7    private final long timestampEpochMs;
8
9    @JsonCreator
10    public OrderEvent(
11        @JsonProperty("order_id") String orderId,
12        @JsonProperty("status") String status,
13        @JsonProperty("timestamp_epoch_ms") long timestampEpochMs
14    ) {
15        this.orderId = orderId;
16        this.status = status;
17        this.timestampEpochMs = timestampEpochMs;
18    }
19
20    public String getOrderId() { return orderId; }
21    public String getStatus() { return status; }
22    public long getTimestampEpochMs() { return timestampEpochMs; }
23}

Without @JsonProperty on the constructor parameters, Jackson cannot reliably match JSON fields to arguments, especially when compiled without the -parameters flag. The deserialization either fails or produces incorrect bindings.

This pattern is especially important with Java records, where all fields are final by design:

java
1import com.fasterxml.jackson.annotation.JsonProperty;
2
3public record ApiError(
4    @JsonProperty("error_code") int errorCode,
5    @JsonProperty("error_message") String errorMessage
6) {}

Controlling Serialization Direction With Access

@JsonProperty supports an access attribute that controls whether a field participates in reading (deserialization), writing (serialization), or both.

java
1import com.fasterxml.jackson.annotation.JsonProperty;
2
3public class CreateUserRequest {
4    @JsonProperty("username")
5    private String username;
6
7    @JsonProperty(value = "password", access = JsonProperty.Access.WRITE_ONLY)
8    private String password;
9
10    @JsonProperty(value = "id", access = JsonProperty.Access.READ_ONLY)
11    private Long id;
12
13    // getters and setters
14}
Access modeSerialization (Java to JSON)Deserialization (JSON to Java)
READ_WRITE (default)IncludedAccepted
WRITE_ONLYExcludedAccepted
READ_ONLYIncludedIgnored

WRITE_ONLY is common for password fields in request DTOs. The field is accepted from incoming JSON but never appears in outgoing responses. READ_ONLY is useful for server-generated values like IDs, timestamps, or computed fields that should be serialized out but should not be overwritten by client input.

Marking Fields as Required

The required attribute on @JsonProperty signals that the field must be present during deserialization. When combined with @JsonCreator, Jackson throws a MismatchedInputException if the required field is missing from the JSON input.

java
1@JsonCreator
2public Product(
3    @JsonProperty(value = "sku", required = true) String sku,
4    @JsonProperty(value = "name", required = true) String name,
5    @JsonProperty(value = "description") String description
6) {
7    this.sku = sku;
8    this.name = name;
9    this.description = description;
10}

This is a lightweight validation mechanism. For more complex validation rules (length constraints, pattern matching), combine with Bean Validation annotations like @NotNull or @Size.

Annotation Placement Options

You can place @JsonProperty on fields, getters, setters, or constructor parameters. The best location depends on your class design:

PlacementBest forExample
FieldSimple DTOs with direct field access@JsonProperty("user_id") private Long userId;
Constructor parameterImmutable objects, records@JsonCreator public Foo(@JsonProperty("bar") String bar)
GetterMethod-based serialization logic@JsonProperty("full_name") public String getFullName()
SetterCustom deserialization with validation@JsonProperty("age") public void setAge(int age)

Consistency matters. If your team annotates fields in some DTOs and getters in others, the mapping becomes harder to audit. Pick one style per project and document it.

Combining With Other Jackson Annotations

@JsonProperty often works alongside other annotations:

java
1public class EventPayload {
2    @JsonProperty("event_type")
3    private String eventType;
4
5    @JsonProperty("payload")
6    @JsonRawValue
7    private String rawPayload;  // serialized as raw JSON, not a quoted string
8
9    @JsonProperty("metadata")
10    @JsonInclude(JsonInclude.Include.NON_NULL)
11    private Map<String, String> metadata;  // omitted from output when null
12
13    @JsonIgnore
14    private String internalTraceId;  // never serialized or deserialized
15}

@JsonIgnore excludes a field entirely. @JsonInclude controls when a field appears based on its value. @JsonRawValue writes a string as raw JSON rather than escaping it. These annotations complement @JsonProperty rather than replacing it.

When You Do Not Need @JsonProperty

You do not need the annotation when:

  • Field names already match the JSON contract exactly.
  • A global naming strategy handles the transformation (e.g., SNAKE_CASE).
  • The class has a default constructor and standard getters/setters that Jackson can discover through reflection.

Adding @JsonProperty("username") to a field already named username adds noise without adding clarity. Reserve the annotation for cases where it changes behavior.

Common Pitfalls

Annotating every field even when default mapping already works. This clutters the code and makes real overrides harder to spot. Only annotate when the external name differs from the Java name or when you need constructor binding.

Forgetting constructor parameter annotations on immutable types. Serialization (Java to JSON) often works fine because Jackson reads fields directly. Deserialization (JSON to Java) fails because Jackson cannot map JSON keys to unnamed constructor parameters.

Confusing WRITE_ONLY with security. The access attribute prevents serialization of a field, but it does not replace proper secret handling, hashing, or encryption. A password field marked WRITE_ONLY still exists in memory and can appear in logs or debug output.

Mixing field and method annotations for the same property. Jackson can handle it, but the behavior depends on visibility settings and can produce surprising results. Annotate in one place per property.

Using @JsonProperty when @JsonNaming would be simpler. If every field in a class needs snake_case mapping, applying a class-level @JsonNaming(PropertyNamingStrategies.SnakeCaseStrategy.class) is more maintainable than annotating every field individually.

Summary

  • @JsonProperty customizes the mapping between a Java property and a JSON field name. Use it when names differ across conventions.
  • On constructor parameters, it enables deserialization of immutable objects and records.
  • The access attribute controls serialization direction: WRITE_ONLY for input-only fields, READ_ONLY for output-only fields.
  • The required attribute enforces presence during deserialization.
  • Prefer a global naming strategy when the entire API follows a single convention. Use @JsonProperty for individual overrides.
  • Do not annotate fields whose names already match the JSON contract. Unnecessary annotations add noise.

Course illustration
Course illustration

All Rights Reserved.