Skip to content

If ImplicitPropertyName is present, one-argument constructors with JsonCreator.Mode.DEFAULT are treated differently than usual. #4960

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

Open
1 task done
k163377 opened this issue Feb 8, 2025 · 1 comment
Labels
to-evaluate Issue that has been received but not yet evaluated

Comments

@k163377
Copy link
Contributor

k163377 commented Feb 8, 2025

Search before asking

  • I searched in the issues and found nothing similar.

Describe the bug

If there is an ImplicitPropertyName, it seems that JsonCreator.Mode.PROPERTIES is treated as the basis.

Version Information

Both refer to the head of the branch.

  • 2.17
  • 2.18

Reproduction

Comment out findImplicitPropertyName so that it is treated as JsonCreator.Mode.DELEGATING and the test will succeed.

import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.cfg.MapperConfig;
import com.fasterxml.jackson.databind.introspect.*;
import com.fasterxml.jackson.databind.module.SimpleModule;
import org.junit.Test;

import java.util.Map;

public class GitHub846Java {
    static class Dst {
        private final Map<String, String> map;

        Dst(Map<String, String> map) {
            this.map = map;
        }

        public Map<String, String> getMap() {
            return map;
        }
    }

    // region: reproducing for 2.17
    static class AI217 extends NopAnnotationIntrospector {
        @Override
        public String findImplicitPropertyName(AnnotatedMember member) {
            // Hard coded as only Dst needs to be processed
            if (member instanceof AnnotatedParameter) {
                System.out.println(member);
                System.out.println("map");
                return "map";
            }
            return null;
        }

        @Override
        public JsonCreator.Mode findCreatorAnnotation(MapperConfig<?> config, Annotated ann) {
            if (ann instanceof AnnotatedConstructor) {
                AnnotatedConstructor ac = (AnnotatedConstructor) ann;
                if (ac.getParameterCount() == 1) {
                    System.out.println(ac);
                    return JsonCreator.Mode.DEFAULT;
                }
            }
            return super.findCreatorAnnotation(config, ann);
        }
    }

    @Test
    public void test217() throws JsonProcessingException {
        SimpleModule sm = new SimpleModule() {
            @Override
            public void setupModule(SetupContext context) {
                super.setupModule(context);
                context.appendAnnotationIntrospector(new AI217());
            }
        };
        ObjectMapper mapper = new ObjectMapper().registerModule(sm);

        Dst dst = mapper.readValue("{ \"key\":\"value\" }", Dst.class);

        System.out.println(dst.getMap());
    }
    // endregion
}

Expected behavior

Given that it is not an explicit name, I felt that the treatment of both could be the same.

Additional context

This was found in a research on the following comment
FasterXML/jackson-module-kotlin#846 (comment)

I was not sure if this behavior is a bug, but I submitted it because if it is fixed as a bug, the above issue may be fixed at the same time.

There also seems to be a way to treat it as JsonCreator.Mode.DELEGATING by making some changes to the reproduced code, at least in the 2.17 branch.
The 2.17 branch of kotlin-module should be handled the same way as the reproduced code, but the test does not fail (this behavior seems to have been changed destructively in 2.18, and FasterXML/jackson-module-kotlin#846 is the issue that reports it).
Since it will take more time to investigate the cause of this behavior, let me first ask if the change in behavior with or without ImplicitPropertyName is the expected behavior.

@cowtowncoder
Copy link
Member

The problem is not just the implicit name (although it is required, just not sufficient), but rather there is:

        public Map<String, String> getMap() {

which makes it look very likely map is a Property to set. So this is intentional heuristics, unfortunately.
If getter was missing (public Field named "map" would also cause this) heuristics would not work this way.
The reason for heuristics is easier to see if we instead had, say, String name.

I don't know why 2.17 or earlier might have worked differently.

The one question there is whether heuristics should consider type Map (and perhaps JsonNode) to instead imply DELEGATING.

I think this is sort of follow-up to #4911.

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

2 participants