Customizing enum constant names with Jackson
Asked Answered
W

1

15

I have an enum defined as

public enum Locale {
  EN_US, ES_MX
}

These locale, however, are written as lowercase strings with hyphen as en-us and es-mx in data.

Is there a way to map these lowercase strings to corresponding enum constants? Like en-us to EN_US?

EDIT Let me provide more information. I have an object of the following class.

public class Song {
  private Map<Locale, String> songName;
  private int durationMillis;
}

A song's name can vary by Locale. So I create a map for the song's name in various Locales.

I have a JSON file with info on songs. It reads like:

{
  "songs": [
    {
      "songName": {"en-us":"Song name in US english", "es-mx": "Song name in Spanish"},
      "durationMillis": 100000
    },
    {
      "songName": {"en-us": "another song name -  English"},
      "durationMillis": 200000
    }
  ]
}

I define another class.

public class Songs {
  private Set<Song> songs;
}

I use FasterXml's ObjectMapper to load the JSON as an object of Songs class.

Songs songs = objectMapper.readValue(jsonStr, Songs.class);

This above line crashed right now because ObjectMapper cannot map en-us string to Locale.EN_US.

I can always edit the enum and define it as

public enum Locale {
  EN_US("en-us"),
  ES_MX("es-mx");

  private String value;
  Locale(String val){
    value = val;
  }
}

But I have seen a smarter way somewhere, which converted the lowercase hyphenated string to uppercase underscored literal. Can you point me to that solution?

I need a solution such that FasterXml's ObjectMapper can map the string to enum.

Wards answered 6/1, 2017 at 22:42 Comment(2)
Possible duplicate of Override valueof() and toString() in Java enumHaber
@jhamon: it's not a duplicate. I don't have flexibility in calling a specific method of the defined enum. I don't know what method Jackson's ObjectMapper would call. It probably works only with the constructor.Wards
H
31

Since Jackson 2.6, you can annotate your enum constants with @JsonProperty to give them a custom name. The javadoc states

Starting with Jackson 2.6 this annotation may also be used to change serialization of Enum like so:

public enum MyEnum {
    @JsonProperty("theFirstValue") THE_FIRST_VALUE,
    @JsonProperty("another_value") ANOTHER_VALUE;
}

In your case, you'd use

public enum Locale {
  @JsonProperty("en-us") EN_US, @JsonProperty("es-mx") ES_MX
}

Alternatively, assuming all enum constants follow the same naming pattern, you can use @JsonValue. Define an instance method annotated with @JsonValue in your enum type and implement it with your naming strategy. For example,

@JsonValue
public String forJackson() {
    return name().toLowerCase().replace('_', '-');
}

You get the nice benefit of

when use for Java enums, one additional feature is that value returned by annotated method is also considered to be the value to deserialize from, not just JSON String to serialize as. This is possible since set of Enum values is constant and it is possible to define mapping, but can not be done in general for POJO types; as such, this is not used for POJO deserialization.

It'll be used for both serialization and deserialization.


Avoid naming your types with names already appearing in the JDK. Java already provides a commonly used Locale type. Consider renaming your class.

Haplography answered 6/1, 2017 at 23:2 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.