السبت، 19 يوليو 2025

Mastering @JsonFormat in Jackson: A Complete Guide with Examples

If you're working with Java and JSON, the Jackson library is likely part of your tech stack. One of the most powerful yet underused annotations it provides is @JsonFormat.

In this ultimate guide, we’ll break down what @JsonFormat does, when to use it, and how to handle advanced scenarios with fully working examples. This post is optimized for SEO to help developers find quick and accurate answers.


✅ What is @JsonFormat in Jackson?

@JsonFormat is a Jackson annotation that helps control how Java fields are serialized (Java to JSON) or deserialized (JSON to Java). This is especially useful for dates, enums, and number formats.

Import Statement:


import com.fasterxml.jackson.annotation.JsonFormat;

Dependencies

Make sure you include the correct Jackson modules for java.time:


 <dependency>
   <groupId>com.fasterxml.jackson.datatype</groupId>
   <artifactId>jackson-datatype-jsr310</artifactId>
   <version>2.15.3</version>
 </dependency>
 

And register it:


 ObjectMapper mapper = new ObjectMapper();
 mapper.registerModule(new JavaTimeModule());
 


📅 1. Formatting Dates and Times

Basic Example with Date

import com.fasterxml.jackson.annotation.JsonFormat;
import com.fasterxml.jackson.databind.ObjectMapper;

import java.util.Date;

public class Event {
    @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd HH:mm:ss", timezone = "Asia/Kolkata")
    private Date eventDate;

    public Event(Date eventDate) {
        this.eventDate = eventDate;
    }

    public Date getEventDate() {
        return eventDate;
    }

    public static void main(String[] args) throws Exception {
        Event event = new Event(new Date());
        ObjectMapper mapper = new ObjectMapper();
        String json = mapper.writeValueAsString(event);
        System.out.println(json);
    }
}

JSON Output:

{
  "eventDate": "2025-07-19 15:00:00"
}


Working with LocalDateTime


import com.fasterxml.jackson.annotation.JsonFormat;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;

import java.time.LocalDateTime;

public class Schedule {
    @JsonFormat(pattern = "yyyy-MM-dd'T'HH:mm:ss")
    private LocalDateTime start;

    public Schedule(LocalDateTime start) {
        this.start = start;
    }

    public static void main(String[] args) throws Exception {
        Schedule schedule = new Schedule(LocalDateTime.now());
        ObjectMapper mapper = new ObjectMapper();
        mapper.registerModule(new JavaTimeModule());
        System.out.println(mapper.writeValueAsString(schedule));
    }
}

Output:

{
  "start": "2025-07-19T12:30:00"
}


2. Customizing Enum Serialization

Enum as Full Object



import com.fasterxml.jackson.annotation.JsonFormat;
import com.fasterxml.jackson.databind.ObjectMapper;

public class User {
    @JsonFormat(shape = JsonFormat.Shape.OBJECT)
    private Status status;

    public User(Status status) {
        this.status = status;
    }

    public static void main(String[] args) throws Exception {
        ObjectMapper mapper = new ObjectMapper();
        User user = new User(Status.ACTIVE);
        System.out.println(mapper.writeValueAsString(user));
    }

    @JsonFormat(shape = JsonFormat.Shape.OBJECT)
    enum Status {
        ACTIVE("Active"), INACTIVE("Inactive");

        private final String label;

        Status(String label) {
            this.label = label;
        }

        public String getLabel() {
            return label;
        }
    }
}

Sample Output:


{"status":{"label":"Active"}}


🔢 3. Formatting Numbers



import com.fasterxml.jackson.annotation.JsonFormat;
import com.fasterxml.jackson.databind.ObjectMapper;

import java.math.BigDecimal;

public class Invoice {
    @JsonFormat(shape = JsonFormat.Shape.STRING)
    private BigDecimal amount;

    public Invoice(BigDecimal amount) {
        this.amount = amount;
    }

    public static void main(String[] args) throws Exception {
        Invoice invoice = new Invoice(new BigDecimal("12345.67"));
        ObjectMapper mapper = new ObjectMapper();
        System.out.println(mapper.writeValueAsString(invoice));
    }
}

Sample output:

{"amount":"12345.67"}

📦 4. Shape Control: Arrays vs Objects



import com.fasterxml.jackson.annotation.JsonFormat;
import com.fasterxml.jackson.databind.ObjectMapper;

public class BoxExample {
    public static void main(String[] args) throws Exception {
        ObjectMapper mapper = new ObjectMapper();
        Box box = new Box(new Point(10, 20), new Point(30, 40));
        System.out.println(mapper.writeValueAsString(box));
    }

    static class Point {
        public int x, y;
        public Point(int x, int y) { this.x = x; this.y = y; }
    }

    static class Box {
        @JsonFormat(shape = JsonFormat.Shape.ARRAY)
        public Point topLeft;

        @JsonFormat(shape = JsonFormat.Shape.ARRAY)
        public Point bottomRight;

        public Box(Point topLeft, Point bottomRight) {
            this.topLeft = topLeft;
            this.bottomRight = bottomRight;
        }
    }
}

Sample output

{"topLeft":[10,20],"bottomRight":[30,40]}

🧪 5. Case-Insensitive Enum Deserialization


import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.MapperFeature;

public class CaseInsensitiveEnumExample {
    enum Role {
        ADMIN, USER, GUEST
    }

    public static void main(String[] args) throws Exception {
        String json = "\"AdMiN\"";

        ObjectMapper mapper = new ObjectMapper();
        mapper.enable(MapperFeature.ACCEPT_CASE_INSENSITIVE_ENUMS);

        Role role = mapper.readValue(json, Role.class);
        System.out.println(role); // Output: ADMIN
    }
}

Sample output

ADMIN


🛑 6. Common Pitfalls

  • Pattern must match the input exactly during deserialization.
  • Using the wrong timezone may cause incorrect results.
  • Not all types support all Shape options (e.g., BigDecimal cannot be OBJECT).

🧰 7 Tips

Prefer LocalDate, LocalDateTime, ZonedDateTime from java.time over java.util.Date.

You can also use global config via ObjectMapper:

ObjectMapper mapper = new ObjectMapper();
mapper.setDateFormat(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"));



ليست هناك تعليقات:

إرسال تعليق

Please do not add any spam links in the comments section.