Skip to content

There are cases where isRequired specifications are not properly merged. #668

@k163377

Description

@k163377

Jackson has a policy of merging annotations assigned to accessors, fields, or parameters into a single property.
ProjectMapK/jackson-module-kogera#101 (comment)

Therefore, the goal of this issue is to match the behavior of databind.

The following is an old explanation.


Describe the bug
For example, if a getter is given JsonProperty(required = true), the parameter nullability is ignored and overridden by required = true.
This appears to be an unexpected behavior, since getters are not involved in deserialization.

Also, since this override does not occur for setters, there is no consistency in behavior.

To Reproduce

import com.fasterxml.jackson.annotation.JsonProperty
import com.fasterxml.jackson.databind.BeanDescription
import com.fasterxml.jackson.databind.ObjectMapper
import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper
import org.junit.Test

class PropRequiredTest {
    val mapper = jacksonObjectMapper()

    private inline fun <reified T> ObjectMapper.introspectDeser(): BeanDescription =
        deserializationConfig.introspect(deserializationConfig.constructType(T::class.java))

    private fun BeanDescription.isRequired(propertyName: String): Boolean =
        this.findProperties().find { it.name == propertyName }?.isRequired ?: false

    data class AffectByAccessor(
        @get:JsonProperty(required = true)
        var a: String?,
        @field:JsonProperty(required = true)
        var b: String?,
        @set:JsonProperty(required = true)
        var c: String?
    ) {
        @get:JsonProperty(required = true)
        var x: String? = null
        @field:JsonProperty(required = true)
        var y: String? = null
        @JvmField
        @field:JsonProperty(required = true)
        var z: String? = null
    }

    @Test
    fun affectByAccessorTestDeser() {
        val desc = mapper.introspectDeser<AffectByAccessor>()

        // The expected value of a ~ c is false, but the actual values are all true.
        val a = desc.isRequired("a")
        val b = desc.isRequired("b")
        val c = desc.isRequired("c")

        // x and y is false and z is true. These are the expected values.
        val x = desc.isRequired("x")
        val y = desc.isRequired("y")
        val z = desc.isRequired("z")
    }
}

Expected behavior
Annotations assigned to accessors should not affect the creator.

Versions
Kotlin: 1.5.32
Jackson-module-kotlin & Jackson-databind: 2.15.0

Additional context
If processing is performed without registering a KotlinModule, a ~ c and x ~ z will all be true.
Therefore, a possible policy is to match the KotlinModule to this result.

Metadata

Metadata

Assignees

No one assigned

    Labels

    3.xIssue affecting/planned for Jackson 3.xbug

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions