jackson-databind: One field deserialization bug

Search before asking

  • I searched in the issues and found nothing similar.

Describe the bug

I compile java sources with -parameters and I register Jackson’s com.fasterxml.jackson.module:jackson-module-parameter-names:2.16.0

Everything works as expected for classes with two and/or more fields.

But deserialization of a class with one field — fails.

Adding any of annotations: @ConstructorProperties("a") or @JsonCreator helps.

But they are not required in case of “2+ field” classes.

A very short test that shows the problem is attached.

Version Information

2.16.0

Reproduction

public class JacksonBehaviorTest {
  public static class One {
    public final Integer a;

    //@ConstructorProperties("a")
    //@JsonCreator
    public One (Integer a){ this.a = a; }
  }
  public static class Two {
    public final Integer a;
    public final Integer b;

    public Two (Integer a, Integer b){ this.a = a; this.b = b; }
  }
  @Test
  void testDeserializationBug () throws JsonProcessingException {
    ObjectMapper mapper = new ObjectMapper().findAndRegisterModules();
    String s = "{\"b\":2,\"a\":1}";// wrong order to show `-parameters` works
    Two two = mapper.readValue(s, Two.class);
    assertEquals("{\"a\":1,\"b\":2}", mapper.writeValueAsString(two));// Two is ok
    s = "{\"a\":1}";
    mapper.readValue(s, One.class);
    fail("One must fail with: MismatchedInputException: Cannot construct instance of `test.JacksonBehaviorTest$One` (although at least one Creator exists): cannot deserialize from Object value (no delegate- or property-based Creator) ");
  }
}

Expected behavior

Deserialization must work for class One as it does for class Two

Additional context

Funny fact @ConstructorProperties with ANY text helps: E.g. @ConstructorProperties("You can call me Your Majesty") works and one.a == 1

About this issue

  • Original URL
  • State: closed
  • Created 7 months ago
  • Reactions: 3
  • Comments: 16 (9 by maintainers)

Most upvoted comments

Maybe it is time to add ~ com.fasterxml.jackson.databind.MapperFeature#SUPPORT_ONE_ARG_CTOR if a class has one ctor with one parameter, and the type of this parameter is the same as one final field, and this MapperFeature is enabled then use this ctor even without javac -parameters and jackson-module-parameter-names 🤷‍♀️

Isn’t it a bug?

I think it’s more like there’s no feature request because whatever that is already available is enough to make things work.

And making such change may break behaviour people are already relying on (I’ve learned my lesson from my previous contribution that users do really weird things).

“Use heuristics to see if “properties” mode is to be used (POJO has a property with the same name as the implicit name [if available] of the constructor argument). Note: this is the default choice for Jackson versions before 2.12.”

The problem is currently, Jackson considers a constructor argument as “having implicit name” if and only if the constructor is annotated with @JsonCreator or @ConstructorProperties, which is why it worked when you used them.

Maybe it is time to add ~ com.fasterxml.jackson.databind.MapperFeature#SUPPORT_ONE_ARG_CTOR

Reminds me of ConstructorDetector.USE_PROPERTIES_BASED https://cowtowncoder.medium.com/jackson-2-12-most-wanted-3-5-246624e2d3d0 - is that what you’re looking for?

ConstructorProperties is a bit weird, i’m guessing it might just work as a JsonCreator and then the parameters module overrides the param names