Backend Development 18 min read

Understanding Jackson vs Fastjson Serialization of Circular References and Global Exception Handling in Spring Boot

The article examines how Spring Boot handles circular reference serialization with Jackson and Fastjson, demonstrates the role of @ControllerAdvice for global exception capture, explains why Jackson may emit both 200 and 500 responses, and provides practical solutions using annotations and configuration.

Rare Earth Juejin Tech Community
Rare Earth Juejin Tech Community
Rare Earth Juejin Tech Community
Understanding Jackson vs Fastjson Serialization of Circular References and Global Exception Handling in Spring Boot

In a previous post the author compared Fastjson and Jackson for handling circular references during object serialization in Spring applications. Fastjson silently resolves the reference, while Jackson throws an exception, delegating the decision to the developer.

The article introduces @ControllerAdvice (or @RestControllerAdvice ) as the mechanism for global exception handling in Spring. By defining a class annotated with @RestControllerAdvice and methods annotated with @ExceptionHandler , any exception that propagates to the controller layer can be captured and transformed into a unified response.

@RestControllerAdvice
public class GlobalExceptionHandler {
    Logger logger = LoggerFactory.getLogger(GlobalExceptionHandler.class);

    @ExceptionHandler(value = Exception.class)
    public Result exceptionHandler(Exception e){
        logger.error(e.getMessage(), e);
        return Result.error(e.getMessage());
    }

    @ExceptionHandler(value = RuntimeException.class)
    public Result exceptionHandlerRuntimeException(Exception e){
        logger.error(e.getMessage(), e);
        return Result.error(e.getMessage());
    }
    // other custom exceptions …
}

A standard response wrapper Result and an enum ReturnCodeEnum are defined to carry status codes, success flags, data and messages.

public class Result
implements Serializable {
    private String code;
    private Boolean success;
    private T data;
    private String msg;
    // constructors, static factories, getters/setters …
}
public enum ReturnCodeEnum {
    OK("200", "success"),
    SERVER_FAILED("500", "server failed 500 !!!"),
    // other codes …
}

A simple Person class with a self‑referencing father field is used to create circular structures.

@Getter @Setter
public class Person {
    private String name;
    private Integer age;
    private Person father;
    public Person(String name, Integer age) { this.name = name; this.age = age; }
}

When Fastjson is configured with SerializerFeature.DisableCircularReferenceDetect , the serialization process throws a StackOverflowError . The global exception handler catches it and returns a JSON payload with code 500, confirming that the exception is handled correctly.

Switching to Jackson (the default in Spring Boot) produces a different log: an Infinite recursion (StackOverflowError) is logged, but the client receives a 200 response body containing partially serialized data followed by a separate 500 error payload. The author initially suspects that the return statement is executed before the exception, causing two responses.

Further investigation shows that Jackson writes to the HTTP output stream incrementally. Its internal buffer (≈8000 bytes) flushes to the client before the circular‑reference exception is thrown, so part of the successful 200 payload is already sent. When the exception finally occurs, the @ControllerAdvice handler sends a second 500 payload, resulting in two concatenated JSON messages.

Fastjson, on the other hand, buffers the entire serialization result in an expandable buffer. The exception occurs before any data is flushed, so only the 500 error response is sent.

The article also discusses scenarios where @ControllerAdvice does not work (e.g., exceptions swallowed in service layers or AOP advice) and emphasizes that proper configuration makes it reliable even for exceptions thrown after the controller method returns.

To solve the circular‑reference problem with Jackson, the author recommends using annotations such as @JsonBackReference , @JsonManagedReference , @JsonIgnore , or @JsonIdentityInfo . An example using @JsonIdentityInfo is shown, which produces a correct JSON without infinite recursion.

@JsonIdentityInfo(generator=ObjectIdGenerators.IntSequenceGenerator.class, property="name")
private Person father;

In conclusion, the article explains why Jackson may emit both 200 and 500 responses when a circular reference triggers an exception, how Fastjson avoids this issue, and provides practical ways to prevent or mitigate circular‑reference serialization problems in Spring MVC applications.

backendSerializationSpring BootfastjsonJacksoncircular referenceGlobal Exception Handling
Rare Earth Juejin Tech Community
Written by

Rare Earth Juejin Tech Community

Juejin, a tech community that helps developers grow.

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.