Question

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

Was it helpful?

Solution

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();
    }
    ...
}

OTHER TIPS

Use PropertyUtils (from apache commons-beanutils) instead of BeanUtils.

It has a getProperty(Object bean, String name) method that returns an Object instead of a String.

See the JavaDoc for more information.

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!");
    }
}

See the Reflection API:

Use Class.getMethod() (or getMethods()) to find the appropriate method and invoke it.

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);
}

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!");
    }
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top