Hello, I'd like to be able to call "getProgram" on objects which have that method, without knowing which class they belong to. I know I should use an interface here, but I'm working with someone else's code and can't redesign the classes I'm working with. I thought BeanUtils.getProperty might help me, but it seems it only returns strings. Is there something like Beanutils.getProperty that will return a cast-able object? Or another, smarter way to work with two similar classes that don't share an interface? thanks, -Morgan
See the Reflection API:
Use Class.getMethod() (or getMethods()) to find the appropriate method and invoke it.
Just use reflection for this... the following example shows how to do it on objects that have no common interface.
public static void main(String[] args) throws Exception {
doSomething(new A());
doSomething(new B());
}
private static void doSomething(Object object) throws Exception {
Method m = object.getClass().getMethod("doSomething", (Class[])null);
m.invoke(object, (Object[])null);
}
private static class A {
public void doSomething() {
System.out.println("I'm doing it already!");
}
}
private static class B {
public void doSomething() {
System.out.println("I'm doing it too!");
}
}
java.beans.Expression will do that, as long as the method is accessible in the concrete class of the receiver.
public static void main(String[] args) throws Exception {
new Expression(new A(), "doSomething", null).getValue();
new Expression(new B(), "doSomething", null).getValue();
}
public static class A {
public void doSomething() {
System.out.println("I'm doing it already!");
}
}
public static class B {
public void doSomething() {
System.out.println("I'm doing it too!");
}
}
Presumably you have a finite number of classes implementing this method, and you can link to them directly. So you don't need reflection. Reflection is evil.
Say you have a set of classes with the method:
public class LibA { public Program getProgram() { return program; } ... };
public class LibB { public Program getProgram() { return program; } ... };
...
Then you just need instanceof/cast pairs. You can put this in a method so that you only need to do it once.
public static Program getProgram(Object obj) {
if (obj instanceof LibA) {
return ((LibA)obj).getProgram();
} else if (obj instanceof LibB) {
return ((LibB)obj).getProgram();
} else {
throw new IllegalArgumentException(obj+" doesn't have a known getProgram");
// Or an appropriate application exception.
}
}
Alternatively you might want to use an adapter:
public interface ProgramContainer {
Program getProgram();
...
}
public class LibAContainer implements ProgramContainer {
private final LibA libA;
public LibAContainer(LibA libA) {
this.libA = libA;
}
public Program getProgram() {
return libA.getProgram();
}
...
}
A pretty simple solution: Use delegation which implements the interface:
interface GetProgram
{
String getProgram ();
}
class AWrapper implements GetProgram
{
A a;
public AWrapper (A a) { this.a = a;
String getProgram () { return a.getProgram(); }
}
Now you can use the interface in your code without touching the original classes.
Drawback: This doesn't work well if you A is created somewhere outside of your reach. It works best if A is created once under your control and you can wrap it immediately.
A slightly shorter version if you have Java 5+
public static void main(String[] args) throws Exception {
System.out.println(invoke("toString", new A());
System.out.println(invoke("toString", new B());
}
private static <R> R invoke(Object object, String methodName) throws Exception {
return (R) object.getClass().getMethod(methodName).invoke(object);
}