1

Is there a way to skip MissingPropertyException while using GroovyShell.evaluate?

def sharedData = new Binding()
def shell = new GroovyShell(sharedData)
shell.evaluate("a=5; b=1") // works fine

// How to not get MissingPropertyException, or silently ignore property 'a'
shell.evaluate("a; b=1") // MissingPropertyException for 'a'

I know about the Expando solution, is there a way to do it without defining a class?

ic10503
  • 131
  • 4
  • 16
  • "is there a way to do it without defining a class?" - What is it that you want `a` to evaluate to if you refer to it in the script but never define it? – Jeff Scott Brown Nov 03 '21 at 16:33
  • Thanks @JeffScottBrown. I just want to skip evaluating `a`. – ic10503 Nov 03 '21 at 17:10
  • " I just want to skip evaluating a" - The language doesn't support that. If you evaluate a series of statements like `a; b=1`, there is no way to tell Groovy not to evaluate `a`. The presence of `a` in the script is an explicit request that it be evaluated. – Jeff Scott Brown Nov 03 '21 at 17:13
  • You can make it evaluate to an empty `String`, `null`, the number zero, or any other default value you like, but you can't skip evaluating it altogether. – Jeff Scott Brown Nov 03 '21 at 17:14
  • @JeffScottBrown Thanks, that should be alright. Do you have some sample code? – ic10503 Nov 03 '21 at 17:38
  • "Thanks, that should be alright. Do you have some sample code?" - I can create one for you. What is it that you would like `a` to evaluate to when you evaluate something like `a; b=1`? – Jeff Scott Brown Nov 03 '21 at 19:21

2 Answers2

0

A very minimal approach would be to override Binding.getVariable. Note that this is very straight forward: "all exceptions" are ignored - you might want to have better logging or more accurate error handling.

import groovy.lang.*

class NoOpBinding extends Binding {
    @Override
    Object getVariable(String name) {
        try {
            return super.getVariable(name)
        }
        catch (Throwable t) {
            println "Ignoring variable=`$name`"
            return null
        }
    }
}

def shell = new GroovyShell(new NoOpBinding())
shell.evaluate("a; b=1") // MissingPropertyException for 'a'
// → Ignoring variable=`a`
println shell.getVariable('b')
// → 1
cfrick
  • 35,203
  • 6
  • 56
  • 68
  • 1
    I won't post another answer since your one solves the problem. There is one small improvement you could suggest in your answer - `new Binding([:].withDefault { null })` This way you can use the existing `Binding` class with a map that returns `null` for bindings that don't exist. Just a few less lines of code to write :-) Good job anyway! – Szymon Stepniak Nov 03 '21 at 18:46
  • This does not address the question "is there a way to do it without defining a class?". @ic10503 Do you want to do this without introducing a new class/type? – Jeff Scott Brown Nov 03 '21 at 19:22
  • @cftrick thanks for your answer. How is it any better than defining a new class that extends `Expando`? – ic10503 Nov 03 '21 at 22:27
  • @ic10503 You mean the approach, you state in https://stackoverflow.com/questions/69826801/get-json-from-groovy-object-script-with-missing-properties , where you claim it does not work? This at least works (well it will not in your other question but for different reasons). If your homework assignment forbids defining a class, then the approach Szymon suggested in the first comment works too. – cfrick Nov 04 '21 at 07:46
0

You could do something like this:

def binding = [:].withDefault { }
def shell = new GroovyShell(binding as Binding)

shell.evaluate 'a; b=1'
Jeff Scott Brown
  • 26,804
  • 2
  • 30
  • 47