Search code examples
javajacksonyaml

Is there a way to (de)serialize a Java enum to/from YAML?


I am trying to serialize and deserialize a Java object that contains an enum to/from YAML representation. I'm trying to use the Jackson (com.fasterxml.jackson) package to do this.

I keep getting this exception:

Caused by: com.fasterxml.jackson.databind.exc.InvalidFormatException: Cannot deserialize value of type `com.beastcode.devops.prometheusbroker.domain.Metric$Type` from String "counter": not one of the values accepted for Enum class: [GAUGE, COUNTER]

I assume I need some sort of adapter or converter, but don't know what's available (if anything) for YAML.

For reference:

Metric.java:

public class Metric {

  public enum Type {
    COUNTER, GAUGE
  }

  private String           name;
  private String           description;
  private Type             type;
  private List<String>     labels;
  private List<MetricData> data;

  // getters/setters removed
}

data.yaml:

---
name: gitlab_pipeline_success_total
description: "blah blah blah"
type: counter
labels:
  - project
  - somethingElse
data:

Parser.java:

public class Parser {

  private ObjectMapper mapper = new ObjectMapper(new YAMLFactory());

  public void parse() throws StreamReadException, DatabindException, IOException {
    Metric m = mapper.readValue(new File("data.yaml"), Metric.class);
  }

}

Solution

  • By default Jackson uses the enum's valueOf method. That's case sensitive.

    You can easily change this by adding a static method annotated with @JsonCreator:

    public class Metric {
    
        public enum Type {
            COUNTER, GAUGE;
    
            @JsonCreator
            public static Type getType(String value) {
                return valueOf(value.toUpperCase());
            }
    
            // optional, for serialization
            @JsonValue
            public String value() {
                return name().toLowerCase();
            }
        }
    
        // rest omitted
    }