Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Consider SetterInfo in the deserializer's absentValue #4221

Closed
k163377 opened this issue Nov 26, 2023 · 7 comments
Closed

Consider SetterInfo in the deserializer's absentValue #4221

k163377 opened this issue Nov 26, 2023 · 7 comments
Labels
to-evaluate Issue that has been received but not yet evaluated

Comments

@k163377
Copy link
Contributor

k163377 commented Nov 26, 2023

Is your feature request related to a problem? Please describe.

In kotlin-module, there is a process to get the absentValue of the valueDeserializer when no value is entered on the JSON.
https://github.com/FasterXML/jackson-module-kotlin/blob/05869498a780523e036ed20ba57392b1cd43fca1/src/main/kotlin/com/fasterxml/jackson/module/kotlin/KotlinValueInstantiator.kt#L87

On the other hand, if Nulls.AS_EMPTY is specified by JsonSetter or configOverride, this absentValue will also be null.

Describe the solution you'd like

The absentValue returns a value according to SetterInfo.

Usage example

No response

Additional context

If this can be done, the following options and associated processing can be removed in kotlin-module.
https://github.com/FasterXML/jackson-module-kotlin/blob/05869498a780523e036ed20ba57392b1cd43fca1/src/main/kotlin/com/fasterxml/ jackson/module/kotlin/KotlinFeature.kt#L9-L17

@k163377 k163377 added the to-evaluate Issue that has been received but not yet evaluated label Nov 26, 2023
@k163377
Copy link
Contributor Author

k163377 commented Nov 26, 2023

I commented on #4201, but as far as kotlin-module is concerned, if there is a way to read values from PropertyValueBuffer without error, this feature may not be necessary.

@cowtowncoder
Copy link
Member

I am not sure I understand the request here. Maybe a PR or (if possible) failing test would help show it?

@k163377
Copy link
Contributor Author

k163377 commented Dec 9, 2023

@cowtowncoder
Sorry for the late reply, I have created a sample code.
In the following example, the SetterInfo is ignored in getAbsentValue.
On the other hand, FAIL_ON_NULL_FOR_PRIMITIVES works fine.

import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.annotation.JsonSetter;
import com.fasterxml.jackson.annotation.Nulls;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.*;
import com.fasterxml.jackson.databind.deser.SettableBeanProperty;
import com.fasterxml.jackson.databind.deser.ValueInstantiator;
import com.fasterxml.jackson.databind.deser.impl.PropertyValueBuffer;
import com.fasterxml.jackson.databind.deser.std.StdValueInstantiator;
import com.fasterxml.jackson.databind.module.SimpleModule;
import com.fasterxml.jackson.databind.module.SimpleValueInstantiators;
import org.junit.jupiter.api.Test;

import java.util.List;

public class DefaultWithContext {
    static class Dto {
        private final List<String> foo;
        private final int bar;

        @JsonCreator
        Dto(@JsonProperty("foo") List<String> foo, @JsonProperty("bar") int bar) {
            this.foo = foo;
            this.bar = bar;
        }
    }

    static class Instantiator extends StdValueInstantiator {
        public Instantiator(StdValueInstantiator src) {
            super(src);
        }

        @Override
        public Object createFromObjectWith(
                DeserializationContext ctxt,
                SettableBeanProperty[] props,
                PropertyValueBuffer buffer
        ) {
            for (SettableBeanProperty prop : props) {
                JsonDeserializer<Object> deser = prop.getValueDeserializer();

                Object result;
                try {
                    result = deser.getAbsentValue(ctxt);
                } catch (Exception e) {
                    result = e;
                }

                System.out.println(prop.getName() + ": " + result);
            }

            return null;
        }
    }

    static class Instantiators extends SimpleValueInstantiators {
        public ValueInstantiator findValueInstantiator(
                DeserializationConfig config,
                BeanDescription beanDesc,
                ValueInstantiator defaultInstantiator
        ) {
            if (defaultInstantiator instanceof StdValueInstantiator) {
                return new Instantiator((StdValueInstantiator) defaultInstantiator);
            } else {
                return defaultInstantiator;
            }
        }
    }

    @Test
    void test() throws JsonProcessingException {
        SimpleModule module = new SimpleModule();
        module.setValueInstantiators(new Instantiators());
        ObjectMapper mapper = new ObjectMapper().registerModule(module);

        // foo: null
        // bar: 0
        mapper.readValue("{}", Dto.class);

        // FAIL_ON_NULL_FOR_PRIMITIVES is reflected in getAbsentValue.
        mapper.enable(DeserializationFeature.FAIL_ON_NULL_FOR_PRIMITIVES);
        // foo: null
        // bar: com.fasterxml.jackson.databind.exc.MismatchedInputException: Cannot map ...
        mapper.readValue("{}", Dto.class);

        mapper.disable(DeserializationFeature.FAIL_ON_NULL_FOR_PRIMITIVES);

        // SetterInfo is not reflected in getAbsentValue.
        mapper.configOverride(List.class).setSetterInfo(JsonSetter.Value.forValueNulls(Nulls.AS_EMPTY));
        // foo: null
        // bar: 0
        mapper.readValue("{}", Dto.class);
    }
}

@JooHyukKim
Copy link
Member

JooHyukKim commented Dec 9, 2023

I was thinking maybe adding a new option `So adding MapperFeature (USE_ABSENT_FOR_MISSING_REQUIRED or whatever) instead of...

FYI, Have you checked Tatu's last idea about adding an option that Kotlin module can use in #4201? Maybe such option may possibly be easier to implement and less disruptive 🤔? Instead ...

Describe the solution you'd like

The absentValue returns a value according to SetterInfo.

...of connecting these, absentValue and SetterInfo functionalities? @k163377

@k163377
Copy link
Contributor Author

k163377 commented Dec 9, 2023

you checked Tatu's last idea about #4201 (comment) that Kotlin module can use in #4201?

I was wondering what content to reply with.

connecting these, absentValue and SetterInfo functionalities?

As you can see in the sample code, there are cases where the DeserializationContext setting is respected and other cases where it is not, which can be a bit confusing.
I am sorry for the way I wrote it, but I would appreciate it if you could consider it as a databind feature.

@cowtowncoder
Copy link
Member

Hmmh. Well, absent value comes from JsonDeserializer (sort of fixed), SetterInfo from annotations. The two are not combined, so getAbsentValue() never considers SetterInfo.

But the two are also not quite the same things; SetterInfo relates to handling of explicit null values from input, and "absent" value means handling of case where nothing comes from input (although only supported for Creator methods, not for Setters or Fields).

I think there is some confusion here.

@k163377
Copy link
Contributor Author

k163377 commented Dec 10, 2023

Oh, I was very much mistaken.
It seems that the information in the SetterInfo is set in the SettableBeanProperty and cannot be read from the DeserializationContext.

This request is closed because it was based on a misunderstanding.

@k163377 k163377 closed this as completed Dec 10, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
to-evaluate Issue that has been received but not yet evaluated
Projects
None yet
Development

No branches or pull requests

3 participants