Tom
Tom

Reputation: 4161

Asymmetric name/property mapping with Jackson, more elegant solution?

we consume an API with our backend that outputs camelCased properties, map this to POJOs, to apply some business logic and then output it with our API to some apps. The format we want to output is snake_case properties.

This test describes what we want to do:

@Test
public void mappingTest() throws IOException {
    String input = "{ \"merchantId\": 23, \"contactName\": \"foobar\" }";

    ObjectMapper mapper = new ObjectMapper();
    Merchant merch = mapper.readValue(input, Merchant.class);

    String output = mapper.writeValueAsString(merch);

    String expectedOutput = "{ merchant_id: 23, contact_name: 'foobar' }";
    assertEquals("", expectedOutput, output);
}

At the moment the model class looks like this:

@JsonInclude(Include.NON_NULL)
public class Merchant {

    private String merchantId;
    private String contactName;

    public Merchant() {
    }

    public Merchant(final String merchantId, final String contactName) {
        this.merchantId = merchantId;
        this.contactName = contactName;
    }

    @JsonProperty("contact_name")
    public String getContactName() {
        return contactName;
    }

    @JsonProperty("contactName")
    public void setContactName(final String contactName) {
        this.contactName = contactName;
    }

    @JsonProperty("merchant_id")
    public String getMerchantId() {
        return merchantId;
    }

    @JsonProperty("merchantId")
    public void setMerchantId(final String merchantId) {
        this.merchantId = merchantId;
    }
}

It works but I think it's not very elegant since our input is always camelcase and the output is always snakecase. Is there a way to globally set JSON serialization to snakecase and deserialization to camelcase for jackson? (we are using it together with RestTemplate in Spring, if that makes any difference)

Cheers

Upvotes: 3

Views: 139

Answers (2)

Use a separately configured ObjectMapper for your output:

ObjectMapper outputMapper = new ObjectMapper();
outputMapper.setPropertyNamingStrategy(PropertyNamingStrategy.SNAKE_CASE);

Using that for writing the output ensures that properties are always written in snake case.

Or if you need to use only a single ObjectMapper instance, create your own forwarding ProptertyNamingStrategy:

PropertyNamingStrategy myStrategy = new PropertyNamingStrategy() {
    @Override
    public String nameForGetterMethod(MapperConfig<?> config, AnnotatedMethod method, String defaultName) {
        return PropertyNamingStrategy.SNAKE_CASE.nameForGetterMethod(config, method, defaultName);
    }

    @Override
    public String nameForSetterMethod(MapperConfig<?> config, AnnotatedMethod method, String defaultName) {
        return PropertyNamingStrategy.LOWER_CAMEL_CASE.nameForSetterMethod(config, method, defaultName);
    }
};

Upvotes: 0

Andremoniy
Andremoniy

Reputation: 34920

You can implement and register your own PropertyNamingStrategy where define different logic for public String nameForGetterMethod(...) and public String nameForSetterMethod(...) methods respectively.

Upvotes: 2

Related Questions