Freezerburn
Freezerburn

Reputation: 1013

Implement generic interface twice in inheritance hierarchy with different generic types

I have a generic interface in Java that I created in order to represent the ID of something in a type-safe way. It looks basically like this:

public interface ID<T extends BaseOfAllIDNeedingObjects> {
    long getId();
    boolean isConcrete();
}

That isn't exactly it, but close enough for demonstration purposes. The actually ID number is obtainable, and I have various wrapping facilities to turn a long into an instance of an ID, so I can check if I have the object that the ID represents or a wrapper in case I want to cast back to the object. This works great for single object, but the problem is that at least some of our objects inherit others, and there are cases for using the base type over the specific type. So for example:

public class SpecificThing extends BaseThing {
    /* stuff */
}

public class BaseThing extends BaseOfAllIDNeedingObjects {
    /* stuff that all Things need */
}

Naturally, I would like to be able to represent the ID of both a BaseThing and a SpecificThing in different circumstances. Getting a SpecificThing requires extra work to pull data from different tables in the database, so sometimes I just want a BaseThing because it has all the information I need at the time. However, Java doesn't allow the following:

public class BaseThing extends BaseOfAllIDNeedingObjects implements ID<BaseThing> {
    /* base thing stuff here */
}

public class SpecificThing extends BaseThing implements ID<SpecificThing> {
    /* specific things */
}

This is straight up a compiler error. My IDE (Jetbrains) says "ID cannot be inherited with different type arguments 'BaseThing' and 'SpecificThing'". Is there some way that I can work around this? Do I just need to not tag BaseThing with ID, and only ever allow for SpecificThings to be used as an ID, wrapping the BaseThings in a separate ID object? Or is there some pattern that I'm unaware of which would allow me to finagle something like this into working?

Upvotes: 2

Views: 800

Answers (2)

wkenzow
wkenzow

Reputation: 68

You can define your classes this way:

public class BaseThingGeneric<T extends BaseThingGeneric<T>> extends BaseOfAllIDNeedingObjects implements ID<T> {
    /* base thing stuff here */
}

public class BaseThing extends BaseThingGeneric<BaseThing> {
    /* just redefine the constructors */
}

public class SpecificThingGeneric<T extends SpecificThingGeneric<T>> extends BaseThingGeneric<T> {
    /* specific things */
}

public class SpecificThing extends SpecificThingGeneric<SpecificThing> {
    /* just redefine the constructors */
}

The implementations will be in BaseThingGeneric and SpecificThingGeneric. BaseThing and SpecificThing are provided just to semplify instantiation. Furthermore ScecificThing will be also extensible in the same way by extending SpecificThingGeneric.

Upvotes: 0

Calculator
Calculator

Reputation: 2789

You can pull the implementation of BaseThing up to an abstract class and then use a self recursive generic parameter:

public abstract class AbstractBaseThing<T extends AbstractBaseThing<T>> extends BaseOfAllIDNeedingObjects implements ID<T> {
    /* base thing stuff here */
}

public class BaseThing extends AbstractBaseThing<BaseThing> {
    /* concrete base thing */
}

public class SpecificThing extends AbstractBaseThing<SpecificThing> {
    /* specific things */
}

Upvotes: 4

Related Questions