FasterXML / jackson-modules-java8

Set of support modules for Java 8 datatypes (Optionals, date/time) and features (parameter names)
Apache License 2.0
399 stars 116 forks source link

Annotating parameters when using parameter names module #264

Closed gmellemstrand closed 1 year ago

gmellemstrand commented 1 year ago

I ran into something unexpected when I wanted to started using the parameters module in an existing project. It was a bit unexpected, so I'm wondering if this is the intended behaviour.

I have this class that I want to serialize. I realize this class is not using the actual parameter names functionality.

public class TestClass {

    private String name;

    private String address;

    private TestClass(
        String name,
        String address
    ) {
        this.name = name;
        this.address = address;
    }

    @JsonCreator(mode = JsonCreator.Mode.PROPERTIES)
    public static TestClass create(
        @JsonProperty("_name") String name,
        @JsonProperty("_address") String address
    ) {
        return new TestClass(name, address);
    }

    @JsonProperty
    public String getName() {
        return name;
    }

    @JsonProperty
    public String getAddressNewName() {
        return address;
    }
}

I then test the class using the following code:

    public void testSerialization() throws JsonProcessingException {
        ObjectMapper mapper = new ObjectMapper();
        mapper.registerModule(new ParameterNamesModule());

        String input = "{\n"
            + "    \"_name\": \"name\",\n"
            + "    \"_address\": \"address\""
            + "}";

        TestClass testClass = mapper.readValue(input, TestClass.class);

        String result = mapper.writeValueAsString(testClass);

        System.out.println(result);
    }

When not using the parameters module, the fields would be serialized by the names of their getters (name, addressNewName). However, when I turn the parameters module on, they get the names _name and addressNewName. It seems like if the getter has the same name as the field, the JsonProperty annotation from the parameter is used instead.

cowtowncoder commented 1 year ago

Yes, this is bit non-intuitive but sort of expected behavior from implementation perspective.

The reason being that without module, parameter names do not have any "implicit" name -- and so the only name known is that from @JsonProperty. Hence they cannot be linked with getter names. Basically you have 4 properties (2 of each "real" properties) -- although since there is no way to serialize something for which there is only creator parameter, only 2 are serialized. With module, however, "implicit" names are found and now properties can be linked; so getters and creator parameters only induce 2 properties. Those are then renamed as per @JsonProperty on creator parameters.