Skip to content

If JacksonInject is specified for field and deserialized by the Creator, the inject process will be executed twice. #4218

@k163377

Description

@k163377

Search before asking

  • I searched in the issues and found nothing similar.

Describe the bug

SSIA

Version Information

2.16.0

Reproduction

The following is a sample using InjectableValues that is made to count up when findInjectableValue is called.
Since it is deserialized only once, the first ID is expected, but it is actually the second ID.

import com.fasterxml.jackson.annotation.JacksonInject;
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.*;
import org.junit.jupiter.api.Test;

import java.util.Arrays;
import java.util.List;
import java.util.UUID;

import static org.junit.jupiter.api.Assertions.assertEquals;

public class JacksonInjectForFieldTest {
    static class Dto {
        @JacksonInject("uuid")
        private final UUID uuid;

        @JsonCreator
        Dto(
                // @JacksonInject("uuid")
                @JsonProperty("uuid")
                UUID uuid
        ) {
            this.uuid = uuid;
        }
    }

    List<UUID> ids = Arrays.asList(UUID.randomUUID(), UUID.randomUUID());
    class MyInjectableValues extends InjectableValues.Std {
        int count = 0; // count up if injected

        @Override
        public Object findInjectableValue(
                Object valueId,
                DeserializationContext ctxt,
                BeanProperty forProperty,
                Object beanInstance
        ) throws JsonMappingException {
            if (valueId.equals("uuid")) {
                return ids.get(count++);
            } else {
                return super.findInjectableValue(valueId, ctxt, forProperty, beanInstance);
            }
        }
    }

    @Test
    void test() throws JsonProcessingException {
        ObjectReader reader = new ObjectMapper()
                .readerFor(Dto.class)
                .with(new MyInjectableValues());

        Dto dto = reader.readValue("{}");
        UUID actual = dto.uuid;

        System.out.println(ids);
        System.out.println(ids.get(0) == actual);
        System.out.println(ids.get(1) == actual);

        assertEquals(ids.get(0), actual);
    }
}

Expected behavior

The inject process is executed only once.
In fact, if a specification is made for a parameter, the result is as expected.

Additional context

After processing in the creator, another injection is performed on the field, so it is called twice in total.

I commented but forgot to mention the above initially.
#4218 (comment)

Metadata

Metadata

Assignees

No one assigned

    Labels

    has-failing-testIndicates that there exists a test case (under `failing/`) to reproduce the issue

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions