Backend Development 6 min read

Master Polymorphic Deserialization in Spring Boot 3 with Jackson

This tutorial shows how to use Jackson's polymorphic deserialization in Spring Boot 3 to handle variable JSON request bodies by defining a common Order interface, concrete implementations, and a REST controller that routes calculations based on the order type, eliminating redundant endpoints.

Spring Full-Stack Practical Cases
Spring Full-Stack Practical Cases
Spring Full-Stack Practical Cases
Master Polymorphic Deserialization in Spring Boot 3 with Jackson

Introduction

When the JSON body format is unknown, defining a separate API for each possible structure leads to redundant endpoints. Polymorphic deserialization with Jackson provides a concise and extensible solution.

Case Study

Assume an online store needs to handle three order types: regular, discount, and promo, each with different fields and calculation logic.

1. Interface Definition

<code>@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, property = "orderType", visible = true)
@JsonSubTypes({
    @JsonSubTypes.Type(value = RegularOrder.class, name = "regular"),
    @JsonSubTypes.Type(value = DiscountOrder.class, name = "discount"),
    @JsonSubTypes.Type(value = PromoOrder.class, name = "promo")
})
public interface Order {
}</code>

2. POJO Implementations

<code>public class DiscountOrder implements Order {
    private double price;
    private int quantity;
    private double discountRate;
}
public class PromoOrder implements Order {
    private double price;
    private int quantity;
    private String promoCode;
}
public class RegularOrder implements Order {
    private double price;
    private int quantity;
}</code>

3. Controller

<code>@RestController
@RequestMapping("/orders")
public class OrderController {
    private final OrderService orderService;
    public OrderController(OrderService orderService) {
        this.orderService = orderService;
    }
    @PostMapping("/calculate")
    public ResponseEntity<Double> calculateTotal(@RequestBody Order order) {
        double total = 0;
        switch (order) {
            case RegularOrder r -> total = orderService.calculateRegularTotal(r);
            case DiscountOrder d -> total = orderService.calculateDiscountTotal(d);
            case PromoOrder p -> total = orderService.calculatePromoTotal(p);
            default -> logger.error("Unknown order type: {}", order);
        }
        return ResponseEntity.ok(total);
    }
}</code>

4. Service

<code>@Service
public class OrderService {
    public double calculateRegularTotal(RegularOrder order) {
        return order.getPrice() * order.getQuantity();
    }
    public double calculateDiscountTotal(DiscountOrder order) {
        return order.getPrice() * order.getQuantity() * (1 - order.getDiscountRate());
    }
    public double calculatePromoTotal(PromoOrder order) {
        return order.getPrice() * order.getQuantity() * 0.75;
    }
}</code>

5. Alternative: Dynamic Field Types

By annotating a field with @JsonTypeInfo and @JsonSubTypes, the field can hold different Java types based on a "type" property in the JSON.

<code>public class Order {
    @JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.EXTERNAL_PROPERTY, property = "type")
    @JsonSubTypes({
        @JsonSubTypes.Type(value = String.class, name = "string"),
        @JsonSubTypes.Type(value = Long.class, name = "long"),
        @JsonSubTypes.Type(value = Integer.class, name = "int")
    })
    protected Object value;
}</code>

When the request contains

"type":"long"

, the

value

field is deserialized as a

Long

, etc.

backendJavaSpring BootREST APIJacksonPolymorphic Deserialization
Spring Full-Stack Practical Cases
Written by

Spring Full-Stack Practical Cases

Full-stack Java development with Vue 2/3 front-end suite; hands-on examples and source code analysis for Spring, Spring Boot 2/3, and Spring Cloud.

0 followers
Reader feedback

How this landed with the community

login Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.