3

I've used Jackson for years, and I am not sure I ever faced this issue.

Using Jackson 2.12.5 in a Spring Boot 2.5.5 project, I have an object that I need to serialize. I have no issue with other fields, but these 2 fields are causing me problems :

@Jacksonized
@Builder
@Getter
public class ComputationResult {
  
  private final String pId;

  private final String cId;

  ... other fields ignored

} 

As you can see, I am also using Lombok annotations. When "delombokized", the getters are :

  public String getPId() {
    return this.pId;
  }

  public String getCId() {
    return this.cId;
  }

when serializing the POJO, I expect the field names to be "pId" and "cId", but they are not : I get "pid" and "cid", all lower-case. I don't have the problem with other fields, for which the case is respected.

It caused me an issue because I need to serialize then deserialize the POJO, and the deserialization failed because it could not map "cid" json field to "cId" java field.

There are various workarounds (I am using @JsonAlias("cid") on the field to allow the deserialization), but I am puzzled : is this an expected behavior by Jackson ? does it process String fields differently depending on their length ? or is it a java beans convention that I am not aware of ?

Is there a property to set in the objectMapper to "fix" the behavior, without implementing my own com.fasterxml.jackson.databind.PropertyNamingStrategy ?

Vincent F
  • 6,523
  • 7
  • 37
  • 79

1 Answers1

1

The problem seems to be caused by how JavaBeans methods get generated when there's a single lowercase character at the beginning of the property name. You might be surprised by the fact that getpId and getcId are indeed correctly named, just as I was.

In short, pId correctly results in the getter getpId rather than the Lombok-generated getPId (the one JavaBeans should have kept, in my opinion).

Now, the interesting part is that Jackson makes cid and pid out of getCId and getPId, respectively, for some reason... while at the same time producing cId and pId for getcId and getpId.

So while getcId and getpId are a quirk of JavaBeans, it seems that Jackson is behaving correctly by default, when the getters are correctly named, i.e., getpId -> "pId" and getcId -> "cId".
Given that Lombok generates getPId and getCId, which lead to the all-lowercase keys in the resulting JSON, deserialization does not work.

If you don't like the getpId/getcId naming, then you may have to write your own getters and force a property name explicitly:

@Builder
@Jacksonized
class ComputationResult {

    private final String pId;
    private final String cId;

    @JsonProperty("pId")
    public String getPId() {
        return pId;
    }

    @JsonProperty("cId")
    public String getCId() {
        return cId;
    }
}

For the setters, you already have to rely on @Jacksonized because of final fields anyway, so it doesn't make a difference. Just note that @Getter has to be omitted because it'd result in duplicate properties (with the other kind of naming, that is).

ernest_k
  • 44,416
  • 5
  • 53
  • 99