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

"Input mismatch reading Enum" after upgrade to Jackson 2.11 #336

Closed
sschuberth opened this issue May 10, 2020 · 14 comments
Closed

"Input mismatch reading Enum" after upgrade to Jackson 2.11 #336

sschuberth opened this issue May 10, 2020 · 14 comments

Comments

@sschuberth
Copy link

After upgrading Jackson from 2.10.3 to 2.11.0 we started to see "Input mismatch reading Enum" errors when deserializing this Koltin Enum class which has a custom @JsonCreator.

To reproduce, you may want to check out this PR and run the added test via

./gradlew :clearly-defined:test --tests org.ossreviewtoolkit.clearlydefined.ClearlyDefinedServiceTest

with and without the Revert "Gradle: Upgrade Jackson to version 2.11.0" commit.

The full error is:

com.fasterxml.jackson.databind.exc.MismatchedInputException: Input mismatch reading Enum `org.ossreviewtoolkit.clearlydefined.ClearlyDefinedService$Provider`: properties-based `@JsonCreator` ([method org.ossreviewtoolkit.clearlydefined.ClearlyDefinedService$Provider#fromString(1 params)]) expects JSON Object (JsonToken.START_OBJECT), got JsonToken.VALUE_STRING
at [Source: (okhttp3.ResponseBody$BomAwareReader); line: 1, column: 87] (through reference chain: org.ossreviewtoolkit.clearlydefined.ClearlyDefinedService$Curation["described"]->org.ossreviewtoolkit.clearlydefined.ClearlyDefinedService$Described["sourceLocation"]->org.ossreviewtoolkit.clearlydefined.ClearlyDefinedService$SourceLocation["provider"])
@sschuberth sschuberth changed the title "Input mismatch reading Enum" after upgrade top Jackson 2.11 "Input mismatch reading Enum" after upgrade to Jackson 2.11 May 10, 2020
@cowtowncoder cowtowncoder transferred this issue from FasterXML/jackson-databind May 11, 2020
@lpandzic
Copy link

I've encountered this problem with Java too, when using @JsonCreator on factory method of an enum with a String parameter.
Switching to @JsonCreator(mode = JsonCreator.Mode.DELEGATING) fixed the issue.

@sschuberth
Copy link
Author

sschuberth commented May 19, 2020

I've encountered this problem with Java too

So, should this issue still be reported against https://github.com/FasterXML/jackson-databind instead (despite the move of @cowtowncoder)? When looking at the issues over there I wondered whether FasterXML/jackson-databind#2725 is related to this issue.

@cowtowncoder
Copy link
Member

@sschuberth If test can be simplified to only use Java (and ideally just include test class in comment), jackson-databind makes sense. While not certain, I suspect databind 2725 might have different root cause.

sschuberth added a commit to oss-review-toolkit/ort that referenced this issue Jun 29, 2020
See https://github.com/FasterXML/jackson/wiki/Jackson-Release-2.11.1.

This fixes #2796 by applying the work-around described at [1] as our
Jackson version was actually already being upgraded to version 2.11.0
by Gradle via the Antenna dependency.

[1] FasterXML/jackson-module-kotlin#336 (comment)

Signed-off-by: Sebastian Schuberth <[email protected]>
sschuberth added a commit to oss-review-toolkit/ort that referenced this issue Jun 29, 2020
See https://github.com/FasterXML/jackson/wiki/Jackson-Release-2.11.1.

This fixes #2796 by applying the work-around described at [1] as our
Jackson version was actually already being upgraded to version 2.11.0
by Gradle via the Antenna dependency.

[1] FasterXML/jackson-module-kotlin#336 (comment)

Signed-off-by: Sebastian Schuberth <[email protected]>
sschuberth added a commit to oss-review-toolkit/ort that referenced this issue Jun 29, 2020
See https://github.com/FasterXML/jackson/wiki/Jackson-Release-2.11.1.

This fixes #2796 by applying the work-around described at [1] to enums as
our Jackson version was actually already being upgraded to version 2.11.0
by Gradle via the Antenna dependency.

[1] FasterXML/jackson-module-kotlin#336 (comment)

Signed-off-by: Sebastian Schuberth <[email protected]>
sschuberth added a commit to oss-review-toolkit/ort that referenced this issue Jun 29, 2020
See https://github.com/FasterXML/jackson/wiki/Jackson-Release-2.11.1.

This fixes #2796 by applying the work-around described at [1] to enums as
our Jackson version was actually already being upgraded to version 2.11.0
by Gradle via the Antenna dependency.

[1] FasterXML/jackson-module-kotlin#336 (comment)

Signed-off-by: Sebastian Schuberth <[email protected]>
@bentmann
Copy link

If test can be simplified to only use Java

How's that:

package test;

import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonCreator.Mode;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.databind.ObjectMapper;

public class JacksonTest
{
  public enum LinkType
  {
    TEST;

    @JsonCreator(mode = Mode.DEFAULT)
    public static LinkType fromString(@JsonProperty("type") String type) {
      return TEST;
    }
  }

  private final LinkType type;

  @JsonCreator
  public JacksonTest(@JsonProperty("type") LinkType type) {
    this.type = type;
  }

  @Override
  public String toString() {
    return "> " +  type;
  }

  public static void main(String[] args) throws Exception {
    String json = "{\"type\":\"TEST\"}";
    System.out.println(new ObjectMapper().readValue(json, JacksonTest.class));
  }
}

This works as is with Jackson 2.10.x but fails with aforementioned error on Jackson 2.11 unless

  • JsonCreator.Mode.DELEGATING is used or
  • @JsonProperty is dropped from fromString()

Which Jackson version behaves properly?

@cowtowncoder
Copy link
Member

@bentmann thank you! I'll transfer this, have a look.

@cowtowncoder
Copy link
Member

Oh, actually, no. @bentmann Problem here is that example is fundamentally ambiguous at outer level. It could legally be either delegating or properties-based -- of which only delegating can work due to inner definition that is detectable as Properties one (due to addition of @JsonProperty for parameter).
In fact, this requires combination of inner/outer such that exactly one is Delegating, and the other one Properties-based.

In this case, you really should indicate mode for both. This can not be changed to reliably work as-is.
Even if it may have happened to work on 2.10.x: something in heuristics (probably fixes to aspects of Creator detection for Enum) has changed.

@bentmann
Copy link

OK, thanks for the clarification

@bushwakko
Copy link

Is this issue fixed? Or is there another issue to fix it? Because I also have this problem. If I fix one case, the other one breaks, and vice versa.

@cowtowncoder
Copy link
Member

@bushwakko There is nothing that can be fixed here as far as I can see -- single-argument creator must indicate correct binding type: either "properties-based' or "delegating". @lpandzic's answer is correct; @bentmann's example is broken since it defines property-name for argument but expects delegating-style content.

I am not sure what you mean by two cases, but if you mean that you would have to accept both JSON Object and JSON String as values, you will need to implement custom Creator, taking either java.lang.Object (or its counterpart in Kotlin), or JsonNode, specifying Mode.DELEGATING, and using value you get (if Object it is either String or Map; for JsonNode it's either TextNode or ObjectNode).

@OLibutzki
Copy link

OLibutzki commented Jun 9, 2021

@cowtowncoder is there a way to workaround the openapi-generator issue which just uses @JsonCreator on a static enum method to resolve an enum literal from a String? Is it possible to "fix" the heuristics which choose the mode for this particular case or to configure the ObjectMapper accordingly?

@lpandzic
Copy link

lpandzic commented Jun 9, 2021

Today this can be solved with a custom module with a custom annotation introspector similar to SingleArgumentPropertiesCreatorModeAnnotationIntrospector. The one I linked does the necessary steps to determine if the single argument constructor is actually a property based one and tells jackson to mark it as such (SingleArgumentPropertiesCreatorModeAnnotationIntrospectorTest). Similar approach could be used for opposite case - DELEGATING creator one.
Probably a smarter one could be created that would automatically fallback to delegating if it's clearly not a property based one.

The crux of the issue, from my view, is that each object is created through either delegating or property based mode and single argument constructor is a edge case because of historical reasons (pre Java 8 it was very unconventional not to have a (mutable) pojo in your model).
Jackson community as a whole needs to reach a consensus on whether delegating or property based one should be the default one in jackson 3.0.0 and provide clear path for migration for other side.

@cowtowncoder
Copy link
Member

Aside from AnnotationIntrospector @lpandzic explained, Jackson 2.12 also has another way to change defaulting, using ConstructorDetector. It is explained here:

https://cowtowncoder.medium.com/jackson-2-12-most-wanted-3-5-246624e2d3d0

For example:

ObjectMapper mapper = JsonMapper.builder()
    .constructorDetector(ConstructorDetector.USE_PROPERTIES_BASED)
    .build()

@OLibutzki
Copy link

OLibutzki commented Jun 10, 2021

Thanks a lot for the recommendations. I realized that we configured the visibility of fields to be any in the ObjectMapper. That led to the exception. I don't understand why, but removing field visibility any solved it in our scenario... so obvioudly the heuristics take that into account somehow...

@alinagb
Copy link

alinagb commented Jul 27, 2023

Hi, is there any workaround for this? as soon as we have the enum generated i cannot use mode = JsonCreator.Mode.DELEGATING to the JsonCreator. I was trying to add:
mapper.registerModule(new ParameterNamesModule(JsonCreator.Mode.DELEGATING)).readValue(value, clazz), but still it doesn't work

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

7 participants