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

SnakeCaseStrategy causes unexpected MismatchedInputException during deserialization #3368

Closed
sszuev opened this issue Jan 11, 2022 · 4 comments
Milestone

Comments

@sszuev
Copy link

sszuev commented Jan 11, 2022

The following test (TestStructureWithSnakeNames.java.txt) works fine in 2.12.0 :

import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.PropertyNamingStrategies;
import com.fasterxml.jackson.databind.annotation.JsonNaming;

import java.util.Map;

@JsonNaming(PropertyNamingStrategies.SnakeCaseStrategy.class)
public class TestStructure {
    private String timeZone;
    private String utcZone;

    @JsonProperty("time_zone")
    private void unpackTimeZone(Map<String, String> timeZone) {
        this.setTimeZone(timeZone.get("name"));
        this.setUtcZone(timeZone.get("utc_zone"));
    }

    public String getTimeZone() {
        return this.timeZone;
    }

    public String getUtcZone() {
        return this.utcZone;
    }

    public void setTimeZone(String timeZone) {
        this.timeZone = timeZone;
    }

    public void setUtcZone(String utcZone) {
        this.utcZone = utcZone;
    }

    public static class DeserializationTest {
        public static void main(String... args) throws Exception {
            ObjectMapper objectMapper = new ObjectMapper();
            System.out.println(objectMapper.version());
            String test = "    {\n" +
                    "      \"time_zone\": {\n" +
                    "        \"name\": \"XXX\",\n" +
                    "        \"utc_zone\": \"ZZZ\"\n" +
                    "      }\n" +
                    "    }";
            TestStructure res = objectMapper.readerFor(new TypeReference<TestStructure>() {
            }).readValue(test);
            assert "XXX".equals(res.getTimeZone()) : "wrong time"; // use `java -ea ...` when run
            assert "ZZZ".equals(res.getUtcZone()) : "wrong zone";
            System.out.println("DONE");
        }
    }
}

But after switching to 2.12.1 (and later) I see the error :

Exception in thread "main" com.fasterxml.jackson.databind.exc.MismatchedInputException: Cannot deserialize value of type `java.lang.String` from Object value (token `JsonToken.START_OBJECT`)
 at [Source: (String)"    {
      "time_zone": {
        "name": "XXX",
        "utc_zone": "ZZZ"
      }
    }"; line: 2, column: 20] (through reference chain: TestStructure["time_zone"])
	at com.fasterxml.jackson.databind.exc.MismatchedInputException.from(MismatchedInputException.java:59)
	at com.fasterxml.jackson.databind.DeserializationContext.reportInputMismatch(DeserializationContext.java:1741)
	at com.fasterxml.jackson.databind.DeserializationContext.handleUnexpectedToken(DeserializationContext.java:1515)
	at com.fasterxml.jackson.databind.DeserializationContext.handleUnexpectedToken(DeserializationContext.java:1420)
	at com.fasterxml.jackson.databind.DeserializationContext.extractScalarFromObject(DeserializationContext.java:932)
	at com.fasterxml.jackson.databind.deser.std.StringDeserializer.deserialize(StringDeserializer.java:62)
	at com.fasterxml.jackson.databind.deser.std.StringDeserializer.deserialize(StringDeserializer.java:11)
	at com.fasterxml.jackson.databind.deser.impl.MethodProperty.deserializeAndSet(MethodProperty.java:129)
	at com.fasterxml.jackson.databind.deser.BeanDeserializer.vanillaDeserialize(BeanDeserializer.java:313)
	at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserialize(BeanDeserializer.java:176)
	at com.fasterxml.jackson.databind.deser.DefaultDeserializationContext.readRootValue(DefaultDeserializationContext.java:322)
	at com.fasterxml.jackson.databind.ObjectReader._bindAndClose(ObjectReader.java:2051)
	at com.fasterxml.jackson.databind.ObjectReader.readValue(ObjectReader.java:1492)
	at TestStructure$DeserializationTest.main(TestStructure.java:47)

Since the similar test with normal names (TestStructureWithNormalNames.java.txt) works well in 2.12.0, 2.12.1 and 2.13.1, I suspect this behavior could be a bug.

@sszuev sszuev added the to-evaluate Issue that has been received but not yet evaluated label Jan 11, 2022
@cowtowncoder
Copy link
Member

Looks like test relies on something like Lombok, so I cannot run test as-is. Would it be possible to get a version where Lombok has processed accessors (getters, setters) so I can verify behavior?

Also this seems to be a manual test, not unit test, so it probably should check contents: but that's fine for now since there is exception.

@cowtowncoder cowtowncoder added lombok Issue (likely) related to use of Lombok and removed to-evaluate Issue that has been received but not yet evaluated labels Jan 12, 2022
@sszuev
Copy link
Author

sszuev commented Jan 12, 2022

Looks like test relies on something like Lombok, so I cannot run test as-is. Would it be possible to get a version where Lombok has processed accessors (getters, setters) so I can verify behavior?

Also this seems to be a manual test, not unit test, so it probably should check contents: but that's fine for now since there is exception.

Not sure this can be called a manual test, but yes, this is just a demo, shortened and cleaned up for demonstration, not a real unit-test.
Ok, I replaced @lombok.Getter and @lombok.Setter with real setters and getters, and, also, remove the package and insert assert for more correct checkings. I hope this helps.
(But no, it seems lombok has nothing to do with it. I used it here here just to make the report shorten).

Also, just in case, java-versions, tried:

java version "14.0.2" 2020-07-14
Java(TM) SE Runtime Environment (build 14.0.2+12-46)
Java HotSpot(TM) 64-Bit Server VM (build 14.0.2+12-46, mixed mode, sharing)
java version "11.0.9" 2020-10-20 LTS
Java(TM) SE Runtime Environment 18.9 (build 11.0.9+7-LTS)
Java HotSpot(TM) 64-Bit Server VM 18.9 (build 11.0.9+7-LTS, mixed mode)

@cowtowncoder
Copy link
Member

Ok so the problem is due to conflict between setTimeZone() and unpackTimeZone() which uses renaming.
So a safe work-around here would be to add @JsonIgnore on "setTimeZone()".
Ideally this should not be needed, however, since in this case unpackTimeZone() does have explicit annotation and should have precedence.
Change in behavior might have come from the fix to #2979.

I hope to see if there's a chance this could be resolved, but in the meantime I would suggest use of @JsonIgnore.

@cowtowncoder cowtowncoder changed the title SnakeCaseStrategy causes unexpected MismatchedInputException while deserialization SnakeCaseStrategy causes unexpected MismatchedInputException during deserialization Jan 19, 2022
@cowtowncoder cowtowncoder added 2.13 and removed lombok Issue (likely) related to use of Lombok labels Jan 19, 2022
@cowtowncoder cowtowncoder added this to the 2.13.0 milestone Jan 19, 2022
@cowtowncoder
Copy link
Member

Ok, cool. Turns out this was not difficult to fix, reworking the fix for #2979. Fix will be in 2.13.2 whenever that is released.

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

2 participants