views:

178

answers:

3

Is any practical way to reference a method on a class in a type-safe manner? A basic example is if I wanted to create something like the following utility function:

public Result validateField(Object data, String fieldName, 
                            ValidationOptions options) { ... }

In order to call it, I would have to do:

validateField(data, "phoneNumber", options);

Which forces me to either use a magic string, or declare a constant somewhere with that string.

I'm pretty sure there's no way to get around that with the stock Java language, but is there some kind of (production grade) pre-compiler or alternative compiler that may offer a work around? (similar to how AspectJ extends the Java language) It would be nice to do something like the following instead:

public Result validateField(Object data, Method method, 
                            ValidationOptions options) { ... }

And call it with:

validateField(data, Person.phoneNumber.getter, options);
+1  A: 

There isn't anything in the language yet - but part of the closures proposal for Java 7 includes method literals, I believe.

I don't have any suggestions beyond that, I'm afraid.

Jon Skeet
@Downvoter: Care to give a reason?
Jon Skeet
A: 

Is any practical way to reference a method on a class in a type-safe manner?

First of all, reflection is type-safe. It is just that it is dynamically typed, not statically typed.

So, assuming that you want a statically typed equivalent of reflection, the theoretical answer is that it is impossible. Consider this:

Method m;
if (arbitraryFunction(obj)) {
    obj.getClass().getDeclaredMethod("foo", ...);
} else {
    obj.getClass().getDeclaredMethod("bar", ...);
}

Can we do this so that that runtime type exceptions cannot happen? In general NO, since this would entail proving that arbitraryFunction(obj) terminates. (This is equivalent to the Halting Problem, which is proven to be unsolvable in general, and is intractable using state-of-the-art theorem proving technology ... AFAIK.)

And I think that this road-block would apply to any approach where you could inject arbitrary Java code into the logic that is used to reflectively select a method from an object's class.

To my mind, the only moderately practical approach at the moment would be to replace the reflective code with something that generates and compiles Java source code. If this process occurs before you "run" the application, you've satisfied the requirement for static type-safety.

Stephen C
Thanks for the correction on the terminology.I'm not sure how the rest of your answer is related to my question. If you're doing reflection dynamically at run time (i.e. the result of the reflection could vary depending on input or other runtime state), then yes, you likely won't be able to ensure that the code won't throw an exception or that it will halt.
jthg
I was more asking about reflection in which the result is always the same. I.E. Person.class.getMethod("getPhoneNumber", null) would always return the same method and it's entirely possible to resolve it at compile time. Just like how you can do Person.class to get a Class object, it would be helpful to be able to do something like Person.getPhoneNumber.method to get a Method object.
jthg
+1  A: 

As others mention, there is no real way to do this... and I've not seen a precompiler that supports it. The syntax would be interesting, to say the least. Even in your example, it could only cover a small subset of the potential reflective possibilities that a user might want to do since it won't handle non-standard accessors or methods that take arguments, etc..

Even if it's impossible to check at compile time, if you want bad code to fail as soon as possible then one approach is to resolve referenced Method objects at class initialization time.

Imagine you have a utility method for looking up Method objects that maybe throws error or runtime exception:

public static Method lookupMethod( Class c, String name, Class... args ) {
    // do the lookup or throw an unchecked exception of some kind with a really
    // good error message
}

Then in your classes, have constants to preresolve the methods you will use:

public class MyClass {
    private static final Method GET_PHONE_NUM = MyUtils.lookupMethod( PhoneNumber.class, "getPhoneNumber" );

    ....

    public void someMethod() {
        validateField(data, GET_PHONE_NUM, options);
    }
}

At least then it will fail as soon as MyClass is loaded the first time.

I use reflection a lot, especially bean property reflection and I've just gotten used to late exceptions at runtime. But that style of bean code tends to error late for all kinds of other reasons, being very dynamic and all. For something in between, the above would help.

PSpeed
This seems like a decent idea. It's better than trying to define string constants with the names of fields like what I've seen in code I've maintained.
jthg
Yeah, it's sort of "making the best of it". Not sure who/why I got a down vote from someone. :) Always fun to get down voted with no comment.
PSpeed
The other nice thing about this approach is when/if the language gets Method literals then it's conceivably a simple change to convert.
PSpeed