Getting generic parameter from supertype class - java

Say I have a parent interface/class like so
interface Parent<T> {}
And a number of implementing interfaces that fix the generic type.
interface Child extends Parent<Type> {}
Can I use reflection to get the instance of Class representing T if I have the Class object for Child. Something like this:
<T, I extends Parent<T>> I create(Class<I> type) {
Class<T> tType = ...
...
}
Currently I'm having tType be passed in as a parameter, but I'd like to simplify things if I can.

Yes, despite what the others have said, this info is available if you have access to the subclass' Class object. You need to use getGenericSuperclass along with getActualTypeArguments.
ParameterizedType superClass = (ParameterizedType)childClass.getGenericSuperclass();
System.out.println(superClass.getActualTypeArguments()[0]);
In your example, the "actual" type argument should return the Class for Type.

If you need to do anything non-trivial with generic types at runtime, consider Guava's TypeToken. It can answer your question (and many more!) while addressing some of the nuanced concerns raised by commenters:
private interface Parent<T> {}
private interface Intermediate<U, V> extends Parent<V> {}
private interface Child<Z> extends Comparable<Double>, Intermediate<Z, Iterable<String>> {}
public void exploreGuavaTypeTokens() {
final TypeToken<? super Child> token = TypeToken.of(Child.class).getSupertype(Parent.class);
final TypeToken<?> resolved = token.resolveType(Parent.class.getTypeParameters()[0]);
System.out.println(resolved); // "java.lang.Iterable<java.lang.String>"
final Class<?> raw = resolved.getRawType();
System.out.println(raw); // "interface java.lang.Iterable"
}

I don't think so. Read about type erasure: the generic types are used only for compile-time checking, and then discarded. They're not stored in the compiled class files so they're not available at runtime.

Related

Class of a generic Java type cannot be assigned to a variable whose Class type is upper bounded by a generic super type

I use Java 8. In my design a have a few simple classes which model value parameters such as FloatParameter or EnumParameter<E>. A have a common generic super class of these classes (GenericParameter<T>) which implements parameter name and its default value. The sub classes implement other attributes specific to them such as range in case of FloatParameter.
Moreover, I want to work with the types of the parameters regardless of their specific type. But I still want to bound the types in the way that they are sub types of GenericParameter<T>. In order to do that, I created a method such as process(Class<? extends GenericParameter<?>> paramType).
Now, the problem is that the EnumParameter.class cannot be assigned to a variable of type Class<? extends GenericParameter<?>> while FloatParameter.class can be.
Further I list the code for the classes to make it more clear and reproducible:
public class GenericParameter<T> {
protected String name;
protected T defaultValue;
}
public class FloatGenericParameter extends GenericParameter<Float> {
...
}
public class TypedGenericParameter<T> extends GenericParameter<T> {
...
}
Class<? extends GenericParameter<?>> fgpc = FloatGenericParameter.class; // ok
Class<? extends GenericParameter<?>> tgpc = TypedGenericParameter.class; // error: incompatible types: Class<TypedGenericParameter> cannot be converted to Class<? extends GenericParameter<?>>
Class<? extends GenericParameter> tgpc2 = TypedGenericParameter.class; // warning: [rawtypes] found raw type: GenericParameter
Finally, when using a non-generic base class, there is no problem:
public class Parameter {
....
}
public class FloatParameter extends Parameter {
...
}
public class TypedParameter<T> extends Parameter {
...
}
Class<? extends Parameter> fpc = FloatParameter.class; // ok
Class<? extends Parameter> tpc = TypedParameter.class; // ok
Please, do you have any suggestions?
I can go with process(Class<?> paramType) as a workaround or do casts, but I wanted to benefit from the static type checking by the compiler.
EDIT:
I would like to use the cast when registering factories that produce GUI components for each parameter type. The code looks like:
addParameterComponentFactory(EnumParameter.class, new ParameterComponentFactory() { ... })
In such case, the compiler would check the added parameter type at compile time. Also the code would be more self-explaining.
EDIT 2:
Currently, I am using the suggested approach to introduce a type parameter for the addParameterComponentFactory method. The signature looks like this:
public static <P extends GenericParameter<?>> addParameterComponentFactory(Class<P> clazz, ParameterComponentFactory pcf)
With this definition I am able to specify TypedParameter.class (EnumParameter.class - also one type param) as well as I obtain the static type checking.
Let's start with the core bits of your API. You have a generic Parameter<T>
type that represents some named parameter with a value of type T. You have
specialized GUI components designed to edit or display specific types of
parameters, and you want to be able to register factories to create these
components.
class Parameter<T> {
String name;
T defaultValue;
}
class ParameterComponent<P extends Parameter> {
void setParameter(final P p) {}
}
interface ParameterComponentFactory<P extends Parameter> {
ParameterComponent<P> newComponent();
}
class FloatParameter extends Parameter<Float> {}
class FloatParameterComponent extends ParameterComponent<FloatParameter> {}
class EnumParameter extends Parameter<Enum> {}
class EnumParameterComponent extends ParameterComponent<EnumParameter> {}
If I understand you correctly, you're running into trouble figuring out how to
declare a method that statically enforces a relationship between some
Parameter type and a factory for GUI components specialized for that type.
For example, you want to be able to write this:
addComponentFactory(EnumParameter.class, EnumParameterComponent::new); // OK
addComponentFactory(FloatParameter.class, FloatParameterComponent::new); // OK
addComponentFactory(FloatParameter.class, EnumParameterComponent::new); // ERROR!
The problem is related to the rules of generic subtyping, and you can work around them by employing a type variable instead of an embedded wildcard. This should give you the type checking you want, without the need for
nasty casting:
static <P extends Parameter> void addComponentFactory(
final Class<P> parameterType,
final ParameterComponentFactory<? extends P> factory) { ... }
Explanation[1]
Explain the difference between introducing a new type P extends Parameter<?> used in Class<P> and stating
directly Class<? extends Parameter<?>>
This is complicated, so bear with me. Let's talk a bit about wildcards, raw
types, and conversions. Consider the following:
// Scenario 1(a)
GenericParameter raw = /* some value */;
GenericParameter<?> wc = raw;
// Scenario 1(b)
Class raw = GenericParameter.class;
Class<?> wc = raw;
// Scenario 2
Class<GenericParameter> classOfRaw = GenericParameter.class;
Class<GenericParameter<?>> classOfWC = classOfRaw;
Scenarios 1(a) and 1(b) both compile for the same reason: because a raw type
G may undergo an unchecked conversion
to any parameterized type of the form G<T_1, ..., T_n>.
Scenario 2 does NOT compile. But why?
In Scenario 2, neither side in the second assignment is a raw type. For the
assignment to be valid,
there must be either an identity conversion or a widening conversion
from the right-hand type to the left-hand type. For widening conversions on
reference types, the left-hand type must be a supertype of the right-hand type.
When these types are generic, the rules of generic subtyping
apply. Specifically, the type arguments on the left-hand side must
contain
the type arguments on the right-hand side.
An assignment from Class<String> to Class<? extends Object> is valid.
Class<String> is a generic subtype of Class<? extends Object> because
? extends Object contains String. In Scenario 2, for the second
assignment to be valid, GenericParameter<?> would have to contain
GenericParameter, but it doesn't. T is not a subtype of T<?>;
T is a supertype of T<?>. Thus, by the generic subtyping rules,
Class<T> is not a subtype of Class<T<?>>, and the assignment is not
valid.
So why does the following work?
public static <P extends GenericParameter<?>> addParameterComponentFactory(
Class<P> clazz,
ParameterComponentFactory pcf)
addParameterComponentFactory(EnumParameter.class, new ParameterComponentFactory() {})
In the call above, type inference on P is driven entirely by the
Class<P> argument. You are passing a Class<EnumParameter>, so P
in this case gets bound to the raw type EnumParameter. For the constraint
P extends GenericParameter<?> to be satisfied, GenericParameter<?>
must be assignable from EnumParameter, and it is assignable via an
unchecked conversion, just like in Scenarios 1(a) and 1(b).
[1] This explanation is blatant plagarism
an amalgamation of other excellent Stack Overflow answers, mostly by
radiodef.

Can generics infer a related type?

Given
public class Foo {
public static class FooBuilder { ... }
}
I want to write a method on a third class that returns Foo, given Foo.FooBuilder.class
i.e.
Foo f = x.make(Foo.FooBuilder.class, someData);
Is it possible to declare a signature using generics that can imply the return type? Is there some language feature that lets me say "type U is outer class of type T"?
Obviously, it is possible to specify that type extends, or is the base of, a generic type (U extends T or U super T, respectively) but I am looking for U outer T which is, I think, more than Java can offer, even indirectly, at least in 1.7, which I am targeting.
So far, I have simply declared both inner and outer types, which works but is a wider definition than I am after and looks clumsy too.
public <TYPE,BUILDER> TYPE make(Class<BUILDER> builderClass, Map<String,Object> data) {
// Construct TYPE
}
Is there a way to infer TYPE without explicitly providing a template parameter?
There is a Class#getDeclaringClass method that may work in your case.
Quoting the docs:
If the class or interface represented by this Class object is a member of another class, returns the Class object representing the class in which it was declared.
EDIT:
After the clarification of OP, here is the new suggestion:
You create an generic interface to mark all your nested classes:
public interface Nested<P> {
}
Then you apply it to your Foo.Bar class like this:
public class Foo {
public static class Bar implements Nested<Foo> {
}
}
Then in your factory you can have the following:
public <P> P make(Class<? extends Nested<P>> clazz, Map<String, Object> someData) {
// do whatever you need to do
return (P) clazz.getDeclaringClass();
}
However, with this construct, there is not way to validate it your nested class is the real class, declared when implementing the generic interface.

Anyway to pass a generic type in a constructor to a parent class constructor?

Is there anyway to get a generic type in a class constructor in order to pass it to a parent constructor?
Given base class:
public class BaseSupport<T>{
private Class<T> type;
public BaseSupport(Class<T> type){
this.type = type;
}
}
Is there anyway to create a subclass to do this?
public class Support<T> extends BaseSupport<T> {
public Support() {
// is there anyway to know what "T" is here?
super( T.class );
}
}
And then finally, I would simply be able to create a class like:
public class MyClass extends Support<OtherClass>{
// no need to explicitly define a constructor here since the Support class handles it
}
I know Guava has TypeToken to help with retrieve generic type information, but given that super() must be the first method called in a constructor, I can't use it to extract the type information to pass to the parent class.
I suspect that this isn't feasible, but thought I would ask to see if there are any features/tricks that I don't know about in Java 7 since 'T' would be available at compile time.
Did you see the option mentioned in the TypeToken docs?
Capture a generic type with a (usually anonymous) subclass and resolve it against a context class that knows what the type parameters are. For example:
abstract class IKnowMyType<T> {
TypeToken<T> type = new TypeToken<T>(getClass()) {};
}
new IKnowMyType<String>() {}.type => String
You could effectively do this.
public class MyClass extends Support<OtherClass>{
// no need to explicitly define a constructor here since the Support class handles it
public MyClass() {
super(OtherClass.class);
}
}
And in support, have a constructor that accept a Class type and call the super keyword as I have done above (eliminating T.class all together).
Update: Alternatively, you can use Reflection to get ParameterizedType on your BaseSupport class and not need to provide an argument to your BaseSupport public constructor.
Resource:
Reflecting Generics.
Related Answer on StackOverflow.

How to declare a Class<?> object such that is is an Enum AND an Interface in Java

I have a utility class that needs to work on a generic Class but must be restricted to those that are an enum and implement a particular interface.
// These two work
Class<? extends Enum<?>> enumClass;
Class<? extends MyInterface> interfaceClass;
// This is what I want but does not work
Class<? extends MyInterface & Enum<?>> enumAndInterfaceClass;
For generics I can successfully use this
public class MyClass<T extends Enum<T> & MyInterface> {
public MyClass(Class<T> theClass) {
...
}
}
However I can't use the Generics everywhere and need to declare it separately. I am not sure if this is even possible.
So my question boils down to how can I declare a member variable with those constraints?
So Currently MyClass is a singleton then as needed the enum/interface can be updated. The return values of its operations will change depending on which enum it is given. I would like to not have the generics on it since that would require creating a new instance for every change to the enum. There is a lot of code using it already so deviating from the singleton is not going to be approved. So a reference must be kept. I suppose I could only enforce the Interface requirement then check in the setter method that it is an enum throwing an exception otherwise but that is not ideal.
Edit (Updated question and added more detail)
As far as I remember, you can only declare intersection types (this is what & creates) for type parameters of classes and methods. You can not declare a local variable with an intersection type directly; you can create such variables with the aid of a class or method type parameter, as seen in the answer of milkplusvellocet.
See the JLS reference in this answer to a similar question:
https://stackoverflow.com/a/6643378/282229
This should work:
public interface MyInterface {
void foo();
}
public final class Utils {
public static <E extends Enum<E> & MyInterface> void doWork(Class<E> clazz) {
for(E enumConstant : clazz.getEnumConstants) {
enumConstant.foo();
}
}
}
EDIT I didn't notice your line about using the captured type as a local variable. You can of course use this throughout the body of the parameterised method, see revised snippet above.

AbstractFactory with generic types in Java: a design problem

I have the following 2 interfaces accordingly to abstract factory pattern:
public interface GenericObjectInterface<T extends Number>{
public T getResult();
}
public interface AbstractFactoryInterface{
public <T extends Number> GenericObjectInterface<T> createGenericObject();
}
I have an abstract class implementing GenericObject, but it's still unaware of the concrete type (it does only generic operations on Number):
public abstract class GenericAbstractClass<T extends Number> implements GenericObjectInterface<T>{ }
Then I have a series of concrete class extending that perform generic parameter substitution:
public class IntegerObject extends GenericAbstractClass<Integer>{
public Integer getResult(){}
}
....
Now, from inside an implementation of the factory I build the concrete type, that's implementing GenericObjectInterface but has lost it's generic parameter:
public class ConcreteFactory{
public <T extends Number> GenericObjectInterface<T> greateGenericObject(Class<T> c){
if (c.class.isInstance(Integer.class)){
IntegerObject obj = new IntegerObject();
//I would like to return obj
GenericObjectInterface<T> a = new IntegerObject(); //errror
GenericAbstractClass<T> a = new IntegerObject(); //errror
return a;
}else if (c.class.isInstance(Double.class)){
}
}
}
I would like to return obj that implements GenericObjectInterface but I don't know how can I do it.
how can I solve this?
I'm used to abstract factory but I've never used it with generics. Am I doing some mistakes in interpreting the pattern?
If your method returns an IntegerObject why don't you just return GenericObjectInterface<Integer>? You already know the parameter type.
In that case, just add a generic parameter to AbstractFactoryInterface, too:
public interface AbstractFactoryInterface<T extends Number> { ... }
public class ConcreteFactory implements AbstractFactoryInterface<Integer> { ... }
In your implementation the type of T would be inferred from the assignment, and thus you could do this:
GenericObjectInterface<Double> g = new ConcreteFactory().greateGenericObject();
In that case T would be Double but you'd use Integer internally, resulting in this:
GenericObjectInterface<Double> a = new IntegerCell();
Since the compiler can't ensure that T will always be of type Integer it won't allow you to do that assignment.
Abstract factory is characterized by the factory method returning an interface or abstract class reference instead of the concrete reference. It does not extend to type parameters.
Think of it this way: should you be able to do this?
public class ConcreteListFactory {
public <T> List<T> createList() {
return new ArrayList<String>();
}
}
What if the caller wanted a List<Integer>?
If you want your factory to return a generified type, you should have your concrete class accept the type parameter. Otherwise have your factory method return a GenericObjectInterface<Integer>.
Alternatively, you could have your method accept a type token (Integer.class). For example:
public <T extends Number> GenericObjectInterface<T> createGenericObject(Class<T> clazz) {
if ( clazz.equals(Integer.class) ) {
return (GenericObjectInterface<T>) new IntegerObject();
}
}
This will result in an unchecked cast warning but you can prove to yourself that it is safe, and thus suppress the warning or ignore it.
Generally, factories are not implemented as generics because you can't examine the type of the generic to determine the type of object to create (you can't do T.getClass) which is why #Mark's example causes the class to be passed in as an argument.
I think, more usually you would have multiple concrete factories. One for each Number type that you intend to support.
public interface AbstractFactoryInterface<T extends Number> {
public GenericObjectInterface<T> createGenericObject();
}
class IntegerFactory implements AbstractFactoryInterface<Integer>...
class LongFactory implements AbstractFactoryInterface<Long>...
You could then create a Map<Class, AbstractFactoryInterface>...
Map<Class, AbstractFactoryInterface> myMap = ...;
myMap.put(Integer.class, new IntegerFactory());
myMap.put(Long.class, new LongFactory ());
casting is perfectly fine here. if c==Integer.class, then T=Integer, casting GOI<Object> to GOI<T> is absolutely correct. It is a checked cast because you have checked that T=Integer before casting, therefore the unchecked warning can be legitimately suppressed.

Categories