2
public abstract class BaseDaoImpl<E extends AbstractEntity> implements BaseDao<E> {

    .....

    public BaseDaoImpl() throws DataAccessException {
        logger = LoggerFactory.getLogger(E);  <<-- error here.
    }

In the above code I get a error in the call to getLogger(E).

E cannot be resolved to a variable

This makes sense, but getLogger(E.class) (or variants thereof) does not work either.

I don't want to pass the literal class in the constructor, so a solution like changing the the constructor header to:
public BaseDaoImpl(Class<E> clazz) ... is not an option.

How do I get the class type from E?

Note that the answers to: How to get class of generic type when there is no parameter of it?
do not help.

Community
  • 1
  • 1
Johan
  • 71,222
  • 23
  • 174
  • 298
  • 2
    You can't, because of type erasure. – SLaks Mar 13 '13 at 16:19
  • Java generics are not the same as C++ Templates. With Java generics, the type is erased at compile time. Google "java type erasure" for details. This seems like a bad decision, but is actually a great decision; since it is fully backwards compatable with older java. – DwB Mar 13 '13 at 16:30
  • possible duplicate of [Get generic type of class at runtime](http://stackoverflow.com/questions/3403909/get-generic-type-of-class-at-runtime) – Louis Wasserman Mar 13 '13 at 18:04

4 Answers4

6

Without changing the constructor you can't learn anything about E at runtime that you didn't already know statically. That's because in Java, there just simply isn't any runtime effect of a generic parameter -- the compiler literally erases all references to E in the code it generates. So if you want code that can tell what class its type parameter is being instantiated with, you have to add in some kind of argument (e.g. a Class object) yourself. There's just no way around it.

jacobm
  • 12,582
  • 1
  • 21
  • 24
  • I stumbled into this by trying to understand [`List.toArray()`](https://docs.oracle.com/javase/8/docs/api/java/util/List.html#toArray-T:A-) and man it's disappointing. I understand that type-erasure was done as a sort of cost/complexity cutting measure, but it really leaves things half-baked. At a minimum, and implicit `Class` parameters could have been added to generic functions, which allows the runtime to pipe in the metadata for generic type `E`. – Alexander Jul 25 '19 at 17:12
2

It is possible by reflection as pointed out by @CorayThan . A simple way to do it is from method signature

interface BaseDao<E>
    E find(long id);

class FooDao implements BaseDao<Foo>
    Foo find(long id)

So type E can be found through

this.getClass().getDeclaredMethod("find", long.class).getReturnType();

However, it is a very good option to pass a Class in the constructor. Because the constructor is not meant to be called by user codes, the verbosity is not an issue here.

abstract class BaseDaoImpl<E>

    BaseDaoImpl(Class<E> clazz)

class FooDao extends BaseBaoImpl<Foo>

    FooDao()
        super(Foo.class);

// usages:

BaseDao<Foo> fooDao = new FooDao(); // clean & simple API
ZhongYu
  • 18,232
  • 5
  • 28
  • 55
0

Because generics are implemented in the Java language using type erasure, you cannot do anything that would require runtime type information. See this page for more info.

gparyani
  • 1,872
  • 3
  • 24
  • 35
-1

Already been answered.

Basically, you can't unless you use reflection.

I wouldn't recommend using reflection, but if you want to, you should be able to use:

GenericClass.class.getTypeParameters()
Community
  • 1
  • 1
CorayThan
  • 15,119
  • 26
  • 101
  • 148
  • This is not correct in general. For example, if I have `class Foo extends BaseDaoImpl` then you still won't be able to get it. – newacct Mar 13 '13 at 19:44
  • It should work if you have `class Foo extends BaseFoo extends User>` though. If you are trying to get the class of E, obviously you're going to have problems, as E isn't a class! – CorayThan Mar 13 '13 at 19:49
  • Getting the `Type` is not the same as getting the `Class` – jpaugh Jan 29 '16 at 20:36