3

I'm working on a groovy unit-testing class that contains a collection of rules for whether or not the contents of a file are correctly formatted. (Not using a proper rules engine, it just takes advantage of Groovy's assertion capabilities to do validation in a way that vaguely resembles what a rules engine would do.) I was thinking that I could create a method called FireAllRules that looks like this:

public static void FireAllRules(File file)
{
    for(def method in Class.getMethods)
    {
        if(method.name.indexOf("rule" == 0) method.invoke(file);
    }
}

All the methods that I want the loop to pick up on are static, and I noticed during the debugging process none of my rule methods are included in the Class.getMethods() enumeration. Ideally, I would like to only loop over the methods that I personally wrote into the class rather than sorting through dozens of uninteresting methods that come in along with java.Object. Is there a way to use reflection to iterate over these static methods at runtime?

3 Answers 3

6

Given:

class Test {
  public static testThis() {
    println "Called testThis"
  }

  public static woo() {
    println "Called woo"
  }

  public static testOther() {
    println "Called testOther"
  }
}

You can do:

Test.metaClass.methods.grep { it.static && it.name.startsWith( 'test' ) }.each {
  it.invoke( Test )
}

To print:

Called testOther
Called testThis

A more generic method to execute the static test methods of a class would be:

def invokeClass( clazz ) {
  clazz.metaClass.methods.grep { it.static && it.name.startsWith( 'test' ) }.each {
    it.invoke( clazz )
  }
}

invokeClass( Test )
Sign up to request clarification or add additional context in comments.

4 Comments

This looks like exactly what I had in mind. The only problem I'm running into is that the compiler's complaining that it.invoke(clazz) has the wrong number of arguments. Do you know why that might be? EDIT: Nevermind, I got it.
@estanford You could try it.invoke( clazz, null ) oddly the single arg version works for me... what version of Groovy? 1.8.6?
@tim_yates I noticed that your example was different from mine insofar as I was passing a File object into all the rules and your example didn't, so I had to call the invoke method as it.invoke(clazz, file) in order to make it work properly.
@estanford ahhh yes... Sorry, I forgot that originally when I was coming up with the code above :-( Glad you got it sorted out though! :-)
3

Static methods are included in the methods returned by getMethods(). Your issue might be method.name.indexOf("rule" == 0). This should be method.name.indexOf("rule") == 0, or better yet method.name.startsWith("rule").

Also, are your rule methods public? If not, you can use getDeclaredMethods(). To invoke them, you will have to call setAccessible() first.

Comments

2

The java version would be something like this (I've removed the imports and exceptions for clarity).

public class FindAndRunStaticMethods {
    public static void main(String[] args) {
        fireAllRules();
    }

    public static void fireAllRules() {
        for(Method method : StaticMethodClass.class.getDeclaredMethods()) {
            findAndRunRules(method);
        }
    }

    private static void findAndRunRules(Method method) {
        if (!Modifier.isStatic(method.getModifiers())) return;
        if (!method.getName().startsWith("rule")) return;
        if (!method.getReturnType().equals(Void.TYPE)) return;

        Class[] parameterTypes = method.getParameterTypes();

        if (parameterTypes.length != 1) return;
        if (!parameterTypes[0].equals(File.class)) return;

        method.invoke(null, new File("dummy"));
    }
}

A sample test class could look like this

public class StaticMethodClass {
    public static void ruleHere(File x) { System.out.println("should print"); }
    public static void ruleRun(File x) { System.out.println("should print"); }  
    public void ruleNotSelected() { System.out.println("not run"); }
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.