Reputation: 3803
I would like to do this:
Get "Class" object from generic type T
but the other way round. So I would like to get the type of class objects. In Pseudocode I want to do something like this:
public class ExampleClass {
public static final Class<?>[] classes = new Class[]{MyClass1.class,
MyClass2.class, MyClass3.class, MyClass4.class, MyClass5.class};
public void myMethod() {
for (Class<?> c : DataBaseConfigUtils.classes ) {
MyObjectDAO<c.getType(), Integer> myObjectDAO = getMyObjectDAO(c);
ArrayList<c.getType()> list = myObjectDAO.queryAll();
for (c.getType() element : list) {
processElement(element);
}
}
}
public <T> MyObjectDAO<T, Integer> getMyObjectDAO(Class<T> c) {
return doSomething(c);
}
}
But there is nothing like Class.getType()
. So how to get the type of a class object?
Upvotes: 3
Views: 3487
Reputation: 2848
This is not possible in Java. The type is used only during the compilation and is erased. This information is not present in the bytecode or in the runtime environment.
https://docs.oracle.com/javase/tutorial/java/generics/erasure.html
Generics were introduced to the Java language to provide tighter type checks at compile time and to support generic programming. To implement generics, the Java compiler applies type erasure to:
- Replace all type parameters in generic types with their bounds or Object if the type parameters are unbounded. The produced bytecode, therefore, contains only ordinary classes, interfaces, and methods.
- Insert type casts if necessary to preserve type safety.
- Generate bridge methods to preserve polymorphism in extended generic types.
Type erasure ensures that no new classes are created for parameterized types; consequently, generics incur no runtime overhead.
Upvotes: 4
Reputation: 37645
Your generic method getMyObjectDAO
seems to answer your own question. If you have a variable with a wildcard in the type, you can use a generic helper method whenever you need to refer to the type in the code. You can refactor your code into this:
public class ExampleClass {
public static final Class<?>[] classes = new Class[]{MyClass1.class,
MyClass2.class, MyClass3.class, MyClass4.class, MyClass5.class};
public void myMethod() {
for (Class<?> c : DataBaseConfigUtils.classes ) {
act(c);
}
}
private <T> void act(Class<T> c) {
MyObjectDAO<T, Integer> myObjectDAO = getMyObjectDAO(c);
ArrayList<T> list = myObjectDAO.queryAll();
for (T element : list) {
processElement(element);
}
}
public <T> MyObjectDAO<T, Integer> getMyObjectDAO(Class<T> c) {
return doSomething(c);
}
}
It is important to be aware of the limitations of this. Suppose you have a variable of type List<?>
. While it is possible to use a private generic helper method that will enable you to treat it as a List<T>
and use the type T
in code, type erasure means that you can't query the type T
at runtime. So all of the following are illegal
if (T == String) { //do something; }
if (T.class == String.class) { //do something }
if (a instanceof T) { //do something }
The usual workaround for this is to make one of the arguments to the helper method a Class<T>
object, because you can do
if (clazz == String.class) { //do something }
(Note that this will not work if T
is itself a generic type, because you cannot write List<String>.class
, for example. There is a workaround called super type tokens for this.)
Since the objects you are using are Class
objects, type erasure should not cause you any problems at all.
Upvotes: 1
Reputation: 109
For example:
ParameterizedType superclass = (ParameterizedType)getClass().getGenericSuperclass();
this.entityClass = (Class<T>) superclass.getActualTypeArguments()[0];
But if you want to add as type Generic I suppose you have design errors. Best Practice for it - You should create Parent (abstract) class or Interface and use it in your code:
public abstract class ABaseEntity{
...
}
public class Child extends ABaseEntity{
...
}
Create base dao with your BaseEntity whiche will be return some entities extended you ABaseEntity :
public class AbstarctDAO<T extends ABaseEntity, PK extends Serializable> {
@PersistenceContext
protected EntityManager em;
protected Class<T> entityClass;
protected AbstarctDAO() {
}
@PostConstruct
public void init(){
final ParameterizedType superclass = (ParameterizedType)getClass().getGenericSuperclass();
this.entityClass = (Class<T>) superclass.getActualTypeArguments()[0];
}
@Override
public T create(T object) throws Exception {
em.persist(object);
em.flush();
return object;
}
...
}
Excecution example: 1.
AbstarctDAO dao = new AbstarctDAO();
try {
dao.create(new Child ());
}catch (Exception e){
}
2.
@ Stateless
@ Transactional
public class ChildDAO extends AbstarctDAO<Child , Long> {
@Transactional(Transactional.TxType.SUPPORTS)
public Child getChildByName(String name) {
...
return (Child)query.getSingleResult();
}
}
Upvotes: 0