Skip to content

Kotlin Serialization does not back off when JSON-B is the only JSON converter #50953

Description

@dlwldnjs1009

KotlinSerializationJsonConvertersCustomizer gives the Kotlin Serialization converter a broad (type) -> true predicate unless one of its Jackson 3, Jackson 2, or Gson classpath checks matches. JSON-B is not among those checks:

boolean hasAnyJsonSupport = ClassUtils.isPresent("tools.jackson.databind.json.JsonMapper", classLoader)
        || ClassUtils.isPresent("com.fasterxml.jackson.databind.ObjectMapper", classLoader)
        || ClassUtils.isPresent("com.google.gson.Gson", classLoader);

When JSON-B and Kotlin Serialization are configured together without Jackson or Gson, the Kotlin converter claims every type for application/json and, being ordered ahead of JSON-B, handles non-@Serializable types that JsonbHttpMessageConverter would otherwise serialize. This doesn't match the "when no alternative JSON converter is available" intent of #48070.

Reproduction: with only kotlinx-serialization-json and a JSON-B provider on the classpath (no Jackson/Gson). With this setup, the auto-configured Kotlin converter is given its broad (type) -> true predicate and therefore reports that it can write Map as application/json, so it wins over JsonbHttpMessageConverter for non-@Serializable types. The same client and server customizer feeds MVC, RestTemplate, and RestClient; the reactive codec side has no JSON-B codec and is not affected.

This is a regression from 4.0.0 to 4.0.1. The original fix for #48070 (58cdf71) decided the predicate by scanning the registered HttpMessageConverter beans for one supporting application/json, which included JSON-B. The client/server split in 4.0.1 (50f64f) replaced that with the Jackson/Jackson2/Gson classpath check above, dropping JSON-B. It remains in 4.0.x, 4.1.x, and main.

A plain jakarta.json.bind.Jsonb classpath check needs care: JsonbAutoConfiguration requires JSON-B and JSON-P provider resources before it creates a Jsonb bean (covered by JsonbAutoConfigurationWithNoProviderTests), whereas Spring Framework's default converter detection checks for the JSON-B API alone. The API-only case therefore needs separate consideration. What is the right signal to reflect the JSON-B converter's actual availability in the Kotlin predicate?

If this direction is appropriate, I can prepare a small patch with tests covering both the active JSON-B and API-only cases.

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions