views:

87

answers:

4

I am working with a 3rd party framework and it turns out I need to wrap some of its objects as a delegate to one of my classes.

class Foo { // 3rd party class.
    protected void method() {}
}

class FooWrapper extends Foo {
    private Foo mDelegate;

    public FooWrapper(Foo inDelegate) {
        mDelegate = inDelegate;
    }

    protected void method() {
        mDelegate.method(); // error can't access protected method() of mDelegate
    }
}

So there is the problem. I need to delegate this method to the internal object but its protected and therefore not accessible.

Any ideas on ways to solve this particular problem? This is for Java 1.3.

+3  A: 

Why are you constructing a separate instance of Foo? FooWrapper is already a Foo.

class Foo {
    protected void method() {}
}

class FooWrapper extends Foo {

    protected void method() {
        super.method();
    }
}

Edit: if you really have to have separate instance, one way (albeit slightly ugly) is to use reflection:

public class Foo {

    protected void method() {
        System.out.println("In Foo.method()");
    }
}

public class FooWrapper extends Foo {

    private Foo foo;

    public FooWrapper(Foo foo) {
        this.foo = foo;
    }

    public void method() {
        try {
            Method m = foo.getClass().getDeclaredMethod("method", null);
            m.setAccessible(true);
            m.invoke(foo, null);

        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

Edit2: Based on your comment below, have two sub-classes of Foo, one that simply provides public versions of the protected methods, and one that has overrides all of the important methods. The first will look and act exactly like a Foo, the second can do whatever you need doing:

public class Foo {

    protected void method() {
        System.out.println("In Foo.method()");
    }
}

public class DelegateFoo extends Foo {

    public void method() {
        super.method();
    }
}

public class FooWrapper extends Foo {

    private DelegateFoo foo;

    public FooWrapper(DelegateFoo foo) {
        this.foo = foo;
    }

    public void method() {
        foo.method();
        /* extra logic here */
    }
}
Jared Russell
Because I need to delegate to look like a Foo but delegate to an internal instance of another foo.
Maven
Unfortunately the embedded platform I am working on doesn't have the reflection APIs. Sigh. Good suggestion though.
Maven
Stupid question, but why is it you need to delegate to another instance? Assuming you don't override any other methods the behavior will be exactly the same will it not?
Jared Russell
I am overriding alot of other methods. I omitted alot of code for brevity. The methods of the wrapper class do work before and/or after calling the delegate's methods. Most of the methods I need to delegate are public so there is no problem but a few are protected.
Maven
Then why not create a second sub-class of Foo that only overrides this one specific method, you can then delegate to that from FooWrapper?
Jared Russell
Added some code above to illustrate.
Jared Russell
There we go. You nailed it. That's exactly what is needed. The delegate class needs to subclass the framework class and raise the access level of the protected methods to public. Then the wrapper can call it. Outstanding! Thanks for the help!
Maven
+2  A: 

What I've done when I've been in a situation like this, and its not nice, but it works, is create a PublicFoo in the same package as Foo (but in your source), have it extend Foo, and override the protected method and make it public.

Now, FooWrapper can extend PublicFoo and do whatever you want.

Note, however, if the original jar is signed and sealed, youll need to remove the signatures before you can deploy it. (You can go into the Manifest directory in the jar, and simply delete the certificates)

Milan Ramaiya
I thought about doing that but the problem is that my FooWrapper is being passed other subclasses of Foo that I don't control.
Maven
To be fair this is similar to the accepted answer.
Maven
A: 

A subclass should have access to a superclass's protected methods.

If you just call super.method() instead of mDelegate.method(), it'll go; you're both wrapping the parent class and instantiating it.

Dean J
An instance of class A doesn't have access to protected methods of another instance of class A. Calling super.method() in my FooWrapper defeats the purpose of delegation. The FooWrapper needs to delegate its methods to the internal instance of the same class.
Maven
A: 

Well, if it has public access to its properties (be they getters or public variables), you could create a copy constructor:

public FooWrapper(Foo inDelegate) {
    this.property1 = inDelegate.getProperty1();
    this.property2 = inDelegate.getProperty2();
    // for every property
}

If the properties are objects... great, even better, because then any changes you make will show up when accessed through the original object, too! (That is, until you replace one of those objects, which you have to for immutable classes like String.)

R. Bemrose