Reivax
Reivax

Reputation: 135

Java Abstraction and Generic Types

I'm having a problem properly implementing generics in abstract classes that need to be overridden.

public abstract class AbstractSerachView {
    DataStore<AbstractCriteria, AbstractResults, AbstractService> resultsStore;
    public abstract DataStore<AbstractCriteria, AbstractResults, AbstractService> getResultsStore();
}

the child clases is as follows:

public class TravelSearchView extends AbstractSearchView {
    DataStore<TravelCriteria, TravelResults, TravelService> resultsStore;
    public DataStore<TravelCriteria, TravelResults, TravelService> getResultsStore() {
        return resultsStore;
    }
}

This sort of abstraction does not work at all, although it would be greatly appreciated if I could get this work in some way. What is the correct approach here? I have very little experience with generic types.

The problem is that Eclipse indicates an error in the child class: The return type is incompatible with AbstractSearchView.getResultsStore()

Furthermore, if I leave the child class get method with the 3 abstract types, and override the variable with the 3 travel types, everything is okay except for the return line, where Eclipse indicates: Type mismatch: Cannot convert from DataStore to DataStore

Upvotes: 2

Views: 428

Answers (3)

Alexander Pogrebnyak
Alexander Pogrebnyak

Reputation: 45576

The best way to do it is to make a base class ( or interface ) generic:

public abstract class AbstractSerachView<
    TCriteria extends AbstractCriteria>,
    TResults extends AbstractResults,
    TService extends AbstractService>
{
    DataStore<TCriteria, TResults, TService> resultsStore;
    public DataStore<TCriteria, TResults, TService> getResultsStore()
    {
        return resultsStore;
    }
}

Then in implementation just provide concrete types

public class TravelSearchView
    extends AbstractSearchView<TravelCriteria, TravelResults, TravelService>
{
}

Also, as you can see, implementation class does not need to override getResultsStore method.

Upvotes: 4

matts
matts

Reputation: 6887

Your AbstractSearchView class needs to specify generic parameters for each of the parameters of DataStore if you want to override getResultsStore() with a different return type.

public abstract class AbstractSearchView<C extends AbstractCriteria, R extends AbstractResults, S extends AbstractService> {
    DataStore<AbstractCriteria, AbstractResults, AbstractService> resultsStore;
    public abstract DataStore<AbstractCriteria, AbstractResults, AbstractService> getResultsStore();
}

public class TravelSearchView extends AbstractSearchView<TravelCriteria, TravelResults, TravelService> {
    DataStore<TravelCriteria, TravelResults, TravelService> resultsStore;
    public DataStore<TravelCriteria, TravelResults, TravelService> getResultsStore() {
        return resultsStore;
    }
}

The supertype bounds (X extends SomeClass) in the parameters of AbstractSearchView ensures that subclasses of AbstractSearchView may only use subtypes of each of those parameters.

Upvotes: 4

Louis Wasserman
Louis Wasserman

Reputation: 198043

Here are your alternatives:

a) Change the superclass type signature to

    public DataStore<? extends AbstractCriteria, ? extends AbstractResults, ? extends AbstractService> getResultsStore();

b) Add the type parameters to the class as a whole:

 abstract class AbstractSearchView<
     C extends AbstractCriteria,
     R extends AbstractResults,
     S extends AbstractService>
  public abstract DataStore<C, R, S> getResultsStore();
 } 
 class TravelSearchView extends AbstractSearchView<
     TravelCriteria, TravelResults, TravelService> {
   ...
 }

The issue is that DataStore<TravelCriteria, TravelResults, TravelService> is not a subtype of DataStore<AbstractCriteria, AbstractResults, AbstractService>, even if those generic type arguments are respectively subtypes.

Upvotes: 3

Related Questions