Jackson-databind: PropertyNamingStrategy.UPPER_CAMEL_CASE for a private attribute which name starts with more than one uppercase letter

Created on 14 Nov 2017  路  3Comments  路  Source: FasterXML/jackson-databind

PropertyNamingStrategy.UPPER_CAMEL_CASE doesn't work as expected when a property name should start with more than one uppercase letter (e.g. BADNamingStrategy) and the corresponding attribute is _private_ (which means that the property name is derived from the getter method)

The following test demonstrates that issue.

package org.me.jackson;

import static org.hamcrest.MatcherAssert.*;
import static org.hamcrest.CoreMatchers.*;

import org.junit.Test;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.PropertyNamingStrategy;

public class JacksonUpperCaseSerializationTest {

    ObjectMapper om = new ObjectMapper()
            .setPropertyNamingStrategy(PropertyNamingStrategy.UPPER_CAMEL_CASE);

    public static class Entity {
        // expected property name: BADPublicName
        public boolean bADPublicName = true;

        // expected property name: BADPrivateName, actual: BadprivateName
        private boolean privatePropertyNameDoesntMatter = true;

        public boolean getBADPrivateName() {
            return privatePropertyNameDoesntMatter;
        }

        public void setBADPrivateName(boolean bADPrivateName) {
            this.privatePropertyNameDoesntMatter = bADPrivateName;
        }
    }

    @Test
    public void testSerialization() throws Exception {
        final String json = om.writeValueAsString(new Entity());
        assertThat(json, containsString("BADPublicName"));

        // this one fails: it contains BadprivateName instead
        assertThat(json, containsString("BADPrivateName"));
    }

    @Test
    public void testDeserialization() throws Exception {        
        final String json = "{\"BADPublicName\":false,\"BADPrivateName\":false}";

        // here it says that it has only (2 known properties: "BADPublicName", "BadprivateName"])
        final Entity entity = om.readValue(json, Entity.class); 

        assertThat(entity.bADPublicName, is(false));
        assertThat(entity.getBADPrivateName(), is(false));
    }

}

This is related to the version 2.8.9

Most helpful comment

Ahhh. This is actually due to one minor (usually) deviation Jackson has from Bean naming: if multiple leading letters are upper-case, Jackson lower-cases them all (by default), so "BADxxx" becomes "badxxx". But upper case strategy only upper-cases the first letter, leading to problem here.
This behavior can be changed by:

mapper.enable(MapperFeature.USE_STD_BEAN_NAMING)

which is disabled by default; doing this will solve the problem.
And 3.0.0 has this behavior as default (2.x does not just for backwards compatibility).

So, you need to enable this feature.

All 3 comments

I don't think private field should have any effect here since it is not associated with getter/setter name, as far as I can see. Those names must link for any association.

But other than that, code looks like it should work.

... and when I try it, tests pass for me.

Hmmh. Odd. Test passed with master (for 3.0.0-SNAPSHOT) but not with 2.9 branch, and likely also fails with 2.8.

Ahhh. This is actually due to one minor (usually) deviation Jackson has from Bean naming: if multiple leading letters are upper-case, Jackson lower-cases them all (by default), so "BADxxx" becomes "badxxx". But upper case strategy only upper-cases the first letter, leading to problem here.
This behavior can be changed by:

mapper.enable(MapperFeature.USE_STD_BEAN_NAMING)

which is disabled by default; doing this will solve the problem.
And 3.0.0 has this behavior as default (2.x does not just for backwards compatibility).

So, you need to enable this feature.

Was this page helpful?
0 / 5 - 0 ratings