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

PropertyNamingStrategy doesn't work during deserialization #1832

Closed
unlimitedsola opened this issue Nov 20, 2017 · 6 comments
Closed

PropertyNamingStrategy doesn't work during deserialization #1832

unlimitedsola opened this issue Nov 20, 2017 · 6 comments

Comments

@unlimitedsola
Copy link
Contributor

simple kotlin snippet to reproduce:

class JacksonTest {

    @Test
    fun testSnakeCaseDeserialization() {
        val json = """{"my_camel_case":10001}"""
        val objectMapper = jacksonObjectMapper().findAndRegisterModules()
        val obj = objectMapper.readValue<TestSnakeCase>(json)
        println(obj)
        assertEquals(10001, obj.myCamelCase)
    }

    @Test
    fun testSnakeCaseSerialization() {
        val objectMapper = jacksonObjectMapper().findAndRegisterModules()
        val obj = TestSnakeCase(10001)
        println(objectMapper.writeValueAsString(obj))
    }

    @JsonNaming(PropertyNamingStrategy.SnakeCaseStrategy::class)
    data class TestSnakeCase(val myCamelCase: Int)
}

also happens in Java

@cowtowncoder
Copy link
Member

Please re-file at Kotlin module unless reproducible with Java-only test. If latter, please update with Java-only example here and I can have a look.

@unlimitedsola
Copy link
Contributor Author

@cowtowncoder Sorry for that I thought kotlin code may contain less boilerplate code
Here is a test case in Java

public class JacksonJavaTest {

    @Test
    public void testSnakeCaseDeserialization() throws IOException {
        String json = "{\"my_camel_case\":10001}";
        ObjectMapper objectMapper = new ObjectMapper().findAndRegisterModules();
        TestSnakeCase obj = objectMapper.readValue(json, TestSnakeCase.class);
        assertEquals(Integer.valueOf(10001), obj.getMyCamelCase());
    }

    @Test
    public void testSnakeCaseSerialization() throws JsonProcessingException {
        ObjectMapper objectMapper = new ObjectMapper().findAndRegisterModules();
        TestSnakeCase obj = new TestSnakeCase(10001);
        System.out.println(objectMapper.writeValueAsString(obj));
    }

    @JsonNaming(PropertyNamingStrategy.SnakeCaseStrategy.class)
    static class TestSnakeCase {
        private Integer myCamelCase;

        @JsonCreator
        public TestSnakeCase(Integer myCamelCase) {
            this.myCamelCase = myCamelCase;
        }

        public Integer getMyCamelCase() {
            return myCamelCase;
        }

        public void setMyCamelCase(Integer myCamelCase) {
            this.myCamelCase = myCamelCase;
        }
    }

}

@unlimitedsola
Copy link
Contributor Author

It looks like the PropertyNamingStrategy only works with no-arg-constructor because the following test won't fail:

public class JacksonJavaTest {

    @Test
    public void testSnakeCaseDeserialization() throws IOException {
        String json = "{\"my_camel_case\":10001}";
        ObjectMapper objectMapper = new ObjectMapper().findAndRegisterModules();
        TestSnakeCase obj = objectMapper.readValue(json, TestSnakeCase.class);
        assertEquals(Integer.valueOf(10001), obj.getMyCamelCase());
    }

    @Test
    public void testSnakeCaseSerialization() throws JsonProcessingException {
        ObjectMapper objectMapper = new ObjectMapper().findAndRegisterModules();
        TestSnakeCase obj = new TestSnakeCase(10001);
        System.out.println(objectMapper.writeValueAsString(obj));
    }

    @JsonNaming(PropertyNamingStrategy.SnakeCaseStrategy.class)
    static class TestSnakeCase {
        private Integer myCamelCase;

        public TestSnakeCase() {
        }

        public TestSnakeCase(Integer myCamelCase) {
            this.myCamelCase = myCamelCase;
        }

        public Integer getMyCamelCase() {
            return myCamelCase;
        }

        public void setMyCamelCase(Integer myCamelCase) {
            this.myCamelCase = myCamelCase;
        }
    }

}

@cowtowncoder
Copy link
Member

Actually I think problem here could be bit different.

But first the usual question: which version is this with? Is it reproducible on 2.9.2?
(there were changes in 2.9.2 in this are I think)

If yes, does using

@JsonCreator(mode = JsonCreator.Mode.PROPERTIES)

make difference? It should as by default I think mode would be auto-detected as Mode.DELEGATING (since it is exactly one argument and no property name is defined).

@unlimitedsola
Copy link
Contributor Author

Oops, This is interesting, I didn't notice it only happens on POJO that has exactly one property.
add @JsonCreator(mode = JsonCreator.Mode.PROPERTIES) and everything works fine. Thanks!

@cowtowncoder
Copy link
Member

@unlimitedsola Yes this is.... sort of unfortunate thing, and commonly stumbled upon. So there are two interpretations here: with just 1 property, one could either consider mapping exact value ("delegating"), or JSON Object of just one property ("property-based"). Jackson tries to use heuristics if not explicitly specified but I don't think there is anything that can ultimately tell it, short of allowing configuration for defaulting (mode used if not annotated) and allowing overrides.

mode property was added to allow explicit annotation: if you had added explicit name annotation with @JsonProperty this would also have happened. It is only ambiguous if name is derived from bytecode.

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