Skip to content
This repository was archived by the owner on Jan 22, 2019. It is now read-only.

JsonPropertyOrder Inconsistencies with Caps #80

Closed
agrawroh opened this issue Jun 3, 2015 · 7 comments
Closed

JsonPropertyOrder Inconsistencies with Caps #80

agrawroh opened this issue Jun 3, 2015 · 7 comments

Comments

@agrawroh
Copy link

agrawroh commented Jun 3, 2015

Saw some strange behavior of CSVMapper with JsonPropertOrder Annotation while beginning the attribute names with Caps. In below example if I try to build the schema directly from the Example Class then I get 4 Columns instead of 2. It takes "dnacode" & "rbccount" in addition to the given two columns.

@JsonPropertyOrder(value = {"DNACount","RBCCount"})
public class Example {
    private String RBCCount;
    private String DNACode;

    ...getter-setters...
}

Am I doing anything wrong or is this a tiny bug?

@cowtowncoder
Copy link
Member

Property order definitely should not cause addition of any properties, so that sounds like a possible bug.
But a more complete test case would help figuring out what exactly is happening.

@agrawroh
Copy link
Author

agrawroh commented Jun 4, 2015

Hi cowtowncoder,

Thanks for looking into this issue. Just to provide more clarity on what I have been trying, please see the following.

  1. Example Class with private Attributes
    Result: Get two columns "dnacode", "rbccount"
  2. Example Class with public Attributes
    Result: Get four columns "DNACode", "RBCCount", "rbccount", "dnacode"

Please note that sometimes if the columns are more than they do not follow the order in which they were given in the JsonPropertyOrder Annotation.

@cowtowncoder
Copy link
Member

At this point I think I do need a reproducible test case.

@jmax01
Copy link

jmax01 commented Jul 21, 2015

This is related to how Jackson detects fields.

If you have public fields the naive bean accessor naming convention does not produce a match between the field and the declared accessor you will get the behavior you are seeing.
You need to either rename your fields or add @JsonProperty annotations to your getters.

Couple things:

  • Following proper naming conventions for fields for example DNACount should be named dnaCount
    • If you need the CVS headers to be cased a special way then add @JsonProperty attributes to those fields.
  • Accessor methods of with acronyms in the name should be camel case e.g. getDnaCount
//Workaround example:
    @JsonPropertyOrder({ "DNACount", "RBCCount" })
    public static class BloodCount {

        public String DNACount;

        public String RBCCount;

        //Add this to accessor
        @JsonProperty("DNACount")
        public String getDNACount() {
            return this.DNACount;
        }

        public void setDNACount(String dnaCount) {
            this.DNACount = dnaCount;
        }

        //Add this to accessor
        @JsonProperty("RBCCount")
        public String getRBCCount() {
            return this.RBCCount;
        }

        public void setRBCCount(String rbcCount) {
            this.RBCCount = rbcCount;
        }
    }

@jmax01
Copy link

jmax01 commented Jul 21, 2015

There is another issue with regard to capitalization that happens regardless of the public or private status of the field.

Fields with a single character acronyms are duplicated since Jackson fails to match the eTradeId field against getETradeId() method.

Note that the eTradeId field is duplicated in the output with the etradeId as the header name:

    @JsonPropertyOrder({ "E-Trade ID", "MY-Trade ID" })
    public static class EtradeAccount {

        @JsonProperty("E-Trade ID")
        private final String eTradeId;

        @JsonProperty("MY-Trade ID")
        private final String myTradeId;

        @JsonCreator
        public EtradeAccount(String eTradeId, String myTradeId) {
            super();
            this.eTradeId = eTradeId;
            this.myTradeId = myTradeId;
        }

        public String getETradeId() {
            return this.eTradeId;
        }

        public String getMyTradeId() {
            return this.myTradeId;
        }

    }

   @Test
    public void jacksonCsvCapTest() throws IOException {

        final CsvMapper csvMapper = new CsvMapper();

        final EtradeAccount etradeAccount = new EtradeAccount("eTradeIdValue", "myTradeValue");

        final EtradeAccount[] etradeAccounts = { etradeAccount };

        try (StringWriter writer = new StringWriter()) {
            csvMapper.writer(csvMapper.schemaFor(EtradeAccount.class)
                .withHeader())
                .writeValues(writer)
                .writeAll(etradeAccounts);

            final String etradeAccountCSV = writer.toString();

            /*
             * Returns:
             * "E-Trade ID","MY-Trade ID",etradeId
             * eTradeIdValue,myTradeValue,eTradeIdValue
             */
            System.out.println(etradeAccountCSV);
        }
    }

@cowtowncoder
Copy link
Member

One related feature is MapperFeature.USE_STD_BEAN_NAMING (added in 2.5). It specifically affects handling of property names where more than one of initial letters is upper-case: when disabled (default, behavior for 2.4 and before), all leading upper-case letters are lower case (so "getETradeId" would imply "etradeId"); when enabled, as per Java Bean spec, would imply "ETradeId" (only lower-casing a single upper-case leading letter). Neither would do fuzzy matching with hyphens.

Note, too, that @JsonPropertyOrder allows both renamed name (from @JsonProperty) and implied bean property name.

In your example, problem comes from the fact that no getter/setter name can ever imply property name of "eTradeId"; there is no convention that produces this. If such a name is needed, additional @JsonProperty is needed to link all accessors (including creator parameter name).

An alternative would be registering custom NamingStrategy which could use different name mangling, and it would allow avoiding annotations.

@cowtowncoder
Copy link
Member

At this point I don't see a problem that is specific to CSV module. It is possible that there is a naming issue with standard jackson-databind; if so, a reproduction with JSON there would be good.

Alternatively it could be that issue #96 was at work here; if so, I fixed that for 2.6.5 / 2.7.0.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants