Dean Hiller Dean Hiller - 1 year ago 47
Groovy Question

How to validate a Map snippet in groovy

I have an dynamic html file that groovy is generated from. Part of this html template format is

like so

USER_FORM[name:'Dean', user:randomFunction([item:'s', day:'Tuesday'])]

or something like

USER_FORM[name: 'Dean', user: user]

I made the first example more complex. Currently, I split on ':' and validate all the keys supplied. What I would like to do is take the groovy snippet and grab all the keys and validate

1. all keys are strings
2. validate the keys against some meta data I already have

I do not care about the values at all. Currently, I split on ':' but obviously that won't work for all cases. I am worried about other complex cases I may not be thinking about.

This is for a templating engine and I prefer to failfast if possible making it easier on the user when something is wrong.

Answer Source

I concur with others that you want to avoid parsing directly.

If you use GroovyShell, you can dope the input string with no-op methodMissing and propertyMissing handlers. In this way, even the complex example will work.

See code below, including test-cases (extracting map string from the "USER_FORMstr" format is left to the reader).

class KeyGenerator {
    // these could be "final static". omitted for brevity
    def shell = new GroovyShell() 
    def methodMissingHandler = "def methodMissing(String name, args) {}"
    def propertyMissingHandler = "def propertyMissing(String name) {}"

    def generateKeys(mapStr) {
        def evalInput = "${methodMissingHandler} ; " +
                        "${propertyMissingHandler} ; " + 
        def map = shell.evaluate(evalInput)
        return map.keySet()

// ------- main

def keyGenerator = new KeyGenerator()
def expected = new HashSet()
expected << "name"
expected << "user"

def mapStr = "[name:'Dean', user:randomFunction([item:'s', day:'Tuesday'])]"
assert expected == keyGenerator.generateKeys(mapStr)

def mapStr2 = "[name: 'Dean', user: user]"
assert expected == keyGenerator.generateKeys(mapStr2)