Spring WebFlux
ServerResponse
Jackson Serializer
JSON Processing
Serialization Issues

Spring WebFlux - ServerResponse Jackson Serializer problems

Interview Questions practice on Codemia

Over 8,000 real interview questions from top companies, searchable by company and role.

Browse interview questions

Introduction

Jackson serialization issues in Spring WebFlux often appear as empty JSON, unexpected field formats, or runtime codec errors. The root cause is usually codec configuration mismatch rather than controller logic. A reliable setup aligns your ObjectMapper, WebFlux codecs, and response types.

How Serialization Works in WebFlux

WebFlux uses HttpMessageWriter implementations to encode response bodies. For JSON, the default writer delegates to Jackson through Jackson2JsonEncoder. If custom modules, date formats, or Kotlin handling are missing, output can be wrong even when the application starts successfully.

A typical functional endpoint looks like this:

java
1import org.springframework.context.annotation.Bean;
2import org.springframework.context.annotation.Configuration;
3import org.springframework.http.MediaType;
4import org.springframework.web.reactive.function.server.RouterFunction;
5import org.springframework.web.reactive.function.server.ServerResponse;
6import reactor.core.publisher.Mono;
7
8import static org.springframework.web.reactive.function.server.RouterFunctions.route;
9import static org.springframework.web.reactive.function.server.RequestPredicates.GET;
10
11@Configuration
12public class RoutesConfig {
13
14    @Bean
15    RouterFunction<ServerResponse> routes() {
16        return route(GET("/user"), req -> {
17            UserDto dto = new UserDto("u1", "Mira");
18            return ServerResponse.ok()
19                    .contentType(MediaType.APPLICATION_JSON)
20                    .bodyValue(dto);
21        });
22    }
23
24    public record UserDto(String id, String name) {}
25}

If this endpoint produces wrong JSON, the issue is usually mapper or codec configuration.

Configure a Single ObjectMapper Source

Avoid creating multiple mappers with different modules. Register one mapper bean and wire it into WebFlux codecs.

java
1import com.fasterxml.jackson.databind.ObjectMapper;
2import com.fasterxml.jackson.databind.SerializationFeature;
3import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
4import org.springframework.context.annotation.Bean;
5import org.springframework.context.annotation.Configuration;
6
7@Configuration
8public class JacksonConfig {
9
10    @Bean
11    ObjectMapper objectMapper() {
12        ObjectMapper mapper = new ObjectMapper();
13        mapper.registerModule(new JavaTimeModule());
14        mapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
15        return mapper;
16    }
17}

Then attach that mapper to WebFlux codec configuration.

java
1import org.springframework.context.annotation.Configuration;
2import org.springframework.http.codec.ServerCodecConfigurer;
3import org.springframework.http.codec.json.Jackson2JsonDecoder;
4import org.springframework.http.codec.json.Jackson2JsonEncoder;
5import org.springframework.web.reactive.config.WebFluxConfigurer;
6
7@Configuration
8public class WebFluxCodecConfig implements WebFluxConfigurer {
9
10    private final com.fasterxml.jackson.databind.ObjectMapper mapper;
11
12    public WebFluxCodecConfig(com.fasterxml.jackson.databind.ObjectMapper mapper) {
13        this.mapper = mapper;
14    }
15
16    @Override
17    public void configureHttpMessageCodecs(ServerCodecConfigurer configurer) {
18        configurer.defaultCodecs().jackson2JsonEncoder(new Jackson2JsonEncoder(mapper));
19        configurer.defaultCodecs().jackson2JsonDecoder(new Jackson2JsonDecoder(mapper));
20    }
21}

This prevents subtle mismatches between controller serialization and test serialization.

Common Failure Patterns and Fixes

Serialization failures often come from one of these:

  • Missing module for Java time classes.
  • Returning unsupported types from handlers.
  • Streaming responses with wrong media type.
  • Blocking conversion logic inside reactive chains.

For streaming JSON, use proper newline-delimited or server-sent events format and matching content type. For regular objects, bodyValue is usually enough.

Testing Serialization Behavior

Add focused tests that assert exact JSON shape. This catches mapper drift early.

java
1import org.junit.jupiter.api.Test;
2import org.springframework.beans.factory.annotation.Autowired;
3import org.springframework.boot.test.autoconfigure.web.reactive.WebFluxTest;
4import org.springframework.test.web.reactive.server.WebTestClient;
5
6@WebFluxTest
7class UserEndpointTest {
8
9    @Autowired
10    WebTestClient client;
11
12    @Test
13    void userJsonShapeIsStable() {
14        client.get().uri("/user")
15                .exchange()
16                .expectStatus().isOk()
17                .expectHeader().contentType("application/json")
18                .expectBody()
19                .jsonPath("$.id").isEqualTo("u1")
20                .jsonPath("$.name").isEqualTo("Mira");
21    }
22}

These tests are lightweight and highly effective for reactive APIs.

Serialization for Reactive Streams

When returning streams, serialization behavior differs from single-object responses. If you return a flux of domain objects, verify the media type and client parsing strategy. For line-delimited JSON style responses, the client must process items incrementally.

java
1import reactor.core.publisher.Flux;
2
3Flux<RoutesConfig.UserDto> stream = Flux.just(
4        new RoutesConfig.UserDto("u1", "Mira"),
5        new RoutesConfig.UserDto("u2", "Rin")
6);
7
8// Example usage inside handler
9// return ServerResponse.ok().contentType(MediaType.APPLICATION_NDJSON).body(stream, RoutesConfig.UserDto.class);

If you use the wrong content type with streaming responses, clients may buffer unexpectedly or parse invalid frames. Keep streaming format decisions explicit in API docs and tests.

Mapper Customization Strategy

Large applications often need custom serializers for domain-specific types. Register custom modules in one place instead of scattered per-controller conversion logic.

java
1import com.fasterxml.jackson.core.JsonGenerator;
2import com.fasterxml.jackson.databind.JsonSerializer;
3import com.fasterxml.jackson.databind.SerializerProvider;
4import com.fasterxml.jackson.databind.module.SimpleModule;
5
6class UserIdSerializer extends JsonSerializer<String> {
7    @Override
8    public void serialize(String value, JsonGenerator gen, SerializerProvider serializers) throws java.io.IOException {
9        gen.writeString("user-" + value);
10    }
11}
12
13// mapper.registerModule(new SimpleModule().addSerializer(String.class, new UserIdSerializer()));

Use targeted serializers carefully to avoid global side effects. Scoped serializers for dedicated DTO fields are usually safer than broad type-level overrides.

Common Pitfalls

  • Defining multiple ObjectMapper beans with inconsistent modules.
  • Assuming MVC codec settings apply automatically to WebFlux.
  • Returning reactive wrappers with unsupported nested payload types.
  • Forgetting JSON content type on manual ServerResponse builders.
  • Skipping response-shape tests and discovering issues late.

Summary

  • WebFlux JSON output depends on codec and mapper alignment.
  • Use one shared ObjectMapper and wire it into codecs.
  • Register required modules such as Java time support.
  • Validate output structure with focused WebFlux tests.
  • Treat serialization configuration as part of API contract.

Related reading
Course
Intermediate
27 lessons
14 hours
OOD Fundamentals

Master object-oriented design from first principles, SOLID, design patterns, and classic interview problems with hands-on coding.

View the course
Track what you have practised

A free account saves your progress, solutions and study plan across every problem on Codemia.

Interview Questions practice on Codemia

Over 8,000 real interview questions from top companies, searchable by company and role.

Browse interview questions

All Rights Reserved.