2

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?

1
  • Basically: The current codebase passes around a large number of "long someId" parameters that represent different objects, such as a BaseThing, SpecificThing, or some other TotallyUnrelatedThing. I'd like to make those parameters type-safe, self-documenting, (more than "name of type + id") and allow for a concrete instance of the object to be passed instead of a wrapper over a long saving some memory allocation. EDIT: And there are a lot of times where we don't want to pull the object into memory and just want the ID, as the long will get passed directly to SQL. Commented Feb 8, 2017 at 17:36

2 Answers 2

4

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 */
}
Sign up to request clarification or add additional context in comments.

Comments

0

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.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.