question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Auto-detection of constructor-based creator method skipped if there is an annotated factory-based creator method (regression from 2.11)

See original GitHub issue

Describe the bug First, I am not sure whether it’s a bug or expected behavior, but I just wanted to open an issue for my understanding. Prior to Jackson 2.12.0, it was possible to bind a Number (e.g., 42) to a single field DTO (see example code below). Now, it throws MismatchedInputException with this message:

Cannot construct instance of `jackson211$ExampleDto$Json` (although at least one Creator exists):
no int/Int-argument constructor/factory method to deserialize from Number value (42) at [Source: (String)"42"; line: 1, column: 1]

Version information 2.12.0

To Reproduce The code below can be used.

Some notes:

  • I used jbang to switch between versions easily.
  • The example Dto is the minimal version of an Immutables generated code.
  • Jackson 2.11.3 uses the private constructor to deserialize Number to Dto object.
/// usr/bin/env jbang "$0" "$@" ; exit $?
//DEPS com.fasterxml.jackson.core:jackson-annotations:2.12.0
//DEPS com.fasterxml.jackson.core:jackson-databind:2.12.0

// It prints `true` on 2.11.3.
////DEPS com.fasterxml.jackson.core:jackson-annotations:2.11.3
////DEPS com.fasterxml.jackson.core:jackson-databind:2.11.3

import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
import java.util.Objects;

public final class jackson211 {
    private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper();

    public static void main(String... args) throws JsonProcessingException {
        int version = 1;
        ExampleDto deserialize = OBJECT_MAPPER.readValue(String.valueOf(version), ExampleDto.class);
        System.out.println(new ExampleDto(version).equals(deserialize));
    }

    static final class ExampleDto {
        private final int version;

        private ExampleDto(int version) {
            this.version = version;
        }

        @Override
        public boolean equals(Object o) {
            if (this == o) return true;
            if (o == null || getClass() != o.getClass()) return false;
            ExampleDto that = (ExampleDto) o;
            return version == that.version;
        }

        @Override
        public int hashCode() {
            return Objects.hash(version);
        }

        @JsonCreator(mode = JsonCreator.Mode.DELEGATING)
        static ExampleDto fromJson(Json json) {
            return new ExampleDto(json.version);
        }

        @JsonDeserialize
        @JsonAutoDetect(fieldVisibility = JsonAutoDetect.Visibility.NONE)
        static final class Json {
            int version;
            boolean versionIsSet;

            @JsonProperty
            public void setVersion(int version) {
                this.version = version;
                this.versionIsSet = true;
            }

            public int getVersion() {
                throw new UnsupportedOperationException();
            }
        }
    }
}

Expected behavior As I wrote at the beginning, I am not sure whether it’s a bug or expected behavior. If it’s a bug then, the example code should print true instead of throwing an exception.

Additional context N/A

Issue Analytics

  • State:closed
  • Created 3 years ago
  • Reactions:1
  • Comments:8 (5 by maintainers)

github_iconTop GitHub Comments

1reaction
cowtowncodercommented, Dec 6, 2020

So, rewritten code in 2.12 (meant to work same way as before) had checks so that:

  • Only check for implicit (non-annotated) Constructors if neither annotated factory methods NOR annotated constructors found

but apparently logic earlier was

  • Only check for implicit (non-annotated) Constructors if no annotated constructors found

so that existence of annotated factory method was the difference. Will change code to use older logic, to try to keep backwards-compatibility. This is bit tricky going forward as definition is not very crisp, but seems like the right thing to do for now.

1reaction
cowtowncodercommented, Dec 2, 2020

Ok thank you for verifying these aspects. It sounds like there is an unintended change in behavior here, and I hope to look into it when I get a chance.

Read more comments on GitHub >

github_iconTop Results From Across the Web

Security update for jackson-databind, jackson-dataformats ...
... Auto-detection of constructor-based creator method skipped if there is an annotated factory-based creator method (regression from 2.11) ...
Read more >
JsonCreator (Jackson-annotations 2.11.1 API) - javadoc.io
Marker annotation that can be used to define constructors and factory methods as one to use for instantiating new instances of the associated...
Read more >
3.4.1.1 Constructor-based dependency injection - Spring
Dependency injection (DI) is a process whereby objects define their dependencies, that is, the other objects they work with, only through constructor arguments, ......
Read more >
No Int/Int-Argument Constructor/Factory Method To Deserialize
Autodetection of constructorbased creator method skipped if there is an annotated factorybased creator method regression from 2.11 #.
Read more >
Jackson 2.12 Most Wanted (3/5) - cowtowncoder - Medium
Annotation -less @JsonCreator (even 1-argument) ... (and static factory methods) are ambiguous: there are 2 possible “modes” of binding:.
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found