Skip to main content

Make dynamic invocation through reflection simpler

11 replies [Last post]
vhi
Offline
Joined: 2004-10-11

It would be great if Java simplified dynamic method invocations. E.g.

Instead of:
o.getClass().getMethod("exec", new Class[]{String.class}).invoke(o, new String[]{"Hello"});

Do:
o..exec("Hello")
OR
o::exec("Hello")

This would greatly reduce many uses of single-method interfaces, and make it possible to gracefully call third party code (in which 2 classes have same method to do the same thing but do not share inheritance hierarchy) instead of having to cast.

I would like to know if there are others who would like this.

Reply viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.
yishai
Offline
Joined: 2003-11-16

> Your example is quite easy to implement using a
> normal method, rather than introducting a extra
> language construct. Try something along the lines
> of:[code]
> public class ClassUtils {
> public static Object callMethod(String methodName,
> e, Object o, Object...args) {
> Class classes[] = new Class[args.length];
> for (int j = 0; j != classes.length; j++) {
> classes[j] = args[j].getClass();
> }
> Class oClass = o.getClass();
> Method method = oClass.getMethod(methodName,
> ame, classes);
> return method.invoke(o, args);
> }
>
> }
> [/code]

There are two cases that the above code does not handle, and those two cases are serious work to solve.

1) if you want to pass null as one of the parameters in the args array.

2) if the method actually calls for a superclass, or an interface implemented by, one of those arguments.

spm4
Offline
Joined: 2004-11-22

Improving reflective Field access

----------
import java.lang.reflect.Field;

/**
* tst001
*/
public class T001 {
static class T002 {
Object f1;
int f2;
Object f3 = f1;//(line 003)
};

public static void main(String[] args) {
T002 t002 = new T002();

//Current field access reflection mechanism
Field f1 = t002.getClass().getField("f1"); //line 004
Field f2 = t002.getClass().getField("f2"); //line 005

//Suggested field access reflection mechanism in order to make
//a) refectoring more safe for lines: 004, 005
//b) alleviate finding a java.lang.Object's corresponding java.lang.reflect.Field
// also, at Runtime, i dont have to care about the real field name, all I need is just MY FIELD
// derived from MYOBJECT if object is a member some class aggregate.

Field f1Better = t002.f1.getAsField(); //meaning that Object class could have introduced this method ...
Field f1Better1 = t002.getClass().getAsField(t002.f1) ;//Or method could be a part of reflection aggregate ..

// but this seems to be unambiguous call, see line 003,
// but this is for YOU to solve and suggest ... and think more,
//hopefully you got my point to improvise

//more difficult for not primitive types ...
Class.getAsField(t002.f2.primitiveClass);

}
}

brucechapman
Offline
Joined: 2004-03-18

It seems your use case is where you would like to introduce a common interface to two or more classes which share common methods, but don't share a common interface containing those methods, and where you want to use a single reference to one of these things, and call the common methods on that reference.

One way to do this would be to generate a class that captures this commonality with adapters to each of the classes. For example the commonality of java.lang.reflect.Method and java.lang.reflect.Constructor
[code]abstract class Executable {
/* get one from an instance of each of the common classes */
public static Executable from(Method method) {
return new MethodAdapter(method);
}
public static Executable from(Constructor constructor) {
return new ConstructorAdapter(constructor);
}
/* the common methods */
public abstract int getModifiers();
public abstract Class[] getExceptionTypes();
public abstract String getName();
public abstract Class[] getParameters();

/* the adapters */
private class MethodAdapter extends Executable {
private Method method;
private MethodAdapter(Method method) {
this.method=method;
}
public int getModifiers() { return method.getModifiers(); }
public Class[] getExceptionTypes() { return method.getExceptionTypes(); }
public String getName() { return method.getName(); }
public Class[] getParameters() { return method.getParameters(); }
}
private class ConstructorAdapter extends Executable {
private Constructor constructor;
private MethodAdapter(Constructor constructor) {
this.constructor=constructor;
}
public int getModifiers() { return constructor.getModifiers(); }
public Class[] getExceptionTypes() { return constructor.getExceptionTypes(); }
public String getName() { return constructor.getName(); }
public Class[] getParameters() { return constructor.getParameters(); }
}
}[/code]I am really too lazy to code this up every time I want to do this. You probably guessed this, so yes, I am going to suggest an annotation and apt as a way of generating the common class.

Here would be a use case that would generate the class above[code]@Commonality({Method.class,Constructor.class}
Executable executable;

void doSomething(Class c) {
List executables = new ArrayList();
for(Method m : c.getMethods()) {
executables.add(Executable.from(m));
}
for(Constructor cons : c.getConstructors()) {
executables.add(Executable.from(cons));
}
for(Executable exe : executables) {
System.out.println("%s has modifiers %s%n",
exe.getName(),
Modifiers.toString(exe.getModifiers())
);
}
}[/code]I am imagining the annotation could be on a field or class.

When on a field, the field type would be generated (and shouldn't already exist), as in the above example.

When on a class, the superclass would be generated (and shouldn't already exist) as in this example[code]@Commonality({Method.class,Constructor.class}
class Executable extends ExecutableSuper {}[/code]which would generate ExecutableSuper.

Would this solve all your use cases?

ygmarchi
Offline
Joined: 2003-06-10

Mmm,

I think this would make direct invocation and dynamic invocation too similar; it would make java a dual language both type safe and scripting-like.

Instead I would like to have method literals,
something like

class A
{
public void exec (String [] args)
{
}

public static void main (String []args)
{
A.exec.invoke (new A (), args);
}

}

monika_krug
Offline
Joined: 2004-10-14

> This would greatly reduce many uses of single-method
> interfaces

Using single-method interfaces makes your code safe (at compile time) and fast, using reflection makes it unsafe and slow. Use the interfaces, avoid the reflection whenever possible.

Your notation doesn't make reflection any safer. It makes it easier to use, but mostly for exactly the cases when it should not be used at all.

> and make it possible to gracefully call
> third party code (in which 2 classes have same method
> to do the same thing but do not share inheritance
> hierarchy) instead of having to cast.

You have a point there, casting is about as unsafe as reflection.

Look into AspectJ or other aspect-oriented methods. It's possible to declare existing classes to implement an interface. (I am not sure if this works for third-party classes, I'll find out later.)

Monika.

vhi
Offline
Joined: 2004-10-11

I definitely agree that compile time safety is gone the moment we use reflection. But then, it makes it more flexible for many cases. And, in case of SWT, it was not possible for me to make it inherit from my own interface, because I do not want to customize their code base for this purpose.

vikstar
Offline
Joined: 2004-04-23

Your example is quite easy to implement using a normal method, rather than introducting a extra language construct. Try something along the lines of:[code]
public class ClassUtils {
public static Object callMethod(String methodName, Object o, Object...args) {
Class classes[] = new Class[args.length];
for (int j = 0; j != classes.length; j++) {
classes[j] = args[j].getClass();
}
Class oClass = o.getClass();
Method method = oClass.getMethod(methodName, classes);
return method.invoke(o, args);
}

}
[/code] Ok, I've just written that in a minute in the forum Post Message box, so I'm not sure it compiles, but it does show how such a thing is possible without the need for langauge polution. However, there is an obvious restriction on arguments with inherited classes, or null arguments. With a little more work you could fix these restrictions. For example, you could search through the superclasses of o's class and through all possible combinations of superclasses of the named method's argument classes and find a method that fits.

vhi
Offline
Joined: 2004-10-11

Of course it is possible to do so in Java already. But, my request was to make it simpler.

zander
Offline
Joined: 2003-06-13

Adding something extra to learn and something not intuitively obvious in its function implies its a trick. Java should not be about learning tricks but about simple logic and intuitive constructs.
Consider you find a construct in somebody else's code; you will have to know what it means.

I'm afraid your request to make it simpler makes the language as a whole more complex, that can not be the objective.

zander
Offline
Joined: 2003-06-13

> Instead of:
> o.getClass().getMethod("exec", new Class[]{String.class}).invoke(o, new String[]{"Hello"});

The shortest version of your example above is o.exec("Hello");

Your example shows a usage that is not really usefull and certainly not typically, and your solution quite useless since the normal (not reflective) execution is better.

If you have a real world usage where its not usefull to cache the Method or Class objects at all, and you have a suggestion on a shorter form. Please tell us.

vhi
Offline
Joined: 2004-10-11

>> The shortest version of your example above is o.exec("Hello");
Actually, I forgot to tell that the 'o' is of type Object.

One real-life situation that I encountered this was when I used SWT. In SWT, all widgets have a 'setEnabled' method. But, not all widgets have a common ancestor with the 'setEnabled' method. So, when I had to treat all widgets in the same way, I had to use reflection to invoke the 'setEnabled' method. Other technique would have been 'instanceof' checks, which IMO was an uglier solution.

>> If you have a real world usage where its not usefull to cache the Method or Class objects at all, and you have a suggestion on a shorter form. Please tell us.
Caching is useful mainly in those areas where profiling has indicated it to be beneficial. Normally, the performance of Java reflection satisfies me enough to make caching an unnecessary headache.