eBook – Guide Spring Cloud – NPI EA (cat=Spring Cloud)
announcement - icon

Let's get started with a Microservice Architecture with Spring Cloud:

>> Join Pro and download the eBook

eBook – Mockito – NPI EA (tag = Mockito)
announcement - icon

Mocking is an essential part of unit testing, and the Mockito library makes it easy to write clean and intuitive unit tests for your Java code.

Get started with mocking and improve your application tests using our Mockito guide:

Download the eBook

eBook – Java Concurrency – NPI EA (cat=Java Concurrency)
announcement - icon

Handling concurrency in an application can be a tricky process with many potential pitfalls. A solid grasp of the fundamentals will go a long way to help minimize these issues.

Get started with understanding multi-threaded applications with our Java Concurrency guide:

>> Download the eBook

eBook – Reactive – NPI EA (cat=Reactive)
announcement - icon

Spring 5 added support for reactive programming with the Spring WebFlux module, which has been improved upon ever since. Get started with the Reactor project basics and reactive programming in Spring Boot:

>> Join Pro and download the eBook

eBook – Java Streams – NPI EA (cat=Java Streams)
announcement - icon

Since its introduction in Java 8, the Stream API has become a staple of Java development. The basic operations like iterating, filtering, mapping sequences of elements are deceptively simple to use.

But these can also be overused and fall into some common pitfalls.

To get a better understanding on how Streams work and how to combine them with other language features, check out our guide to Java Streams:

>> Join Pro and download the eBook

eBook – Jackson – NPI EA (cat=Jackson)
announcement - icon

Do JSON right with Jackson

Download the E-book

eBook – HTTP Client – NPI EA (cat=Http Client-Side)
announcement - icon

Get the most out of the Apache HTTP Client

Download the E-book

eBook – Maven – NPI EA (cat = Maven)
announcement - icon

Get Started with Apache Maven:

Download the E-book

eBook – Persistence – NPI EA (cat=Persistence)
announcement - icon

Working on getting your persistence layer right with Spring?

Explore the eBook

eBook – RwS – NPI EA (cat=Spring MVC)
announcement - icon

Building a REST API with Spring?

Download the E-book

Course – LS – NPI EA (cat=Jackson)
announcement - icon

Get started with Spring and Spring Boot, through the Learn Spring course:

>> LEARN SPRING
Course – RWSB – NPI EA (cat=REST)
announcement - icon

Explore Spring Boot 3 and Spring 6 in-depth through building a full REST API with the framework:

>> The New “REST With Spring Boot”

Course – LSS – NPI EA (cat=Spring Security)
announcement - icon

Yes, Spring Security can be complex, from the more advanced functionality within the Core to the deep OAuth support in the framework.

I built the security material as two full courses - Core and OAuth, to get practical with these more complex scenarios. We explore when and how to use each feature and code through it on the backing project.

You can explore the course here:

>> Learn Spring Security

Course – LSD – NPI EA (tag=Spring Data JPA)
announcement - icon

Spring Data JPA is a great way to handle the complexity of JPA with the powerful simplicity of Spring Boot.

Get started with Spring Data JPA through the guided reference course:

>> CHECK OUT THE COURSE

Partner – Moderne – NPI EA (cat=Spring Boot)
announcement - icon

Refactor Java code safely — and automatically — with OpenRewrite.

Refactoring big codebases by hand is slow, risky, and easy to put off. That’s where OpenRewrite comes in. The open-source framework for large-scale, automated code transformations helps teams modernize safely and consistently.

Each month, the creators and maintainers of OpenRewrite at Moderne run live, hands-on training sessions — one for newcomers and one for experienced users. You’ll see how recipes work, how to apply them across projects, and how to modernize code with confidence.

Join the next session, bring your questions, and learn how to automate the kind of work that usually eats your sprint time.

Course – LJB – NPI EA (cat = Core Java)
announcement - icon

Code your way through and build up a solid, practical foundation of Java:

>> Learn Java Basics

Partner – LambdaTest – NPI EA (cat= Testing)
announcement - icon

Distributed systems often come with complex challenges such as service-to-service communication, state management, asynchronous messaging, security, and more.

Dapr (Distributed Application Runtime) provides a set of APIs and building blocks to address these challenges, abstracting away infrastructure so we can focus on business logic.

In this tutorial, we'll focus on Dapr's pub/sub API for message brokering. Using its Spring Boot integration, we'll simplify the creation of a loosely coupled, portable, and easily testable pub/sub messaging system:

>> Flexible Pub/Sub Messaging With Spring Boot and Dapr

eBook – Jackson – NPI (cat=Jackson)
announcement - icon

Jackson and JSON in Java, finally learn with a coding-first approach:

>> Download the eBook

1. Introduction

Serializing our complete data structure to JSON using an exact one-on-one representation of all the fields may not be appropriate sometimes or simply may not be what we want. Instead, we may want to create an extended or simplified view of our data. This is where custom Jackson serializers come into play.

However, implementing a custom serializer can be tedious, especially if our model objects have lots of fields, collections, or nested objects. Fortunately, the Jackson library has several provisions that can make this job a lot simpler.

In this short tutorial, we’ll take a look at custom Jackson serializers and show how to access default serializers inside a custom serializer.

2. Sample Data Model

Before we dive into the customization of Jackson, let’s have a look at our sample Folder class that we want to serialize:

public class Folder {
    private Long id;
    private String name;
    private String owner;
    private Date created;
    private Date modified;
    private Date lastAccess;
    private List<File> files = new ArrayList<>();

    // standard getters and setters
}

And the File class, which is defined as a List inside our Folder class:

public class File {
    private Long id;
    private String name;

    // standard getters and setters
}

3. Custom Serializers in Jackson

The main advantage of using custom serializers is that we do not have to modify our class structure. Plus, we can easily decouple our expected behavior from the class itself.

So, let’s imagine that we want a reduced view of our Folder class:

{
    "name": "Root Folder",
    "files": [
        {"id": 1, "name": "File 1"},
        {"id": 2, "name": "File 2"}
    ]
}

As we’ll see over the next sections, there are several ways we can achieve our desired output in Jackson.

3.1. Brute Force Approach

First, without using Jackson’s default serializers, we can create a custom serializer in which we do all the heavy lifting ourselves.

Let’s create a custom serializer for our Folder class to achieve this:

public class FolderJsonSerializer extends StdSerializer<Folder> {

    public FolderJsonSerializer() {
        super(Folder.class);
    }

    @Override
    public void serialize(Folder value, JsonGenerator gen, SerializerProvider provider)
      throws IOException {
        gen.writeStartObject();
        gen.writeStringField("name", value.getName());

        gen.writeArrayFieldStart("files");
        for (File file : value.getFiles()) {
            gen.writeStartObject();
            gen.writeNumberField("id", file.getId());
            gen.writeStringField("name", file.getName());
            gen.writeEndObject();
        }
        gen.writeEndArray();

        gen.writeEndObject();
    }
}

Thus, we can serialize our Folder class to a reduced view containing only the fields that we want.

3.2. Using Internal ObjectMapper

Although custom serializers provide us the flexibility of altering every property in detail, we can make our job easier by reusing Jackson’s default serializers.

One way of using the default serializers is to access the internal ObjectMapper class:

@Override
public void serialize(Folder value, JsonGenerator gen, SerializerProvider provider) throws IOException {
    gen.writeStartObject();
    gen.writeStringField("name", value.getName());

    ObjectMapper mapper = (ObjectMapper) gen.getCodec();
    gen.writeFieldName("files");
    String stringValue = mapper.writeValueAsString(value.getFiles());
    gen.writeRawValue(stringValue);

    gen.writeEndObject();
}

So, Jackson simply handles the heavy lifting by serializing the List of File objects, and then our output will be the same.

3.3. Using SerializerProvider

Another way of calling the default serializers is to use the SerializerProvider. Therefore, we delegate the process to the default serializer of the type File.

Now, let’s simplify our code a little bit with the help of SerializerProvider:

@Override
public void serialize(Folder value, JsonGenerator gen, SerializerProvider provider) throws IOException {
    gen.writeStartObject();
    gen.writeStringField("name", value.getName());

    provider.defaultSerializeField("files", value.getFiles(), gen);

    gen.writeEndObject();
}

And, just as before, we get the same output.

4. A Possible Recursion Problem

Depending on the use case, we may need to extend our serialized data by including more details for Folder. This might be for a legacy system or an external application to be integrated that we do not have a chance to modify.

Let’s change our serializer to create a details field for our serialized data to simply expose all the fields of the Folder class:

@Override
public void serialize(Folder value, JsonGenerator gen, SerializerProvider provider) throws IOException {
    gen.writeStartObject();
    gen.writeStringField("name", value.getName());

    provider.defaultSerializeField("files", value.getFiles(), gen);

    // this line causes exception
    provider.defaultSerializeField("details", value, gen);

    gen.writeEndObject();
}

This time we get a StackOverflowError exception.

When we define a custom serializer, Jackson internally overrides the original BeanSerializer instance that is created for the type Folder. Consequently, our SerializerProvider finds the customized serializer every time, instead of the default one, and this causes an infinite loop.

So, how do we solve this problem? We’ll see one usable solution for this scenario in the next section.

5. Using BeanSerializerModifier

A possible workaround is using BeanSerializerModifier to store the default serializer for the type Folder before Jackson internally overrides it.

Let’s modify our serializer and add an extra field — defaultSerializer:

private final JsonSerializer<Object> defaultSerializer;

public FolderJsonSerializer(JsonSerializer<Object> defaultSerializer) {
    super(Folder.class);
    this.defaultSerializer = defaultSerializer;
}

Next, we’ll create an implementation of BeanSerializerModifier to pass the default serializer:

public class FolderBeanSerializerModifier extends BeanSerializerModifier {

    @Override
    public JsonSerializer<?> modifySerializer(
      SerializationConfig config, BeanDescription beanDesc, JsonSerializer<?> serializer) {

        if (beanDesc.getBeanClass().equals(Folder.class)) {
            return new FolderJsonSerializer((JsonSerializer<Object>) serializer);
        }

        return serializer;
    }
}

Now, we need to register our BeanSerializerModifier as a module to make it work:

ObjectMapper mapper = new ObjectMapper();

SimpleModule module = new SimpleModule();
module.setSerializerModifier(new FolderBeanSerializerModifier());

mapper.registerModule(module);

Then, we use the defaultSerializer for the details field:

@Override
public void serialize(Folder value, JsonGenerator gen, SerializerProvider provider) throws IOException {
    gen.writeStartObject();
    gen.writeStringField("name", value.getName());

    provider.defaultSerializeField("files", value.getFiles(), gen);

    gen.writeFieldName("details");
    defaultSerializer.serialize(value, gen, provider);

    gen.writeEndObject();
}

Lastly, we may want to remove the files field from the details since we already write it into the serialized data separately.

So, we simply ignore the files field in our Folder class:

@JsonIgnore
private List<File> files = new ArrayList<>();

Finally, the problem is solved and we get our expected output as well:

{
    "name": "Root Folder",
    "files": [
        {"id": 1, "name": "File 1"},
        {"id": 2, "name": "File 2"}
    ],
    "details": {
        "id":1,
        "name": "Root Folder",
        "owner": "root",
        "created": 1565203657164,
        "modified": 1565203657164,
        "lastAccess": 1565203657164
    }
}

6. Conclusion

In this tutorial, we learned how to call default serializers inside a custom serializer in Jackson Library.

The code backing this article is available on GitHub. Once you're logged in as a Baeldung Pro Member, start learning and coding on the project.
Baeldung Pro – NPI EA (cat = Baeldung)
announcement - icon

Baeldung Pro comes with both absolutely No-Ads as well as finally with Dark Mode, for a clean learning experience:

>> Explore a clean Baeldung

Once the early-adopter seats are all used, the price will go up and stay at $33/year.

eBook – HTTP Client – NPI EA (cat=HTTP Client-Side)
announcement - icon

The Apache HTTP Client is a very robust library, suitable for both simple and advanced use cases when testing HTTP endpoints. Check out our guide covering basic request and response handling, as well as security, cookies, timeouts, and more:

>> Download the eBook

eBook – Java Concurrency – NPI EA (cat=Java Concurrency)
announcement - icon

Handling concurrency in an application can be a tricky process with many potential pitfalls. A solid grasp of the fundamentals will go a long way to help minimize these issues.

Get started with understanding multi-threaded applications with our Java Concurrency guide:

>> Download the eBook

eBook – Java Streams – NPI EA (cat=Java Streams)
announcement - icon

Since its introduction in Java 8, the Stream API has become a staple of Java development. The basic operations like iterating, filtering, mapping sequences of elements are deceptively simple to use.

But these can also be overused and fall into some common pitfalls.

To get a better understanding on how Streams work and how to combine them with other language features, check out our guide to Java Streams:

>> Join Pro and download the eBook

eBook – Persistence – NPI EA (cat=Persistence)
announcement - icon

Working on getting your persistence layer right with Spring?

Explore the eBook

Course – LS – NPI EA (cat=REST)

announcement - icon

Get started with Spring Boot and with core Spring, through the Learn Spring course:

>> CHECK OUT THE COURSE

Partner – Moderne – NPI EA (tag=Refactoring)
announcement - icon

Modern Java teams move fast — but codebases don’t always keep up. Frameworks change, dependencies drift, and tech debt builds until it starts to drag on delivery. OpenRewrite was built to fix that: an open-source refactoring engine that automates repetitive code changes while keeping developer intent intact.

The monthly training series, led by the creators and maintainers of OpenRewrite at Moderne, walks through real-world migrations and modernization patterns. Whether you’re new to recipes or ready to write your own, you’ll learn practical ways to refactor safely and at scale.

If you’ve ever wished refactoring felt as natural — and as fast — as writing code, this is a good place to start.

eBook Jackson – NPI EA – 3 (cat = Jackson)
eBook Jackson – NPI (cat = Jackson)