How to check does interface with generic fit to class - java

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);
}

Related

How to get instance of generic in interface

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

Method return type using enclosed Generic class?

I am trying to write a generic request generator method which will return different objects like below:
GenricClass<Object1> genCls1 = getNewRequest(Object1.class);
GenricClass<Object2> genCls2 = getNewRequest(Object2.class);
GenricClass<Object3> genCls3 = getNewRequest(Object3.class);
I want this getNewRequest to return an object which has enclosing generic class object.
How should the signature of my getNewRequest method ?
public `?` getNewRequest(Class classtype) {...}
You can either declare a generic type parameter in the class that contains the method getNewRequest, or directly in the method.
For example, declare generic parameter T in the method getNewRequest:
public <T> GenricClass<T> getNewRequest(Class<T> classtype)
Using the classType instance of T as an argument and returning a GenericClass of the same class type. Somewhat like :
public GenericClass<T> getNewRequest(T classtype) {
}
something like that:
public <T> GenericClass<T> getNewRequest(Class<T> classtype) {
}

How to get main type of generic field with reflection in java?

Assume that i have these below classes in my project:
public class MyBaseEntity<T> {
T id;
}
public class MySubClass extends MyBaseEntity<Long> {
}
and now, i want to get main type of id(java.lang.Long) field of MySubClasswith java reflection, how can i do that?
UPDATE
i changed classes to this and added 2 new Class:
public class MySubClass3 extends MyBaseEntity<Integer> {
}
public class MySubClass2 extends MySubClass3 {
}
public class MySubClass extends MySubClass2 {
}
now, how can i get main type of id, in other word, if the depth of inheritance was dynamic how can i get the main type of id for a specific class?
Pass the type to the constructor of the base class
public MyBaseEntity(Class<?> clazz) {
this.clazz = clazz;
}
Well, you can define in runtime which class was used for your T parameter of MyBaseEntity using the approach like this:
Type type = MySubClass.class.getGenericSuperclass();
if(type instanceof ParameterizedType) {
Type parameterType = ((ParameterizedType) type).getActualTypeArguments()[0];
if(parameterType instanceof Class) {
System.out.println(((Class<?>)parameterType).getName());
// prints java.lang.Long
}
}
But it's quite error-prone approach. You may have more tricky inheritance or use wildcards like class SubClass<T extends Number> extend MyBaseEntity<T> and you will have to handle such cases specially. Thus I'd recommend you to use the approach suggested by #Reimeus.

Get array class of generic type

I have a class with a generic type.
import java.lang.reflect.Array;
public abstract class MyClass<T> {
private Class<T> clazz;
private Class<?> arrayClazz;
public MyClass() {
clazz = ClassUtils.getParameterizedClass(getClass());
arrayClazz = Array.newInstance(clazz, 0).getClass();
}
}
The Utils method reads the generic type of the given class so I don't have to pass the same class as a constructor parameter. What I'm trying to achieve is getting the array class of clazz.
For example if T is String then
clazz = String.class;
arrayClazz = String[].class;
I currently solved it by creating a new instance of T[] and reading its class. I wanted to know if there's a better way or if there are any downsides with this method.
Update
What I'm trying to do: I have a generic DataProvider which requests JSON from a server. I use GSON to parse the response.
public abstract class DataProvider<T> {
private final Class<T> resourceClass;
private final Class arrayClass;
protected DataProvider() {
this.resourceRootPath = resourceRootPath;
this.resourceClass = ClassUtils.getParameterizedClass(getClass());
arrayClass = Array.newInstance(resourceClass, 0).getClass();
}
public void get(String id) {
...
T obj = gson.fromJson(response.body().charStream(), resourceClass)
...
}
public void list(String id) {
...
T[] objs = gson.fromJson(response.body().charStream(), arrayClass)
...
}
}
You should look up Type Erasure, which may prevent a clean way of doing what you're asking for. (Generics can't help you here.)
The problem is that in Java, generic type data is used at compile time to ensure everything looks good... and then Java forgets about it entirely. The types aren't compiled in in the way you'd hope, they're just gone.
Because of that, your approach is (I think!) the cleanest, even if it feels hacky. You need to instantiate one and use reflection to get it's type.

Difference between Java Generic Parameters

What is the difference between passing in generic parameter some generic class with and without his generic parameter?
Example:
Simple Generic class:
public class Foo<T> { /*...*/ }
Simple class that extend simple generic class setting the generic parameter to some irrelevant type:
public class FooFoo extends Foo<Type1> { /*...*/ }
Another generic class
public class Bar<T> extends FooFoo { /*...*/ }
Our base class that as generic parameter need something that extends class Foo
public class TestFooClass<T extends Foo<?>> { /*...*/ }
And the question what is the deference between this two parameters
public class BarTestOne extends TestFooClass<Bar> { /*...*/ }
public class BarTestTwo extends TestFooClass<Bar<?>> { /*...*/ }
Problem
Class<T> class = (Class<T>) ((Foo)getClass().getGenericSuperclass()).getActualTypeArguments()[0];
In the first case code works in the second doesn't.
It looks like you are trying to determine the actual type that the TestFooClass is parameterized with?
In that context, the difference between using generic class with and without its generic parameter is that getActualTypeArguments()[0] will:
In the first case provide an instance of Class representing the raw type
In the second case provide an instance of ParameterizedType (thus one may get ClassCastException). If you call getRawType() on that ParameterizedType, you will get Class representing the raw type.
This:
BarTestOne one = new BarTestOne();
BarTestTwo two = new BarTestTwo();
Class<?> clazz1 = (Class<?>) ((ParameterizedType) one.getClass().getGenericSuperclass()).getActualTypeArguments()[0];
Class<?> clazz2 = (Class<?>) ((ParameterizedType) ((ParameterizedType) two.getClass().getGenericSuperclass()).getActualTypeArguments()[0]).getRawType();
System.out.println(clazz1.equals(clazz2));
This will return true.
Alas, any deeper answer is beyond my knowledge of generics.
Bar means Bar<Object> and Bar<?> doesn't. For example, if you have a List, you can add to it, if you have a List<?> you can't, because the compiler doesn't know if your object is compatible with the "actual generic type" of the object.
As for the reflection code, I don't know. It says getClass(), which depends on the object you call it on; in this case the object is obviously this... From where is this code called?

Categories

Resources