Java reflection getDeclaredMethod [duplicate] - java

How to call a Custom Generic method by reflection in java?
class Person
{
public <T> void print(T t)
{
System.out.println(t.toString());
}
}

Generics are erased at compile time, they only provide extra information to the compiler to determine errors. They do not actually change the signature of the method in the .class file.
This means that you call a generic method by reflection in Java exactly the same way as you would call a non-generic method in Java, except that instead of specifying a type of T, you would specify a type of Object.
There are so many tutorials on how to call a regular method by reflection that I hesitate to add yet another; however, if you really need direction on how to call a method by reflection, please add a comment below and I'll add the necessary code.
If you find that things are not working as expected, you can always run javap on the compiled class file to verify that you are using the right objects in the argument list. It might be possible that if you specify a <T extends List> type generic signature, the resulting parameter object might actually be a List object.

This works for me.
Method method = Person.class.getMethod("print", Object.class);
method.invoke(new Person(), "this is a string");
method.invoke(new Person(), 273);
method.invoke(new Person(), new Object());
printing
this is a string
273
java.lang.Object#addbf1
Of course the theory behind this is explained beautifully in #Edwin's answer.

To highlight the point given in Edwin's answer, where we are using extends in a generic type: if you have a class like
GenericHibernateDao<T extends Serializable>
, and a method
public T save( T entity ) {};
to invoke the method save using reflection you have to use the Serializable class, i.e., you need to use:
Method method = GenericHibernateDao.class.getMethod(methodName, Serializable.class);
and not the Object.class as the parameter, since we are using
<T extends Serializable>

Related

Generics in loop, trying to avoid a cast

I have a method call in a loop currently that does not compile:
for (Example example : Util.getExample(List.class)) {
// Do something with example
}
Util:
public class Util {
public <T> T getExample(Class<T> clazz) {
//...
}
}
The obvious fix is to cast the return from getExample to List<Example>. I'm wondering: is there is an alternative way to avoid the cast?
Further Information:
Posters asked for more information, so here goes...
I have built a framework around annotation processing that writes code to access and mutate class members (constructors, fields and methods). This framework backs both Parceler and Transfuse and allows me to, during compilation, identify a property and generate code to access or modify said property. For private properties (private constructors, private fields, private methods) I use a utility to perform these actions (Parceler's, Transfuse's) to break encapsulation via reflection.
Parceler has a feature to unroll collections during serialization in order to serialize members of the given collection. For private collections the InjectionUtil is used to access these properties within a loop:
for (Example example : InjectionUtil.getField(List.class, Container.class, container, "exampleField")) {
// ...
}
Which is the bug I'm currently faced with, and thus, why I'm asking about avoiding a cast. I'd prefer to not cast as I'd like to generically generate a bit of code to access a type and respect Java generics in the process.
If your getExample method is supposed to always return a list, then yes, change its return type to List<T>. But since you're passing List.class as an argument, it looks like you want to have a method that can return both lists and non-lists depending on which class object you pass it.
If so, that's not going to work the way you might be hoping. Your method in this case returns just List, the raw type. To make it return List<Example>, you'd have to pass it something like a hypothetical List<Example>.class, but there's no such thing. Generic type parameters are erased at compile time, so List<Example> and List<String> are really both the same class; they don't have separate class objects, so a class object argument can't tell your method what kind of list it should return.
You'll probably need to try a different design approach. Since this is clearly a simplified example, you might be able to get more help if you post more details about what you're actually trying to accomplish.
Guava's TypeToken can be used in this case because List<Foo>.class is not valid. TypeToken is used by creating an anonymous class. Because anonymous classes keep their generic signatures, this works.
for (Example foo : Util.getExample(new TypeToken<List<Example>>() {}) {
// do stuff
}
// utils
public <T> T getExample(TypeToken<T> typeToken) {
Type type = typeToken.getType();
// get example
}
TypeToken is more specific than just using the Class. You could also use the plain Type as a parameter so you can still feed it a Class. This is how Gson does it.
I think this is a design issue...
Since the method in Util you are calling is called getExamples it seems reasonable that it might just as well be fixed to return some collectionwhose elements are instance of the Example class.
It is reasonable to change getExamples to something like this?:
class Util {
public static <C extends Collection<? supper Example>> getExamples(final Supplier<C> factory) {
final C result = factory.get();
// here goes the code that adds the examples to the result collection
// using add or addAll.
return result;
}
}
So for-example if you wan to get a List<Example> using ArrayList<E> for implementation you would do like so:
List<Example> examples = Util.getExamples(ArrayList<Example>::new);
Try to pass the returned collection class object reference instead (eg. List.class, ArrayList.class) won't work as the code in getExamples will have a hard time (a) figuring out how to call the appropriate constructor using reflexion to instantiate the result (kinda of impossible if you pass just an interface class object such as List.class) and (b) casting the return from a raw type into a generic type with Example as element type. The latter is trivial however it is not as neat as it can be as it will generate a warning.
It is just more straight forward to delegate in the using code to indicate explicitly how to instantiate the result collection.
If you break away from returning a Collection and use methods like add and addAll in getExamples then perhaps you should borrow the Collectors framework from the java stream API.

Single method to return an instance of different generic type of a class

I have a generic class as follows:
MyClass<T>
{
....
}
Now, what I want create a single generic method,say for example public MyClass<T> getMyClassInstance(Type t){...}, in which I pass a type and this method gives an instance of MyClass with that type.
See the following examples.
If I call this method as follows, getMyClassInstance(Integer_type), then it returns the MyClass<Integer> instance.
Similarly, if I call this method as follows, getMyClassInstance(String_type), then it returns the MyClass<String> instance.
How shall I write this method? If it can't be done, is there any alternative way or another better way to do something like this?
For simple applications of this, you don't even need to pass in a Type or Class argument. Consider the following:
public <T> List<T> getList() {
return new ArrayList<>();
}
To use this is as simple as:
List<Integer> lst = getList();
The compiler will infer the type of the list desired.
Do note that you will get more flexibility from passing in a Type parameter, especially in cases where you may not know in advance what sort of List you want to get back. But this sort of syntax, IMHO, reads more naturally and may be suited to what you want to do. (I say "may" since you haven't provided a ton of details ...)
The Type class must carry the type parameter on it: Type<T>, so you can declare
<T> MyClass<T> getMyClassInstance(Type<T> t);
If you can't make that happen, then the compiler is blind.

Java Generics, Type Inference, Inheritance?

I'm reading about type inference for generics, and this code was provided as an example that fails to compile.
import java.io.*;
class LastError<T> {
private T lastError;
void setError(T t){
lastError = t;
System.out.println("LastError: setError");
}
}
class StrLastError<S extends CharSequence> extends LastError<String>{
public StrLastError(S s) {
}
void setError(S s){
System.out.println("StrLastError: setError");
}
}
class Test {
public static void main(String []args) {
StrLastError<String> err = new StrLastError<String>("Error");
err.setError("Last error");
}
}
And the explanation given in the book was:
"(It looks like the setError() method in StrLastError is overriding setError() in the LastError class. However, it is not the case. At the time of compilation, the knowledge of type S is not available. Therefore, the compiler records the signatures of these two methods as setError(String) in superclass and setError(S_extends_CharSequence) in subclass—treating them as overloaded methods (not overridden). In this case, when the call to setError() is found, the compiler finds both the overloaded methods matching, resulting in the ambiguous method call error."
I really don't understand why type S can't be inferred at compile time.
String is passed when invoking the constructor of class StrLastError,
and from the API docs, String does implement interface CharSequence,
so doesn't that mean that S for <S extends CharSequence> actually is of type String?
I've read the Java online tutorial on the topic of generics several times. I've checked "Type Inference", and Inheritance, I just don't know how the whole thing works. I really need an explanation on this question.
The points I'm stuck at are:
If the subtype can't decide S, how come the super type can decide T, because the superclass does not have an upper bound? Or does it infer that T is String because the subtype calls the supertype's constructor first?
I understand that if the Constructor is invoked as:
StrLastError<CharSequence> err = newStrLastError<>((CharSequence)"Error");
there will be no ambiguity, since it's plain method overriding then. (Or am I even wrong here?)
However, like I said in the beginning, if String is passed, why can't S be inferred to be String?
You have to remind yourself that the classes are compiled one by one. Java generics are not templates as in other languages. There will only be one compiled class and not one class per type it is used with.
This way you can see that the class StrLastError will need to be compiled in a way such that it can also be used with other classes implementing CharSequence as generic type S.
Thats why the compiler gets you two different methods instead of an overridden one. Now it would be a runtime-job to see that the subclass may have wanted to override the method in the parent just in those cases where the types suggest it. Since this behaviour is hard to understand for the developer and would possibly lead to programming mistakes, it raises an exception.
If you use CharSequence as the generic type parameter of the class StrLastError, you will call the setError method in the parent class, since the type of "Last Error" is String, which is more specific than CharSequence and Java always chooses the most specific method in case it is overloaded. (I hope it is clear the the method was not overridden in this case either)
If the subtype can't decide S, how come the super type can decide T, because the superclass does not have an upper bound? Or does it infer that T is String because the subtype calls the supertype's constructor first?
The super type isn't deciding or inferring what T is; you're explicitly telling it what T is by this declaration:
class StrLastError<S extends CharSequence> extends LastError<String>
T is now bound to String for LastError, which makes every reference to T in the parent class a concrete String.
Your child class now has a bound S extends CharSequence attached to it, but this is independent to the bounds applied to the parent class.
What happens now is that Java will compile your child class, and the result of your child class is that two methods with a signature that matches String will be created. (Key note here: A String is-a CharSequence.)
In your child class, setError(Ljava/lang/CharSequence;)V is generated as the signature for setError. Because of the way generics work, LastError#setError will be treated as if it has a signature of setError(Ljava/lang/String;)V. This is also why when you go to actually override the method, it will place a String type as your parameter instead of anything else.
So, what we arrive at are two methods that have override-equivalent signatures.
void setError(CharSequence s)
void setError(String s)
JLS 8.4.8.4. applies here.
It is possible for a class to inherit multiple methods with
override-equivalent signatures (§8.4.2).
It is a compile-time error if a class C inherits a concrete method
whose signature is a subsignature of another concrete method inherited
by C. This can happen if a superclass is generic, and it has two
methods that were distinct in the generic declaration, but have the
same signature in the particular invocation used.
I understand that if the Constructor is invoked as StrLastError err = new StrLastError<>((CharSequence)"Error"); there will be no ambiguity, since its plain method overriding then.(Or I'm even wrong here)
No, now you're messing with raw types. Interestingly enough it will work, primarily because the signatures for the two methods has become:
void setError(Object s)
void setError(String s)
You want to use generics to avoid a scenario like this; you may want to invoke the super class method at some point, but in this scenario with these bindings, it's very difficult to accomplish.
This is a tricky example, to fix it you need to change the following line:
class StrLastError<S extends CharSequence> extends LastError<S>

If the signature of a constructor includes the definition of a generic type, what extra responsibilities does that put on users of that constructor?

I extending an existing project that use generics in a few classes.
I am working on a class called PhiFunction, this class has one construcor which accepts a number of arguments. These include two arguments which I want to force to be the same type, E. These arguments are only used in the constructor, they are not stored as class fields.
I dont want to add this type to the class signature (I want to keep the class definition as simple as possible). The class signature just includes the type T at the moment. To keep the class signature as simple as possible, I added the definition of this type to the constructor signature, as shown below:
Simplified old code:
public class PhiFunction<T> {
...
public PhiFunction(
final MathematicalGroup<?> group, final List<?> baseElements, ...) {
Simplified new code:
public class PhiFunction<T> {
...
public <E extends GroupElement<T>> PhiFunction(
final MathematicalGroup<E> group, final List<E> baseElements, ...) {
The code compiles fine, and works fine.
The thing which surprises and confuses me now is that, it is still possible to create instances of PhiFunction as before. In other words, the addition of this type definition in the constructor signature does not change how the constructor is used (assuming that users do indeed supply arguments which use the same type). Users can still create instances of PhiFunction, just as they did before, without caring that this type definition was added to the constructor. I expected that users of this constructor would have to define E as being some particular class, but they dont.
I had not used generics in this way before. It seems that adding a type definition to the constructor (or to any method I guess) simply allows a type to be defined, without putting responsibilities on the user of the constructor to define that type.
I guess my question is, if the signature of a constructor includes the specification of a generic type, what extra responsibilities does that put on the user of the constructor?
I have one other related question. Should this type E be added to the Java docs as a parameter? and how? I am sure that it should be documented, as two of the arguments of the constructor must be of that type, but I am not sure how this should be added to the Javadocs.
You don't need to do any extra work for invoking a generic method or constructor. Most of the time, the compiler will be able to infer the type argument, based on the argument you pass to the method, or from the return type (not applicable here though).
So, when you create an instance of that class like this:
MathematicalGroup<Sometype> mathematicalGroup;
List<Sometype> list;
PhiFunction<Double> phiFunction = new PhiFunction<>(mathematicalGroup, list);
...the type parameter E of the constructor will automatically be inferred as Sometype.
However, if you pass arguments that doesn't comply to the rules of type parmeters, you'll see a compiler error, as in this case:
MathematicalGroup<Sometype> mathematicalGroup;
List<SomeOthertype> list;
// This will give a compiler error.
PhiFunction<Double> phiFunction = new PhiFunction<>(mathematicalGroup, list);
You also have the option to give explicit type arguments, if sometimes type inference doesn't work as expected:
// Redundant usage of explicit type argument
PhiFunction<Double> phiFunction =
new <Sometype>PhiFunction<Double>(mathematicalGroup, list);
Although the above usage of explicit type argument is redundant, but there are cases where compiler will not infer the type that you expect it to. Those are the cases when you pass inconsistent arguments to the parameters that are of same type parameter. Consider the below method for example:
public static <T> void fill( T [] array, T elem) {
for (int i=0; i<array.length; ++i) { array[i] = elem; }
}
.. if you try to invoke that method as:
fill(new String [5], new String ("XYZ")); // This is fine
fill(new String [5], new Integer (100)); // This is also fine? How?
Ideally you would expect the second method invocation to fail, because String and Integer should not be substitutable for same type parameter T. But here's the surprise. The compiler infers the type parameter as the intersection of all the super types of the arguments you passed. So, the type T is inferred as:
T:=Object&Serializable&Comparable
In that case, you might want to give <Object> as explicit type argument:
YourClass.<Object>fill(new String[5], new Integer(100));
P.S: Did you know that you can invoke non-generic methods in generic way? Well, generics is full of surprises :)
As for Javadoc, no you don't need to give any information about what E represent. Just explain what the paramters group and list means. That's it. The type parameter and formal parameters are anyways the part of the method signature, and will already be there. Consider for example Arrays.binarySearch() method.
To add it to Javadoc:
#param <E> This represents...
This constructor
public PhiFunction(
final MathematicalGroup<?> group, final List<?> baseElements, ...) {
Allows any type to be passed to/used with MathematicalGroup. Does MathematicalGroup have its own generics associated to it already?
If so, then perhaps your new constructor is redundant. That is, even though the original constructor has <?>, the generics restrictions of the MathematicalGroup class itself already does this enforcement.
public <E extends GroupElement<T>> PhiFunction(
final MathematicalGroup<E> group, final List<E> baseElements, ...) {
Otherwise, this is indeed more restrictive, as the original signature allows any type, and this one allows only GroupElement<T>, or one of its sub-classes.
As far as how your users use it:
MathematicalGroup mg = new <GroupElement<Object>>MathematicalGroup<Object>(groupElementInstance, ...);
This is an odd use-case. Usually this generics passing is done with static final utility functions.

Call a Generic method by reflection in java

How to call a Custom Generic method by reflection in java?
class Person
{
public <T> void print(T t)
{
System.out.println(t.toString());
}
}
Generics are erased at compile time, they only provide extra information to the compiler to determine errors. They do not actually change the signature of the method in the .class file.
This means that you call a generic method by reflection in Java exactly the same way as you would call a non-generic method in Java, except that instead of specifying a type of T, you would specify a type of Object.
There are so many tutorials on how to call a regular method by reflection that I hesitate to add yet another; however, if you really need direction on how to call a method by reflection, please add a comment below and I'll add the necessary code.
If you find that things are not working as expected, you can always run javap on the compiled class file to verify that you are using the right objects in the argument list. It might be possible that if you specify a <T extends List> type generic signature, the resulting parameter object might actually be a List object.
This works for me.
Method method = Person.class.getMethod("print", Object.class);
method.invoke(new Person(), "this is a string");
method.invoke(new Person(), 273);
method.invoke(new Person(), new Object());
printing
this is a string
273
java.lang.Object#addbf1
Of course the theory behind this is explained beautifully in #Edwin's answer.
To highlight the point given in Edwin's answer, where we are using extends in a generic type: if you have a class like
GenericHibernateDao<T extends Serializable>
, and a method
public T save( T entity ) {};
to invoke the method save using reflection you have to use the Serializable class, i.e., you need to use:
Method method = GenericHibernateDao.class.getMethod(methodName, Serializable.class);
and not the Object.class as the parameter, since we are using
<T extends Serializable>

Categories