Java - java.lang.NoSuchMethodException
Solution 1
It seems that you forgot to pass type of arguments that your method needs (remember that methods can be overloaded with different arguments types). Take a look at your code, there is no setHeight()
method there but setHeight(int)
. You should try something like
Method m_set = product.getClass().getMethod(method_name,method_value.getClass());
m_set.invoke(product, method_value);
Since you could have problems with primitive types you can use way around. Assuming that there is only one method with same name in your class you want to find you can iterate over all public methods, compare its name with method you are looking for, and then invoke it with arguments you want. Something like
Method[] methods = product.getClass().getMethods();
for (Method m : methods){
System.out.println(m);
if (m.getName().equals("setHeight")){
m.invoke(product, method_value);
break;
}
}
Another and probably better way would be using classes from java.bean
package like PropertyDescriptor
. Thanks to this class you can find getters and setters for specific property. Notice that property for setHeight
is height
so you would need to use it like
Method setter = new PropertyDescriptor("height", product.getClass()).getWriteMethod();
setter.invoke(product, method_value);
Solution 2
Use product.getClass().getMethod("setHeight", int.class);
. You have to pass the method parameters types to target the method signature.
Andrius
Updated on November 12, 2020Comments
-
Andrius over 3 years
I try to use this code (Update m_set is used inside for loop which goes through few methods which use different type arguments. If I would add for example int.class in
getMethod
, I would get error after one iteration, because next method would require String.class. Is it possible to solve such problem using reflection?):Method m_set = product.getClass().getMethod(method_name); m_set.invoke(product, method_value);
I get this error:
Exception in thread "main" java.lang.NoSuchMethodException: test.NormalChair.setHeight() at java.lang.Class.getMethod(Class.java:1655) at test.ProductTrader.create(ProductTrader.java:68) at test.Test.main(Test.java:32)
In error it shows that it tries to find method in class that I use this method. But that method is in parent class and it is public method. I know if I would use
getDeclaredMethod
, it would give similar error, but why it gives this error usinggetMethod
?My class thas has this method:
public abstract class AbstractChair { public String name; public int height; public AbstractChair() { } public AbstractChair(String name, int height){ this.name = name; this.height = height; } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getHeight() { return height; } public void setHeight(int height) { this.height = height; } }
My class that I try to use this method on:
public class NormalChair extends AbstractChair { public NormalChair() { super(); } public NormalChair(String name, int height) { super(name, height); } // Copy constructor public NormalChair(NormalChair chair) { this(chair.getName(), chair.getHeight()); } }
Update2
If I do something like this:
if(method_name == "setHeight"){ Method m_set = product.getClass().getMethod(method_name, int.class); m_set.invoke(product, method_value); } else if (method_name == "setName") { Method m_set = product.getClass().getMethod(method_name, String.class); m_set.invoke(product, method_value); }
Then error disappears. Can someone suggest more universal approach?
-
Andrius over 10 yearscan I somehow get type from value using reflection? as that type may change depending what kind of method it will try to get.
-
Montre over 10 years@Andrius Sure, use
method_value.getClass()
. I'm not sure that will work if the type ofmethod_value
is a subclass of the actual type in the declaration. (Update: no it won't: ideone.com/5sWYV4) -
Andrius over 10 yearsUsing -
method_value.getClass().getTypeParameters()
insidegetMethod
, gives error:The method getMethod(String, Class<?>...) in the type Class<capture#4-of ? extends Object> is not applicable for the arguments (String, TypeVariable<Class<capture#5-of ? extends Object>>[])
-
Montre over 10 years@Andrius
Class.getTypeParameters()
is for working with generics. I don't think it's what you're looking for here. -
Andrius over 10 yearsit does not let me enter valuesTypes... Can I enter somehow list of types and let java choose the one fits somehow? As it is now, I get:
argument type mismatch
error, because I use for loop which uses few methods to set values on object (and methods have different types) -
Pshemo over 10 yearsNo you can't, this would lead to potentially problems if there ware few methods that would match some subset of your types. You need to be specific what argument types has method you are interested in. But it seems that your class don't overload methods so there is only one with same name in your class. If that is true then you can just take all methods with
getMethods()
and iterate over them and get one witch hasgetName().equals(method_name)
and thenmethod.invoke(product,method_value)
-
Pshemo over 10 years@Andrius Take a look at my updated answer. You probably will find few interesting things there.
-
Andrius over 10 yearsWouldn't it give me error after one
for
iteration, when java starts looking for methodsetName
? -
Pshemo over 10 years@Andrius What do you mean? Assuming that there is only one method
setName
in your classfor
loop will find it, execute it with your data you will pass ininvoke
and stop looping for other methods (since there wont be any that will be namedsetName
according to previous assumption). -
Andrius over 10 yearsThanks for a good suggestion. I found out what was wrong. In my other class, which take care of xml parsing. There was a bug where string wasn't converted to Integer. That's why I was getting this error. Fixing that and using your suggestion with
PropertyDescriptor
(just used sliced method_name instead of static"height"
, so it goes for any method java gets) solved this problem.