Get generic type of method - java

Maybe this have been answered before, but I did not find it here. Consider the following line of code:
public static <T> T getAs() { ... }
It is possible to obtain the object Class<T>, by reflection ?
For clarification, im not looking the generic type of a class, like in
class Foo<T> {
public T get() { ...}
}
This can be done in c# at it is really handy, for example
class Foo {
private List<A> items;
public <T extends A> T first() {
Class<T> clazz = //Magic??
foreach (A a : items) {
if (clazz.isInstance(a)) return (T)a;
}
return null;
}
}
Used like this:
SubClass s = fooInst.<SubClass>first();

Sometimes, it is indeed possible to get hold of generic type information even after compilation. In theory, this would even be possible for generic method calls. Spoiler, this is a bad idea. For academic reasons, let's however consider how this would be possible:
Check the execution stack from within the method.
Extract the calling class.
Locate and interpret the calling class's class file and parse its calling method's byte code.
Find the line where the method is called from.
Emulate javac's type inference mechanism and locate the same type for T that javac would have infered.
Load the class by its name you found for T.
This will of course not work very well and it would be broken if a type for T was specified explicitly in the source code. And you would not want to do this as your method call would suddenly require IO.
What you probably want is to return :
<T> T getAs(Class<? extends T> type) { ... }
In this case, you require the user to supply you with the required type but you do it in a type-safe manner.

Related

Check type of Predicate generic

I'm having 2 classes, their internals doesn't matter at all.
class ClassA {
//...
}
class ClassB {
//...
}
And I'm having 2 predicates that use those classes, let's say they look like this
private Predicate<ClassA> classAPredicate() {
return Objects::nonNull;
}
private Predicate<ClassB> classBPredicate() {
return Objects::nonNull;
}
Now, I'm having generic method in external library that is already beeing used by many users and unfortunatelly, it has pretty generic input parameter which is Object which in 90% of cases is Predicate.
What I need to do, is to extend this method functionality by checking type of passed Predicate and based on that, perform some operations.
public void test(Object obj) {
Predicate predicate = (Predicate)obj;
if(predicate.getClass().isAssignableFrom(ClassA.class)) {
System.out.println(predicate.test(new ClassA()));
// logic specific to Predicate<ClassA>
} else {
System.out.println(predicate.test(new ClassB()));
// logic specific to Predicate<ClassB>
}
}
But, during tests I'm passing both Predicates and it fails with Exception in thread "main" java.lang.ClassCastException:
test(classAPredicate());
test(classBPredicate());
I've been debugging and isAssignableFrom() is always returning false so the error is obvious here. I'm not sure if that is the right approach, but I didn't came up with anything else yet. Is there any way to check what is the type of that Predicate?
I know that what I'm trying to implement isn't ideal, but that is current requirement...
In the above, the predicate class is not assignable from Class A.
if(predicate.getClass().isAssignableFrom(ClassA.class))
This causes the else condition to run which passes an instance of B to the Predicate for type A which causes a cast exception. Due to type erasure, it will not be easy to resolve whether an instance of A or B should be passed to the predicate. 3 options are:
Try each input type until one doesn't throw a ClassCastException.
Handle the expected behavior in a new method instead of the existing test function.
Define a more specific interface than Predicate which also has a method to get the type the predicate tests and use the test type in the condition instead. Ex:
public interface TypedPredicate<T> extends Predicate<T> { Class<T> getTestType(); }
Well,
I have been doing Java Generics for going on three years now. I can cite a dozen Stack Overflow posts about "Reifying Java Generics" here: SO1, SO2, SO3. Most importantly, if you are intending to write Java for years and years, you must know that the "Generic Type Parameter" are simply NOT ACCESSIBLE at Run-Time without fields, or extra methods to retrieve them. Java Generics (The syntax that looks like: STUFF<TYPE> with the greater-than, less-than symbols is STRICTLY A COMPILE-TIME FEATURE). At RunTime, the JRE simply has no idea what the Type of the Type-Parameter is - and all it can do is throw ClassCastException if an attempt to misuse occurs.
NOTE: 'Misuse' the generic type such that it throws ClassCastException should sound odd if you are thinking that the JRE does not know and does not care what the type of the type parameter is. Mostly, the way exceptions are thrown, is such that if the code you write inside of a generic makes presumptions, and if it has made faulty presumptions, then this exception will throw.
Read Sun / Oracle's "To Do" list about "Reifying Generic Type Parameters." Also, most importantly, this concept has a very real name that you should read about all the time in Java - and it is called "Run Time Type Erasure" The solution posted before this Stack Overflow Answer says to use try-catch (ClassCastException) blocks, which is, actually, a valid answer.
ALSO: The answer about creating this type of TypedPredicate<T> extends Predicate<T> is not the correct answer if you intend to use your TypedPredicate<T> in any way that expects to allow Java Lambda Syntax to work with it. When you add the following method:
public interface TypedPredicate extends Predicate { Class
getTestType(); }
You will not be able to use the syntax #FunctionalInterface - which is one of the primary benefits of the class java.util.function.Predicate<T> Furthermore, there is a more severe problem in that, the Type of T is not accessible to the programmer and is not known at RunTime by the JRE
You see this part right here (since the answer has a green check mark):
{ Class<T> getTestType(); }
// Can you answer what you would write inside the method body of this
// 'extra-method' that you have added to Predicate<T> ???
The following implementation of a class that extends "Predicate" cannot be instantiated without a constructor. It cannot be called a "#FunctionalInterface" and lambda-expression cannot be used to create them:
// #FunctionalInterface (Commented Out)
public class TypedPredicate<A> implements Predicate<A>
{
public boolean test(A a) { return pred.test(a); }
// This is how the "Class of A" becomes accessible. It this
// version it is a public (and final) field.
public final Class<A> className;
// NOTE: This is the most important part here, the class of
// Variable-Type Parameter 'A' must be passed as a parameter
// to the constructor. The programmer *LITERALLY* has to tell
// the code what type 'A' actually is! This is the *BANE* of
// what I call the Java-Erasure-Fiasco programming.
public TypedPredicate(Predicate<A> pred, Class<A> className)
{
this.pred = pred;
this.className = className;
}
// Again, because a constructor is necessary, this cannot be
// called a "Functional Interface" and it will not work very
// much like a java.util.function.Predicate<T>, but it will
// indeed implement the interface.
}
The best solution would realign whatever logic you have such that you do not need to guess what type a Predicate is! The next best thing would be to try the catch (ClassCastException) version that was suggested in the previous answer.
FINALLY: This idea regarding the java.lang.Class.isAssignableFrom(...) has the right idea behind it - but only if you actually have the Class<T> clazz as an instance in front of you, so to speak. The only way to get an instance of Class<T> would be to pass it to a constructor as in the example I have posted.

Does reflection not respect map generic types? [duplicate]

Imagine the following scenario:
class MyClass extends OtherClass<String>{
String myName;
//Whatever
}
class OtherClass<T> {
T myfield;
}
And I am analyzing MyClass using reflection specifically (MyClass.class).getDeclaredFields(), in this case I will get the following fields (and Types, using getType() of the Field):
myName --> String
myField --> T
I want to get the actual Type for T, which is known at runtime due to the explicit "String" in the extends notation, how do I go about getting the non-genetic type of myField?
EDIT RESOLVED:
Seems like the answer is "you can't". For those who may look at this question later I'd recommend using Jackson (I was trying to do this to generate JSON) and annotating your classes and fields in such a way so that Jackson is aware of the inheritance hierarchy and can automatically do what the correct answer below suggested.
This can be achieved with reflection only because you explicitly used String, otherwise this information would've been lost due to type erasure.
ParameterizedType t = (ParameterizedType) MyClass.class.getGenericSuperclass(); // OtherClass<String>
Class<?> clazz = (Class<?>) t.getActualTypeArguments()[0]; // Class<String>
I found a nice explanation here:
When runtime inspecting a parameterizable type itself, like java.util.List, there is no way of knowing what type is has been parameterized to. This makes sense since the type can be parameterized to all kinds of types in the same application. But, when you inspect the method or field that declares the use of a parameterized type, you can see at runtime what type the paramerizable type was parameterized to.
In short:
You cannot see on a type itself what type it is parameterized to a runtime, but you can see it in fields and methods where it is used and parameterized.
In code:
You can't see T here:
class MyClass<T> { T myField; }
You can see the "T" here:
class FooClass {
MyClass<? extends Serializable> fooField;
}
Here you would be able to tell the type and type parameters of fooField.
See getGeneric*() methods of Class and Method.
By the way, I often see this (shortened):
Class fieldArgClass = (Class) aType.getActualTypeArguments()[0];
This is not correct, because getActualTypeArguments() may, and often will, return TypeVariable instead of class - that's when the generic is <? extends SomeClass> instead of just <SomeClass>. It can go deeper, imagine:
class FooClass {
MyClass<? extends Map<String, List<? extends Serializable>>> fooField;
}
So you get a tree of Types. But that's a bit off-topic. Enjoy :)
This is a classic example of why reflection is not a great idea.
What you can get from a program by reflection are only those facts that the compiler people for the language chose to make available.
And they generally can't afford to make everything available; they'd sort of have to keep the raw program text around.
All the other facts about your code are thus not available to the reflectee.
The cure for this is to step outside the language and use a tool that can provide any arbitrary bit of information about the code. Such tools are called Program Transformation Systems (PTS).
A PTS parses the source code and builds an AST the represents it. A good PTW will build an AST that holds essentially everything about the code (operators, operands, punctuation, comments) so that it can be inspected. Normally a PTS will record the line/column position of language tokens so even layout information is available; extreme PTS will record the whitespace in the gaps between tokens or at least know how to read the original text file when necessary if asked about it. This AST is in essence the equivalent of the full text I said would be necessary, but in a more convenient form to process.
(PTSs have one other very nice property: they can modify the AST and regenerate code for the modified program. But that is above and beyond reflection so I won't comment further on this aspect).
Generic types are not known at runtime. Only the compiler knows about them, checks that your program is typed correctly, and then removes them.
In your particular case, calling MyClass.class.getGenericSuperclass() might give you the information you need, because for some strange reason, the concrete types used when inheriting are kept in the class descriptor.
greate work around here. it is call the "Gafters Gadget" pattern. it is used by jackson and google libraries such as guava.
/**
* References a generic type.
*
* #author crazybob#google.com (Bob Lee)
*/
public abstract class TypeReference {
private final Type type;
private volatile Constructor<?> constructor;
protected TypeReference() {
Type superclass = getClass().getGenericSuperclass();
if (superclass instanceof Class) {
throw new RuntimeException("Missing type parameter.");
}
this.type = ((ParameterizedType) superclass).getActualTypeArguments()[0];
}
/**
* Instantiates a new instance of {#code T} using the default, no-arg
* constructor.
*/
#SuppressWarnings("unchecked")
public T newInstance()
throws NoSuchMethodException, IllegalAccessException,
InvocationTargetException, InstantiationException {
if (constructor == null) {
Class<?> rawType = type instanceof Class<?>
? (Class<?>) type
: (Class<?>) ((ParameterizedType) type).getRawType();
constructor = rawType.getConstructor();
}
return (T) constructor.newInstance();
}
/**
* Gets the referenced type.
*/
public Type getType() {
return this.type;
}
public static void main(String[] args) throws Exception {
List<String> l1 = new TypeReference<ArrayList<String>>() {}.newInstance();
List l2 = new TypeReference<ArrayList>() {}.newInstance();
}
}
There is no direct way to get the actual type because of the Type Erasure. However you can use the following way:
in your OtherClass<T>, write the following abstract method:
protected abstract class<T> getClazz();
Then in MyClass, you implement the method:
#Override
protected Class<String> getClazz(){
return String.class;
}
then you can call getClazz() to get the class.

Java: factory with method type parameters for class generic

Initial Situation:
I created a factory interface for some other generic interface A<T>:
public interface Factory<T, X extends A<T>> {
public X create();
}
Problem Description:
Now i have the problem that i need to instantiate a factory for every single type T. This becomes very unhandy, especially if some code wants to do some transformation from A<T> to A<T2>, where T2 is some previously unknown type or there are so many different T2, that i do not want to specify hundreds of factories for each special case.
The Goal:
I would like to pass the type T as a generic parameter of the create method. Such that i get something like (Attention, not correct Java :-) ):
public interface Factory<X extends A<?>> {
public <T> X<T> create();
}
An implementation of Factory might then simply do something like:
public class Factory4B implements Factory<B> {
public <T> X<T> create() {
return new B<T>();
}
}
Writing the above version of the interface down gives the error message for the return value of create:
The type X is not generic; it cannot be parameterized with argument
The Question:
Is there some way to realize such a generic factory, or do i need to use a totally different approach? I want to be able to specify X at the class level, such that i can instantiate X easily. I do not want to create a single Factory for every parameter T
Thank you for your time to answer this question in advance.
Rethinking the problems based on the below comments (27.4.15)
Rethinking the problem based on the comments below, my question is not possible to realize as it is not possible to guaranty that the generic parameters are still present in the subclasses of A<T>, or in other words: there is no inheritance of generic parameters.
Example:
Lets think of a class C which is derived from A<String>.
It is not possible to create C<Integer> as C has no type argument.
Therefore, there exist no general Factory, that might create C<Integer>
No, this is not possible with generics alone. Due to "type erasure" the type of T is not there anymore at runtime, so Java doesn't know what constructor to call.
You'll have to find a way to pass the type of T to your class at runtime. In, Java you can use the class Class<S> as a runtime type token. Then your code might look something like this:
public <T> X<T> create(Class<T> classOfT) {
T t = classOfT.newInstance();
return new X<T>(t);
}

Java Generics: Returning object of generic class with type parameter that is a super of argument T

I am trying to accomplish something with Java generics and am having a hell of a time since the approaches I would instinctively take do not work in this language, due to type erasure. I can cobble something reasonable together, though, if I get get the following to work. I have two classes:
class A {}
class B extends A {}
And a third class:
class C<T extends A> {}
I want a generic factory method that will return an instance of C, if I give it an instance of either A or B. A first attempt might look like this:
<T extends A> C<T> getObject(T t) { ... }
The issue I am having, which I suppose is not very unique, is most easily explained with the following line:
B b = new B();
C<A> = getObject(b);
The way I have defined getObject, the above call will return an object of type C<B>, which is not C<A> and does not inherit from C<A>, so this will not compile.
What I want to know is: is it possible to invoke some generics magic so that the compiler chooses the generic type T in getObject to be the superclass involved in the above function call, namely A?
Thanks so much!
One thing you can do is change the declaration to be like this:
// (I've deviated from Java generic naming convention for clarity)
<TRet extends A, TArg extends TRet> C<TRet> getObject(TArg arg) { ... }
So now the return type and argument type are inferred independently:
TRet is inferred based on the assignment type of the return value.
TArg is inferred based on the type of the argument.
But TArg still must be TRet or a subclass of TRet. (Or looking at it in the other direction, TRet must be TArg or a superclass of TArg.)
Though I think that is a bit of an ordeal. Too, it's already been mentioned in comments that the singular-typed version compiles on Java 8.
But this:
I can cobble something reasonable together, though, if I get get the following to work.
kind of makes me wonder. It seems like you've described an attempted solution but not the actual problem and it makes me wonder if our suggestions are actually helpful here. If they are, excellent, but if they aren't, don't hesitate to edit the OP or comment with clarification.
I am going ahead and "steal the answer" (see question comments :)).
There is nothing wrong with your class definition. Sometimes you just need to give a hint to the compiler to help it with type inference (guessing what it type should be substituted instead of the generic parameter) when calling a generic method:
public class Test {
static class A { }
static class B extends A { }
static class C<T extends A> { }
public static <T extends A> C<T> getObject(T obj) {
return null; // We don't need to construct anything here
}
public static void main(String[] args) {
// This compiles just fine
C<A> result1 = Test.<A>getObject(new B());
// Of course you can just type-cast the argument
C<A> result2 = Test.getObject((A) new B());
}
}
UPDATE (again, credits to Sotirios) Java 8 clearly has an improved generic type inference and your code would work without the explicit parameter specification as shown above (i.e. C<A> result = getObject(new B()); would simply work out of the box).

Are wildcard generics really needed?

for example:
public String add(Set<?> t){
...;
}
public <T> String add(Set<T> t){
...;
}
The first uses wildcard generics; the second is the normal form of a generic method.
What's the difference?
In what situation do we need wildcard generics, not the normal form of generics?
Here is a situation where wildcards are required. This method takes a List<List<?>>, which is a list of lists. The method can add lists of different component types into it:
public void foo(List<List<?>> t) {
t.add(new ArrayList<String>());
t.add(new ArrayList<Integer>());
}
You cannot do this using generic type parameters without wildcards. For example, the following does not work:
public <T> void foo(List<List<T>> t) {
t.add(new ArrayList<String>()); // does not compile
t.add(new ArrayList<Integer>()); // does not compile
}
Since support for generics was added, using a parameterized type without providing a type parameter usually causes a compiler warning. On the other hand, there are situations where you don't care at all what the type parameter is (i.e. you don't use the type anywhere) or, even worse, you might not know what T is at all, and using <?> lets you express just that without causing a compiler warning.
Possible use case for the "don't care" case (very simple for brevity, but you get the idea):
public void clearList(List<?> list) {
list.clear();
}
An example for the "don't know" case: an actual method signature from Class class:
static Class<?> forName(String className);
Here the method returns an object of some Class type. Class is generic but of course you don't know the type because it depends on the className parameter which is resolved at runtime. So you can't put T here since T is not known at compile time (even for a particular call site), and using just Class without type parameter would be a bad practice and cause a compiler warning.
The wildcard form is when you don't mind what types of objects you are handling.
The generics form allows you to add contraints on the type of objects handled.
An example use case could be the following :
a generic repository with add/update/remove methods, you define common behavior using the generic type :
public class Repository<T>{
public void add(T t){...}
public void update(T t){...}
public void remove(T t){...}
}
Then to make a repository for Apple and Banana you just extend this class and replace T with the real type :
public class AppleRepo extends Repository<Apple> {}
public class BananaRepo extends Repository<Banana> {}
If the generic Repository was declared as Repository<?>, it would not be good because it is not restricted to Banana, and you would not be able to use Banana specific methods inside it without casting objects;
Also the generics allow you to express further constraints, for example
Repository<T extends Fruit>
allows you to restrict the generic repository class to fruits. And you will be able to make calls to Fruit methods in its code.
There's not difference in calling the methods.
In the second method (add(Set<T>)) you can create variables of type T:
public <T> String add(Set<T> t){
T item = t.iterator().next();
//....
}
That gives you some additional type checking.
In the first method you're left with using Object.

Categories

Resources