Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Jackson: final field written to after it is set by @JsonCreator?

It seems Jackson uses reflection to write additional attributes directly into fields even if a @JsonCreator constructor was used and the field is marked as final.

Example:

public class Test {
    static class X {
        final String s;

        @JsonCreator
        public X(@JsonProperty("a") String a) {
            s = "s";
        }

        public String getS() {
            return s;
        }
    }

    @org.junit.Test
    public void ds() throws Exception {
        ObjectMapper om = new ObjectMapper();
        X x = om.readValue("{`a`:``, `s`: `t`}".replace('`', '"'), X.class);
        assertEquals("s", x.s);
    }
}

The assert will fail with org.junit.ComparisonFailure: expected:<[s]> but was:<[t]>.

Is this behavior documented anywhere? Is there anyway to disable this globally?

Also, I think this is a very dangerous design: if there are some value that should be read-only to the client, this effectively allows the client to set them even if the class is well designed according to normal immutable class guidelines.

like image 972
billc.cn Avatar asked Nov 18 '25 21:11

billc.cn


1 Answers

First: yes, Jackson allows deserialization of all visible and not just those for which @JsonCreator property exists. So it is possible to set a smaller set of properties via constructor, and others via setters or fields. This may be needed for some cases like cyclic types.

As to how to prevent use of s for deserialization here. An obvious way is to add @JsonIgnore for field, although if so you will also need @JsonProperty for getS() to avoid both being removed.

But there are other settings as well, in MapperFeature.

  • ALLOW_FINAL_FIELDS_AS_MUTATORS: if you disable this, final fields are never used directly for deserialization
  • INFER_PROPERTY_MUTATORS: if you disable this, then neither fields nor setters are "pulled in" in cases where they are not otherwise visible (for fields, public is needed to be visible; for setters, even private is fine)

So may want to disable one or both settings.

like image 191
StaxMan Avatar answered Nov 21 '25 10:11

StaxMan