5/24/2026

Efficient JSON serialization with Jackson and Java

 



📌 Introduction



JSON serialization is a fundamental part of modern Java applications — converting Java objects into JSON and back. Jackson is the most widely used library for this purpose in the Java ecosystem, offering powerful, flexible, and performant serialization mechanisms.

In this article, we'll explore:

  • Basic Jackson setup
  • Custom serialization & deserialization
  • A real-world one-to-many example: CarDTOCarAttributeDTO

📚 References:


⚙️ 1. Maven Dependency

Add Jackson to your pom.xml:

<dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-databind</artifactId>
    <version>2.17.0</version>
</dependency>

🏗️ 2. Define the DTOs

CarAttributeDTO — The "Many" Side

public class CarAttributeDTO {

    private String attributeName;   // e.g. "color", "engine", "transmission"
    private String attributeValue;  // e.g. "red", "V8", "automatic"

    // Constructors
    public CarAttributeDTO() {}

    public CarAttributeDTO(String attributeName, String attributeValue) {
        this.attributeName = attributeName;
        this.attributeValue = attributeValue;
    }

    // Getters & Setters
    public String getAttributeName() { return attributeName; }
    public void setAttributeName(String attributeName) { 
        this.attributeName = attributeName; 
    }

    public String getAttributeValue() { return attributeValue; }
    public void setAttributeValue(String attributeValue) { 
        this.attributeValue = attributeValue; 
    }
}

CarDTO — The "One" Side (with One-to-Many relationship)

import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.annotation.JsonInclude;
import java.util.List;

@JsonInclude(JsonInclude.Include.NON_NULL) // Excludes null fields from JSON
public class CarDTO {

    @JsonProperty("car_id")
    private Long id;

    @JsonProperty("brand")
    private String brand;           // e.g. "BMW"

    @JsonProperty("model")
    private String model;           // e.g. "M3"

    @JsonProperty("year")
    private int year;               // e.g. 2024

    @JsonProperty("attributes")
    private List<CarAttributeDTO> attributes; // One-to-Many

    // Constructors
    public CarDTO() {}

    public CarDTO(Long id, String brand, String model, 
                  int year, List<CarAttributeDTO> attributes) {
        this.id = id;
        this.brand = brand;
        this.model = model;
        this.year = year;
        this.attributes = attributes;
    }

    // Getters & Setters
    public Long getId() { return id; }
    public void setId(Long id) { this.id = id; }

    public String getBrand() { return brand; }
    public void setBrand(String brand) { this.brand = brand; }

    public String getModel() { return model; }
    public void setModel(String model) { this.model = model; }

    public int getYear() { return year; }
    public void setYear(int year) { this.year = year; }

    public List<CarAttributeDTO> getAttributes() { return attributes; }
    public void setAttributes(List<CarAttributeDTO> attributes) { 
        this.attributes = attributes; 
    }
}

🔄 3. Basic Serialization (Object → JSON)

import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import java.util.List;

public class JacksonSerializationExample {

    public static void main(String[] args) throws Exception {

        // Build the CarDTO with attributes (One-to-Many)
        List<CarAttributeDTO> attributes = List.of(
            new CarAttributeDTO("color",        "Frozen Black"),
            new CarAttributeDTO("engine",       "3.0L TwinPower Turbo"),
            new CarAttributeDTO("transmission", "8-Speed Automatic"),
            new CarAttributeDTO("horsepower",   "503 HP")
        );

        CarDTO car = new CarDTO(1L, "BMW", "M3 Competition", 2024, attributes);

        // Configure ObjectMapper
        ObjectMapper mapper = new ObjectMapper();
        mapper.enable(SerializationFeature.INDENT_OUTPUT); // Pretty print

        // Serialize to JSON String
        String json = mapper.writeValueAsString(car);
        System.out.println(json);
    }
}

📤 Output JSON:

{
  "car_id": 1,
  "brand": "BMW",
  "model": "M3 Competition",
  "year": 2024,
  "attributes": [
    {
      "attributeName": "color",
      "attributeValue": "Frozen Black"
    },
    {
      "attributeName": "engine",
      "attributeValue": "3.0L TwinPower Turbo"
    },
    {
      "attributeName": "transmission",
      "attributeValue": "8-Speed Automatic"
    },
    {
      "attributeName": "horsepower",
      "attributeValue": "503 HP"
    }
  ]
}

🔁 4. Deserialization (JSON → Object)

String jsonInput = """
    {
        "car_id": 2,
        "brand": "BMW",
        "model": "X5",
        "year": 2023,
        "attributes": [
            { "attributeName": "color",    "attributeValue": "Alpine White" },
            { "attributeName": "engine",   "attributeValue": "4.4L V8"      }
        ]
    }
    """;

ObjectMapper mapper = new ObjectMapper();
CarDTO car = mapper.readValue(jsonInput, CarDTO.class);

System.out.println("Brand : " + car.getBrand());
System.out.println("Model : " + car.getModel());
System.out.println("Attrs : " + car.getAttributes().size());

🎨 5. Custom Serializer

Sometimes you need full control over the JSON output. Use a custom serializer to reshape the attributes list into a flat key-value map:

import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.SerializerProvider;
import com.fasterxml.jackson.databind.ser.std.StdSerializer;
import java.io.IOException;

public class CarDTOSerializer extends StdSerializer<CarDTO> {

    public CarDTOSerializer() {
        super(CarDTO.class);
    }

    @Override
    public void serialize(CarDTO car, 
                          JsonGenerator gen, 
                          SerializerProvider provider) throws IOException {

        gen.writeStartObject();

        gen.writeNumberField("car_id", car.getId());
        gen.writeStringField("brand",  car.getBrand());
        gen.writeStringField("model",  car.getModel());
        gen.writeNumberField("year",   car.getYear());

        // 🔑 Flatten attributes into a key-value object
        gen.writeObjectFieldStart("attributes");
        if (car.getAttributes() != null) {
            for (CarAttributeDTO attr : car.getAttributes()) {
                gen.writeStringField(
                    attr.getAttributeName(), 
                    attr.getAttributeValue()
                );
            }
        }
        gen.writeEndObject();

        gen.writeEndObject();
    }
}

Register the Custom Serializer:

ObjectMapper mapper = new ObjectMapper();
mapper.enable(SerializationFeature.INDENT_OUTPUT);

SimpleModule module = new SimpleModule();
module.addSerializer(CarDTO.class, new CarDTOSerializer());
mapper.registerModule(module);

String json = mapper.writeValueAsString(car);
System.out.println(json);

📤 Output with Custom Serializer (flattened attributes):

{
  "car_id": 1,
  "brand": "BMW",
  "model": "M3 Competition",
  "year": 2024,
  "attributes": {
    "color": "Frozen Black",
    "engine": "3.0L TwinPower Turbo",
    "transmission": "8-Speed Automatic",
    "horsepower": "503 HP"
  }
}

🛡️ 6. Useful Jackson Annotations Summary

AnnotationPurpose
@JsonProperty("name")Rename a field in JSON
@JsonInclude(NON_NULL)Exclude null fields from output
@JsonIgnoreCompletely exclude a field from serialization
@JsonAliasAccept multiple names during deserialization
@JsonSerializeAttach a custom serializer to a field/class
@JsonDeserializeAttach a custom deserializer to a field/class
@JsonFormatFormat dates, numbers, etc.

✅ 7. Best Practices

🔹 Reuse ObjectMapper — it is thread-safe and expensive to create
🔹 Use @JsonInclude(NON_NULL) to keep JSON payloads clean
🔹 Prefer DTOs over Entities — never serialize JPA entities directly
🔹 Use custom serializers when you need full control over output format
🔹 Validate deserialized objects using Bean Validation (@Valid)


🎯 Conclusion

Jackson provides a rich, flexible API to handle JSON serialization in Java. By combining annotations, custom serializers, and the ObjectMapper, you can cleanly model complex relationships like Car → Attributes (one-to-many) and produce well-structured, efficient JSON payloads.


📚 Further Reading:

Niciun comentariu:

Efficient JSON serialization with Jackson and Java

  📌 Introduction JSON serialization is a fundamental part of modern Java applications — converting Java objects into JSON and back. Jackson...