jackson-databind icon indicating copy to clipboard operation
jackson-databind copied to clipboard

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

Open k163377 opened this issue 7 months ago • 6 comments

Search before asking

  • [X] 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. https://github.com/FasterXML/jackson-databind/issues/4218#issuecomment-1826461447

k163377 avatar Nov 25 '23 05:11 k163377