Skip to content

YamlSlurper cannot parse Enum value

I have yaml:

- flowId: "2021:6:10:20:22:7"
  flowType: "BIG"
  summary: "Description"
  flowStatus: "NEW"
  createdDate: "2021-06-10"
  lastModifiedDate: "2021-06-10"

class Flow{
...
FlowType flowType;
...
}

Enum FlowType{
SMALL,MEDIUM, BIG;
}

Parsing file using YamlSlurper:

def flowList = new YamlSlurper().parseText(new File(myFile).text).collect { it as Flow }

error: java.lang.ClassCastException: java.lang.String cannot be cast to model.FlowType

Is there a way to solve this?

Answer

The YAML slurper is a cute tool to quickly read a YAML file or string and deal with it to the degree, that you would use the other slurpers: get some basic data types inside lists and maps and just use that.

Your attempt to cast the map to the object only works for very basic objects. The cast basically gets unrolled to something like:

[a: 42] as X

becomes

def x = new X()
map.each{ k, v ->
    x."$k" = v
}

This does:

  • not coerce/convert types
  • fails if keys in the map, that are not set-able properties in the resulting object

If you need proper object mapping, the slurpers are not directly useful most of the time. You would rather switch to using something made for that task — e.g. like Jackson.

Lucky for us, the YAML slurper just uses Jackson (it actually just transforms the YAML into JSON and then uses the JSON slurper to give you your data back).

Following an example of how to load the YAML data into objects using Jackson (all deps are already there, if you already see YamlSlurper):

import com.fasterxml.jackson.core.type.TypeReference
import com.fasterxml.jackson.databind.ObjectMapper
import com.fasterxml.jackson.databind.DeserializationFeature
import com.fasterxml.jackson.dataformat.yaml.YAMLFactory
import com.fasterxml.jackson.dataformat.yaml.YAMLMapper

def yamlStr = """
- flowId: "2021:6:10:20:22:7"
  flowType: "BIG"
  summary: "Description"
  flowStatus: "NEW"
  createdDate: "2021-06-10"
  lastModifiedDate: "2021-06-10"
"""

enum FlowType{ SMALL,MEDIUM, BIG }

@groovy.transform.ToString
class Flow {
    FlowType flowType
}

def flows = new ObjectMapper(new YAMLFactory()).with{
    configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false)
    readValue(yamlStr, new TypeReference<List<Flow>>(){})
}

println flows
// → Flow(BIG)