Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Type-safe method reflection in Java

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);
like image 436
jthg Avatar asked Jan 05 '10 22:01

jthg


People also ask

What is reflection method in Java?

Reflection is a feature in the Java programming language. It allows an executing Java program to examine or "introspect" upon itself, and manipulate internal properties of the program. For example, it's possible for a Java class to obtain the names of all its members and display them.

How do you create a reflection in Java?

In order to reflect a Java class, we first need to create an object of Class . And, using the object we can call various methods to get information about methods, fields, and constructors present in a class. class Dog {...} // create object of Class // to reflect the Dog class Class a = Class. forName("Dog");

What is method reflection?

The reflected method may be a class method or an instance method (including an abstract method). A Method permits widening conversions to occur when matching the actual parameters to invoke with the underlying method's formal parameters, but it throws an IllegalArgumentException if a narrowing conversion would occur.

Is it good practice to use reflection in Java?

Using reflection is not a bad practice. Doing this sort of thing is a bad practice. A better approach when you're wanting to pick among several similar objects by ID is a map from string to a strategy object.


3 Answers

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.

like image 66
PSpeed Avatar answered Nov 06 '22 19:11

PSpeed


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.

like image 42
Jon Skeet Avatar answered Nov 06 '22 20:11

Jon Skeet


Check out https://jodd.org/ref/methref.html. It uses the Jodd proxy library (Proxetta) to proxy your type. Not sure about its performance characteristics, but it does provide type safety.

An example: Suppose Str.class has method .boo(), and you want to get its name as the string "boo":

Methref<Str> m = Methref.on(Str.class);

// `.to()` returns a proxied instance of `Str` upon which you
// can call `.boo()` Methods on this proxy are empty except when
// you call them, the proxy stores the method's name. So doing this
// gets the proxy to store the name `"boo"`.

m.to().boo();

// You can get the name of the method you called by using `.ref()`:

m.ref();   // returns "boo"                                 

There's more to the API than the example above: https://oblac.github.io/jodd-site/javadoc/jodd/methref/Methref.html

like image 25
Dmitry Minkovsky Avatar answered Nov 06 '22 21:11

Dmitry Minkovsky