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

@JsonProperty-ies are ignored on @JsonCreator and getters are used instead, and inconsistent behavior with ParameterNamesModule module #1924

Open
zshamrock opened this Issue Feb 3, 2018 · 4 comments

Comments

Projects
None yet
2 participants
@zshamrock
Copy link

zshamrock commented Feb 3, 2018

There are possibly two different separate things, but at least makes sense to file them together for now to discuss. Not sure whether the first case is the expected/known behavior, or bug, but also, please see to the second case, that it is somehow related.

Consider the following class:

public class Address {
    private final String country;
    private final String city;

    @JsonCreator
    public Address(@JsonProperty("cntr") final String country, 
                   @JsonProperty("ct") final String city) {
        this.country = country;
        this.city = city;
    }

    public String getCountry() {
        return country;
    }

    public String getCity() {
        return city;
    }

    @Override
    public String toString() {
        return "Address{" +
                "country='" + country + '\'' +
                ", city=" + city +
                '}';
    }
}

and the test class:

public class JacksonTest {
    public static void main(final String[] args) throws IOException {
        final ObjectMapper mapper = new ObjectMapper();
        // mapper.registerModule(new ParameterNamesModule()); (1) <-- 
        // This will be mentioned in the second case

        final Address address = mapper.readValue("{\"country\":\"1\", \"city\":\"2\"}", 
            Address.class);
        System.out.println(address);
    }
}

So, when trying to deserialize "{\"country\":\"1\", \"city\":\"2\"}, while @JsonProperty-ies have names like cntr and ct, I would expect deserialization to fail, although it deserializes without any problems and produces Address{country='1', city=2}, and by passing constructor, i.e. constructor is not called. So I assume Jackson inspects the fields (or getters), removes final modifier, and assigns the values into there.

Although, and this is the second case, if enable ParameterNamesModule module, by uncommenting line (1) above (and compiling with -parameters), then deserialization fails as expected with the following errors below.

On Jackson 2.7.5, 2.8.10, 2.8.11 it fails with:

Exception in thread "main" com.fasterxml.jackson.databind.exc.UnrecognizedPropertyException: Unrecognized field "country" (class jackson.Address), not marked as ignorable (2 known properties: "cntr", "ct"])
 at [Source: {"country":"1", "city":"2"}; line: 1, column: 28] (through reference chain: jackson.Address["country"])
	at com.fasterxml.jackson.databind.exc.UnrecognizedPropertyException.from(UnrecognizedPropertyException.java:62)
	at com.fasterxml.jackson.databind.DeserializationContext.handleUnknownProperty(DeserializationContext.java:834)
	at com.fasterxml.jackson.databind.deser.std.StdDeserializer.handleUnknownProperty(StdDeserializer.java:1093)
	at com.fasterxml.jackson.databind.deser.BeanDeserializerBase.handleUnknownProperty(BeanDeserializerBase.java:1489)
	at com.fasterxml.jackson.databind.deser.BeanDeserializerBase.handleUnknownProperties(BeanDeserializerBase.java:1443)
	at com.fasterxml.jackson.databind.deser.BeanDeserializer._deserializeUsingPropertyBased(BeanDeserializer.java:487)
	at com.fasterxml.jackson.databind.deser.BeanDeserializerBase.deserializeFromObjectUsingNonDefault(BeanDeserializerBase.java:1191)
	at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserializeFromObject(BeanDeserializer.java:314)
	at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserialize(BeanDeserializer.java:148)
	at com.fasterxml.jackson.databind.ObjectMapper._readMapAndClose(ObjectMapper.java:3814)
	at com.fasterxml.jackson.databind.ObjectMapper.readValue(ObjectMapper.java:2858)
	at jackson.JacksonTest.main(JacksonTest.java:13)

On the latest Jackson 2.9.4 it fails as well, but the error is different:

Exception in thread "main" java.lang.NoSuchMethodError: com.fasterxml.jackson.core.JsonStreamContext.<init>(Lcom/fasterxml/jackson/core/JsonStreamContext;)V
	at com.fasterxml.jackson.databind.util.TokenBufferReadContext.<init>(TokenBufferReadContext.java:47)
	at com.fasterxml.jackson.databind.util.TokenBufferReadContext.createRootContext(TokenBufferReadContext.java:91)
	at com.fasterxml.jackson.databind.util.TokenBuffer$Parser.<init>(TokenBuffer.java:1298)
	at com.fasterxml.jackson.databind.util.TokenBuffer.asParser(TokenBuffer.java:276)
	at com.fasterxml.jackson.databind.util.TokenBuffer.asParser(TokenBuffer.java:242)
	at com.fasterxml.jackson.databind.deser.BeanDeserializerBase.handleUnknownProperties(BeanDeserializerBase.java:1531)
	at com.fasterxml.jackson.databind.deser.BeanDeserializer._deserializeUsingPropertyBased(BeanDeserializer.java:504)
	at com.fasterxml.jackson.databind.deser.BeanDeserializerBase.deserializeFromObjectUsingNonDefault(BeanDeserializerBase.java:1280)
	at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserializeFromObject(BeanDeserializer.java:326)
	at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserialize(BeanDeserializer.java:159)
	at com.fasterxml.jackson.databind.ObjectMapper._readMapAndClose(ObjectMapper.java:4001)
	at com.fasterxml.jackson.databind.ObjectMapper.readValue(ObjectMapper.java:2992)
	at jackson.JacksonTest.main(JacksonTest.java:13)

So, my expectation is that also without ParameterNamesModule, but with the explicit names in the @JsonProperty I would expect the same error to happen, as I believe conceptually these 2 cases are the same/similar.

@zshamrock zshamrock changed the title @JsonProperty-ies are ignored on @JsonCreator and getters are used instead, and inconsistent behavior @JsonProperty-ies are ignored on @JsonCreator and getters are used instead, and inconsistent behavior with ParameterNamesModule module Feb 3, 2018

@zshamrock

This comment has been minimized.

Copy link

zshamrock commented Feb 3, 2018

These are the dependencies used:

        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-annotations</artifactId>
            <version>${jackson.version}</version>
        </dependency>

        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-databind</artifactId>
            <version>${jackson.version}</version>
        </dependency>

        <dependency>
            <groupId>com.fasterxml.jackson.module</groupId>
            <artifactId>jackson-module-parameter-names</artifactId>
            <version>${jackson.version}</version>
        </dependency>

where I've tried with 2.7.5, 2.8.10, 2.8.11, and 2.9.4 as the jackson.version as described in the issue.

@cowtowncoder

This comment has been minimized.

Copy link
Member

cowtowncoder commented Feb 5, 2018

One quick note: 2.9.4 error is due to incompatible versions: it seems like somehow version of jackson-core is wrong: constructor mentioned was added in 2.9. So that masks the real problem.

As to problem itself, that is quite interesting; but I'd like to see 2.9 behavior first.
I agree behavior does not seem right.

@zshamrock

This comment has been minimized.

Copy link

zshamrock commented Feb 7, 2018

@cowtowncoder you are right. I've tried the isolated project with only Jackson dependencies there, and with the 2.9.4 now I get the same error as with 2.8.10 version.

So, what we have now is that explicit @JsonCreator and @JsonProperty-ies are ignored, but fails when register ParameterNamesModule module.

@cowtowncoder

This comment has been minimized.

Copy link
Member

cowtowncoder commented Feb 20, 2018

Ok. So if I understand situation correctly, it is possible that one setting might help:

MapperFeature.ALLOW_FINAL_FIELDS_AS_MUTATORS

which is enabled by default (for backwards compatibility); disabling that might help here.
Reasons for behavior that you observe are bit complicated, but basically difference is that without parameter names module, the original name of parameters is not known, and thus explicit name is recognized as the only one.
Adding parameter names exposes original "implicit" name, which in turn may be the reason why otherwise private fields are "pulled in".
Latter behavior may also be disabled with:

MapperFeature.INFER_PROPERTY_MUTATORS

and finally, in some cases adding ignoral for undesired names may also hide exception: ignoring meaning roughly "it's fine if these are seen but just ignore them".
And if that is not what you want, you may want to disable:

DeserializationFeature.FAIL_ON_IGNORED_PROPERTIES

I hope this helps.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment