views:

171

answers:

1

I'm working with Google Web Toolkit, and I'm having problems implementing a generic interface. I'm not really familiar with generics, doing an upgrade on someone else's code here.

Here's what I want to do: I want to have an implementation of a generic callback interface that does some logging, and then subclass that implementation in order to handle specific callback scenarios.

The interface is something like this:

public interface AsyncCallback<T> {
    void MethodFromAsyncCallback(T result);
}

The abstract and concrete implementations look something like this:

class CallbackBase implements AsyncCallback<Object> {
    public abstract void doStuff(Object result);

    public void MethodFromAsyncCallback(Object result) {
        // IMPORTANT STUFF
        // here are things I would like to do for all callbacks, hence the superclass.

        // Then we do the subclass specific things.
        doStuff(result);
    }
}

class SpecificCallback extends CallbackBase
{
    public void doStuff(Object result) {
        Integer i = (Integer)result;
        // do stuff with i
    }
}

The callbacks are required to be fired from

public interface MyServiceAsync {
    public void DoSomeThing(AsyncCallback<Integer>);
}

And then it all comes together in a call that looks like this:

MyServiceAsync myService = (MyServiceAsync)GWT.create(MyServiceAsync.class);
myService.DoSomeThing(new SpecificCallback());

And here's where we have a problem!

When the GWT.create() implements the interface I created, it demands that the type given to AsyncCallback is specified (matches a type elsewhere, outside the scope of this question), hence making DoSomething(AsyncCallback<Integer>) an Integer rather than an Object. This is beyond my control.

It complains that DoSomething() takes AsyncCallback<Integer>. I'm giving it something that inherits from something that is an AsyncCallback<Object>. I guess with generics, concepts of inheritance get somewhat broken?

So my question is this:

Either how can I mush this together so that DoSomething() will recognize that that SpecificCallback meets it's requirements,

or how can I structure the relationship between CallbackBase and SpecificCallback so that duplicate code is avoided, but SpecificCallback implements AsyncCallback<Integer> directly?

Thanks.

+4  A: 

What I think you need to do is define CallbackBase like this:

abstract class CallbackBase<T> implements AsyncCallback<T> {
  public abstract void doStuff(T result);

  public void MethodFromAsyncCallback(T result) {
    // general stuff (T is a subclass of Object)
    doStuff(result);
  }
}

Then you want your specific callbacks to be like this:

class SpecificCallback extends CallbackBase<Integer> {
  public void doStuff(Integer result) {
    // no need to cast
    // do stuff with result
  }
}

Then your DoSomething method, which accepts an AsyncCallback<Integer>, will accept a SpecificCallback.

(Pedantic sidenote: please start all methods with lowercase letters in Java)

Edit

For what it's worth, I'd suggest changing your design to use composition rather than inheritance. In this case, rather than using an abstract class CallbackBase and extending it, you'd use a concrete implementation of AsyncCallback<T> that might look something like this:

class GeneralCallbackWrapper<T> implements AsyncCallback<T> {
  private final AsyncCallback<? super T> delegate;

  public GeneralCallbackWrapper(AsyncCallback<? super T> delegate) {
    this.delegate = delegate;
  }

  public void MethodFromAsyncCallback(T result) {
    // general stuff here
    delegate.MethodFromAsyncCallback(result);
  }
}
ColinD
Beauty, thanks!
Ipsquiggle
Re: edit. Yes, that makes a lot of sense. I wanted to alter it to something like that in the first place, but figured I'd address my confusion one step at a time. ;)
Ipsquiggle
Is it possible to extend either of these to account for two possible types? e.g. conceptually equivalent to `implements AsyncCallback<Integer>, AsyncCallback<OtherType>`?
Ipsquiggle