How to get instance of generic in interface - java

I have an interface with generic
public interface MessageCallback<T extends JsonModel> {
void onMessage(T t);
}
And I wanna get instance of T.
I found a solution where I can use reflection
public static <T> Class<T> getGenericClass(Class actualClass, int index) {
ParameterizedType genericSuperclass = (ParameterizedType) actualClass.getGenericSuperclass();
// Get generic class
return (Class<T>) genericSuperclass.getActualTypeArguments()[index];
}
But it throws exception.
java.lang.ClassCastException: java.lang.Class cannot be cast to java.lang.reflect.ParameterizedType
I wanna know is there a solution without using reflection?
Extra. I also found this
class Foo<T> {
final Class<T> typeParameterClass;
public Foo(Class<T> typeParameterClass) {
this.typeParameterClass = typeParameterClass;
}
public void bar() {
// you can access the typeParameterClass here and do whatever you like
}
}
But its only for class. How I can solve my problem? Thanks for your answers.
And if you wanna know it isn't clean Java. It's in Android

About your first code, Class.getGenericSuperclass() returns the type representing the direct superclass of this class, that it Object in your case.
Class.getGenericInterfaces() that returns the Types representing the interfaces directly implemented by this class would be a better choice to retrieve the generic defined in the MessageCallback interface.
But it will probably not help you as the generic type will be which one statically declared in the MessageCallback interface : JsonModel and not which one defined in the subclass declaration that extends the interface.
About your second code, you should not worry about whether the parameter to capture the generic is Class or Type.
For example, the types declared in a generic class such as interface MessageCallback<T extends JsonModel> or a subclass of a generic class such as MessageCallbackImpl extends MessageCallback<MyJsonModel> are necessary classes as parameterized types can only be Classes. So storing the type of the generic type as Class is perfectly valid.
The Type class that is the common superinterface for all types in Java is much broader (raw types, parameterized types, array types, type variables and primitive types)
So to come back to your question : what you need is having a way to refer at runtime the generic type defined at compile and this idiom is a classical way to do that :
public Foo(Class<T> typeParameterClass) {
this.typeParameterClass = typeParameterClass;
}

You were on the right track.
Now suppose we have a generic interface, as in your example:
public interface MessageCallback<T extends JsonModel> {
void onMessage(T t);
}
And a concrete implementation of it:
class FooMessage {}
public class MyMessageCallback
implements MessageCallback<FooMessage extends JsonModel> {
#Override
public void onMessage(FooMessage t) {
System.out.println("Received foo");
}
}
You want to find the type passed into generic interface, MessageCallback, in this case FooMessage.
We can use reflection to find all interfaces that MyMessageCallback implements and for each interface, check if it is a generic interface then return all of its type parameters.
public static <T> Class<?>[] getGenericInterfaceParameter(Class clazz, Class<T> interfaceType) {
Class<?>[] result = new Class<?>[0];
// make sure interfaceType is a generic interface.
if(!interfaceType.isInterface() || interfaceType.getTypeParameters().length < 1) {
return result;
}
// get all interfaces implemented by concrete class.
Type[] interfaceTypes = clazz.getGenericInterfaces();
// for each interface the concrete class implements
// we check if that interface is actually equal to interfaceType
// and is a parametrized type,
// i.e has a type parameter.
// Once a match is found, we return the type parameters.
for(Type it : interfaceTypes) {
if(it instanceof ParameterizedType) {
ParameterizedType parameterizedType = (ParameterizedType) it;
if(!parameterizedType.getRawType().equals(interfaceType)) {
continue;
}
Type[] typeParameters = parameterizedType.getActualTypeArguments();
result = new Class[typeParameters.length];
for(int j = 0; j < typeParameters.length; j++) {
result[j] = (Class) typeParameters[j];
}
}
}
return result;
}
Use the method to find type parameter of MyMessageCallback:
Class<?>[] params = getGenericInterfaceParameter(
MyCallback.class,
MessageCallback.class
);
System.out.println(params[0].getTypeName()); // MyMessageCallback

Related

Java Generic Interface Return Generics

I found this code from a tutorial and I am guessing this method getUriBase return type is String, but not clear what part <T extends IEntity> is playing in this method and why it is placed in the beginning?
public interface IUriMapper {
<T extends IEntity> String getUriBase(final Class<T> clazz);
}
This is the convention of creating a generic method.
The syntax for a generic method includes a type parameter, inside
angle brackets, and appears before the method's return type. For
static generic methods, the type parameter section must appear before
the method's return type.
If you see then before your return type String you defining your type parameter T. Now, coming to <T extends IEntity>, by this basically you are creating a bounded type parameter, where-in you are telling the compiler that T should only be a subclass of IEntity.
An important thing to note is that you need to define <T extends IEntity> before your method (this is what you call "generic method", more info coming...) because your interface is not a generic type, suppose your interface was like below then you need not to define the T type parameter because compiler would know what is the T type parameter.
public interface IUriMapper<T extends IEntity> {
String getUriBase(final Class<T> clazz);
}
So, basically generic method are useful (or in other words meant for situations) when you want to define your own type. Consider below example where-in your generic type (your interface "IUriMapper") defines type parameter "T" but for method getUriBase you are creating a new type "E"
public interface IUriMapper<T extends IEntity> {
<E extends Number> String getUriBase(final Class<E> clazz);
}
This Oracle documentation is best source to learn Generics.
Generic Types
The type parameter section, delimited by angle brackets (<>), follows the class name. It specifies the type parameters (also called type variables) T1, T2, ..., and Tn.
public class Box {
private Object object;
public void set(Object object) { this.object = object; }
public Object get() { return object; }
}
To update the Box class to use generics, you create a generic type declaration by changing the code "public class Box" to "public class Box". This introduces the type variable, T, that can be used anywhere inside the class.
/**
* Generic version of the Box class.
* #param <T> the type of the value being boxed
*/
public class Box<T> {
// T stands for "Type"
private T t;
public void set(T t) { this.t = t; }
public T get() { return t; }
}
Source: https://docs.oracle.com/javase/tutorial/java/generics/types.html
Bounded Type Parameters:
There may be times when you want to restrict the types that can be used as type arguments in a parameterized type. For example, a method that operates on numbers might only want to accept instances of Number or its subclasses. This is what bounded type parameters are for.
public class Box<T> {
private T t;
public void set(T t) {
this.t = t;
}
public T get() {
return t;
}
public <U extends Number> void inspect(U u){
System.out.println("T: " + t.getClass().getName());
System.out.println("U: " + u.getClass().getName());
}
public static void main(String[] args) {
Box<Integer> integerBox = new Box<Integer>();
integerBox.set(new Integer(10));
integerBox.inspect("some text"); // error: this is still String!
}
}
Source: https://docs.oracle.com/javase/tutorial/java/generics/bounded.html

abstract class <T> - getClass type [duplicate]

I have a class like:
public abstract class BaseDao<T extends PersistentObject> {
protected Class<T> getClazz() {
return T.class;
}
// ...
}
But the compiler says to T.class;: Illegal class literal for the type parameter T.
How can I get the class of T?
It's definitely possible to extract it from Class#getGenericSuperclass() because it's not defined during runtime, but during compiletime by FooDao extends BaseDao<Foo>.
Here's a kickoff example how you could extract the desired generic super type in the constructor of the abstract class, taking a hierarchy of subclasses into account (along with a real world use case of applying it on generic EntityManager methods without the need to explicitly supply the type):
public abstract class BaseDao<E extends BaseEntity> {
#PersistenceContext
private EntityManager em;
private Class<E> type;
#SuppressWarnings("unchecked") // For the cast on Class<E>.
public BaseDao() {
Type type = getClass().getGenericSuperclass();
while (!(type instanceof ParameterizedType) || ((ParameterizedType) type).getRawType() != BaseDao.class) {
if (type instanceof ParameterizedType) {
type = ((Class<?>) ((ParameterizedType) type).getRawType()).getGenericSuperclass();
} else {
type = ((Class<?>) type).getGenericSuperclass();
}
}
this.type = (Class<E>) ((ParameterizedType) type).getActualTypeArguments()[0];
}
public E find(Long id) {
return em.find(type, id);
}
public List<E> list() {
return em.createQuery(String.format("SELECT e FROM %s e ORDER BY id", type.getSimpleName()), type).getResultList();
}
// ...
}
Actually, this is not as easy as it seems. There is a problem when you have rich type hierarchy and want to get generic parameter in the supertype. For example, you may have the following hierarchy:
public abstract class BaseDao<T extends BaseEntity> {
...
}
public abstract class SpecialDao<X extends SomeType, E extends BaseEntity> extends BaseDao<E> {
...
}
public class MyDao extends SpecialDao<TypeImpl, EntityImpl> {
...
}
Calling getClass().getGenericSuperclass() in an instance of MyDao returns SpecialDao<TypeImpl, EntityImpl>, but when you call it inside BaseDao method, you don't know how deep the generic hierarchy is. Moreover, as far as I know, you cannot obtain generic supertype of a supertype. Thus, when you invoke getClass().getGenericSuperclass().getRawType().getGenericSuperclass() (with some typecasting omitted for readability), you'll get BaseDao<E> (notice <E> instead of <T>). Since getRawType() strips all type-variable mapping from the type, we're starting with unmapped type variables X and E. Then getGenericSuperclass() just maps these type variables to their positions in BaseDao.
This behavior can be used so that we keep mapping from type variables to their actual values while traversing the type hierarchy. When we hit the class we want, we simply look up its type parameters in the map. Here is the code:
#SuppressWarnings("unchecked")
public static <T> Class<T> getGenericClassParameter(final Class<?> parameterizedSubClass, final Class<?> genericSuperClass, final int pos) {
// a mapping from type variables to actual values (classes)
Map<TypeVariable<?>, Class<?>> mapping = new HashMap<>();
Class<?> klass = parameterizedSubClass;
while (klass != null) {
Type type = klass.getGenericSuperclass();
if (type instanceof ParameterizedType) {
ParameterizedType parType = (ParameterizedType) type;
Type rawType = parType.getRawType();
if (rawType == genericSuperClass) {
// found
Type t = parType.getActualTypeArguments()[pos];
if (t instanceof Class<?>) {
return (Class<T>) t;
} else {
return (Class<T>) mapping.get((TypeVariable<?>)t);
}
}
// resolve
Type[] vars = ((GenericDeclaration)(parType.getRawType())).getTypeParameters();
Type[] args = parType.getActualTypeArguments();
for (int i = 0; i < vars.length; i++) {
if (args[i] instanceof Class<?>) {
mapping.put((TypeVariable)vars[i], (Class<?>)args[i]);
} else {
mapping.put((TypeVariable)vars[i], mapping.get((TypeVariable<?>)(args[i])));
}
}
klass = (Class<?>) rawType;
} else {
klass = klass.getSuperclass();
}
}
throw new IllegalArgumentException("no generic supertype for " + parameterizedSubClass + " of type " + genericSuperClass);
}
If Spring framework is available, you can do like here:
import org.springframework.core.GenericTypeResolver;
public abstract class BaseDao<T extends PersistentObject> {
protected Class<T> getClazz() {
return (Class<T>) GenericTypeResolver.resolveTypeArgument(getClass(), BaseDao.class);
}
}
If your class is abstract, you can try with this:
public class<T> getClassOfT() {
final ParameterizedType type = (ParameterizedType) this.getClass()
.getGenericSuperclass();
Class<T> clazz = (Class<T>) type.getActualTypeArguments()[0];
return clazz;
}
This only work if the instance is a direct subclass, and the type of the class you want is the first one (see the [0]).
If you have a large hierarchy of dao's, you can try fidn the BaseDao recursively and get the parametrized type
See a example here (see the output in the bottom)
Cheers and sorry for my bad english
Common way to sort this issue in a secure way is to add a constructor to store the class of the type.
Example in your context:
public abstract class BaseDao<T extends PersistentObject> {
private Class<T> classT;
BaseDao(Class<T> classT){
this.classT=classT;
}
protected Class<T> getClazz() {
return classT;
}
// ...
}
You might check out TypeTools (which I authored) for this:
Class<T> t = (Class<T>)TypeResolver.resolveRawArgument(BaseDao.class, getClass());
You can pass the type of class through the constructor of the abstract class, like this.
public abstract class BaseDao<T extends PersistentObject> {
private final Class<T> typeClass;
//Here in the constructor, you are asking for the actual Type Class.
BaseDao(Class<T> typeClass) {
this.typeClass = typeClass;
}
// ...
}
And in the concrete class pass the class type in the constructor.
public class BaseDaoImpl extends BaseDao<ActualType> {
BaseDaoImpl() {
//Here in the implementation, you pass the type class
super(ActualType.class);
}
}
The problem with this approach is that you cannot ensure that the type you are passing through the constructor is the actual type is being set in generic, so this can lead to issues if developers do not make sure they are passing the correct type through the constructor.

How to get (generic) type from class object

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?
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.
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.
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();
}
}

How to check does interface with generic fit to class

I have some interface with generic type interface DummyInterface<T> and i have class to which i have to set interface
class DummyClass<T>{
public void setDummyInterface(DummyInterface<T> dummyInterface){
//set interface
}
}
Imagine the situation where i store DummyClass with different generics in ArrayList. When i get class from list i don't know the generic of class, and i want to check if interface has the same generic or not;
For example i want to check like this
if(dummyInterface<SomeTypeIKnow>.getGenericType() == dummyClass.getGenericType()){
dummyClass.setDummyInterface(dummyInterface);
}
You can use something like TypeTools (a library that I authored) to resolve type arguments so long as the argument is captured in a type definition. For example:
interface DummyStringInterface extends DummyInterface<String> {}
Class<?> t = TypeResolver.resolveRawArgument(DummyInterface.class, DummyStringInterface.class);
assert t == String.class;
Not entirely sure I understand your question, but this code will allow you to get the Generic types for an object. They allow you to perform reflection on the generic parameters of an object.
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
public class GenericClassUtils {
public static <T> Class<T> getClassFromGeneric(
Object parentObj,
int oridnalParamterizedTypeIndex) throws Exception{
Type[] typeArray = getParameterizedTypeListAsArray(parentObj);
return (Class<T>)typeArray[oridnalParamterizedTypeIndex];
}
public static <T> Type[] getParameterizedTypeListAsArray(Object parentObj){
return ((ParameterizedType) parentObj.getClass()
.getGenericSuperclass())
.getActualTypeArguments();
}
}
Perhaps by calling something like this:
Class clazz = getClassFromGeneric(dummyClass, 0);
if (clazz.isInstance(SomeTypeIKnow.class)){
dummyClass.setDummyInterface(dummyInterface);
}

Passing generic subtype class information to superclass in Java

I've long used an idiom in Java for using the class information of a (non-abstract) class in the methods of its (generally abstract) ancestor class(es) (unfortunately I can't find the name of this pattern):
public abstract class Abstract<T extends Abstract<T>> {
private final Class<T> subClass;
protected Abstract(Class<T> subClass) {
this.subClass = subClass;
}
protected T getSomethingElseWithSameType() {
....
}
}
An example of a subclass thereof:
public class NonGeneric extends Abstract<NonGeneric> {
public NonGeneric() {
super(NonGeneric.class);
}
}
However, I'm having trouble defining a subclass of Abstract which has its own generic parameters:
public class Generic<T> extends Abstract<Generic<T>> {
public Generic() {
super(Generic.class);
}
}
This example is not compilable; likewise, it is not possible to specify the generic types using e.g. Generic<T>.class or even to use a wildcard like Generic<?>.
I also tried replacing the declaration of generic type T in the superclass to ? extends T, but that isn't compilable either.
Is there any way I can get this pattern to work with generic base classes?
The "pattern" (idiom) of passing an instance of Class<T> (typically to the constructor) is using Class Literals as Runtime-Type Tokens, and is used to keep a runtime reference to the generic type, which is otherwise erased.
The solution is firstly to change the token class bound to:
Class<? extends T>
and then to put a similar requirement on your generic subclass as you did with your super class; have the concrete class pass a type token, but you can type it properly as a parameter:
These classes compile without casts or warnings:
public abstract class Abstract<T extends Abstract<T>> {
private final Class<? extends T> subClass;
protected Abstract(Class<? extends T> subClass) {
this.subClass = subClass;
}
}
public class NonGeneric extends Abstract<NonGeneric> {
public NonGeneric() {
super(NonGeneric.class);
}
}
public class Generic<T> extends Abstract<Generic<T>> {
public Generic(Class<? extends Generic<T>> clazz) {
super(clazz);
}
}
And finally at the concrete class, if you declare the usage as its own class, it doesn't require a cast anywhere:
public class IntegerGeneric extends Generic<Integer> {
public IntegerGeneric() {
super(IntegerGeneric.class);
}
}
I haven't figured out how to create an instance of Generic (anonymous or not) without a cast:
// can someone fill in the parameters without a cast?
new Generic<Integer>(???); // typed direct instance
new Generic<Integer>(???) { }; // anonymous
I don't think it's possible, but I welcome being shown otherwise.
The major problem you have got here is, there is no class literal for concrete parameterized type. And that makes sense, since parameterized types don't have any runtime type information. So, you can only have class literal with raw types, in this case Generic.class.
Reference:
Java Generics FAQs
Why is there no class literal for concrete parameterized types? :
Well, that's fine, but Generic.class gives you a Class<Generic> which is not compatible with Class<Generic<T>>. A workaround is to find a way to convert it to Class<Generic<T>>, but that too you can't do directly. You would have to add an intermediate cast to Class<?>, which represents the family of all the instantiation of Class. And then downcast to Class<Generic<T>>, which will remove the compiler error, though you will an unchecked cast warning. You can annotate the constructor with #SuppressWarnings("unchecked") to remove the warning.
class Generic<T> extends Abstract<Generic<T>> {
public Generic() {
super((Class<Generic<T>>)(Class<?>)Generic.class);
}
}
There is no need in Class<T> subClass argument. Change:
protected Abstract(Class<T> subClass) {
this.subClass = subClass;
}
to:
protected Abstract(Class subClass) {
this.subClass = subClass;
}
and everything will compile.

Categories

Resources