views:

137

answers:

3

This is probably a very basic question, but I'm really new to generics in Java and I'm having a hard time altering my thought process from the way things are done in C#, so bear with me.

I'm trying to build a generic repository in Java. I've created an IRepository interface that looks like this:

public interface IRepository<T extends IEntity>

And a Repository class that looks like this:

public class Repository<T extends IEntity> implements IRepository<T>

Now, from within the constructor of my Repository class, I'd like to be able to "divine" the exact type of T. For example, if I instantiated a repository like this:

IRepository<MyClass> repo = new Repository<MyClass>();

I'd like to know that T is actually MyClass. This is trivial in C#, but obviously generics are a totally different beast in Java and I can't seem to find anything that would help me do this.

+5  A: 

Java uses type erasure, so the specific information is lost at runtime - you only know that this type is generic, not what's the specific argument you've supplied at compile time.

Bozho
The *specific* information is lost; the *generic* information is...generic. :-)
T.J. Crowder
thanks; reworeded :)
Bozho
I think this is the right answer. This clearly explains why what I originally wanted to accomplish simply isn't possible with Java's implementation of generics.
Ragesh
A: 

I've done something similar (also to implement a Repository/Registry pattern) and with a bit of work you can actual find out the type. Note however I wasn't doing this with interfaces, but with a base class, and also note that it took a bit of trial and error to arrive at a solution that worked. This code was running on the Sun JVM so it may be that I've stumbled into an area that is JVM specific.

Also - as another comment mentioned, just because you can do this, doesn't mean you necessarily should :)

import java.lang.reflect.ParameterizedType;
...
public static Class<?> type(Object target) {
    Class base = target.getClass();
    while (base != null) {
        Object gsuper = base.getGenericSuperclass();
        if (gsuper != null && gsuper instanceof ParameterizedType) {
            Object o = ((ParameterizedType) gsuper).getActualTypeArguments()[0];
            if (o instanceof Class) {
                return (Class<?>) o;
            }
        }
        base = base.getSuperclass();
    }

    return null;
}

I used this from my BaseRepository class like:

Class<?> type = type(SomeRepository);

where:

public class SomeRepository extends Repository<MyEntity> {
... 
}
Joe
This only helps when you actually subclass, though... not just instantiate like the OP is doing.
PSpeed
+2  A: 

You can always add the actual type of T in your constructor, like so:

public class Repository<T> implements IRepository<T>
  public Repository(Class<T> type) {
  }
}

and instantiate like

IRepository<MyClass> repo = new Repository<MyClass>(MyClass.class);
Jorn
This is a good workaround, but I think it would still bite me higher up in the chain. I can't think of a way to create a Repository Factory using this same approach.
Ragesh