I've been trying to use Reflection in Java, but it doesn't end up pretty well. Here's my code:
public class ReflectionTest {
public static void main(String[] args) {
ReflectionTest test = new ReflectionTest();
try {
Method m = test.getClass().getDeclaredMethod("Test");
m.invoke(test.getClass(), "Cool story bro");
} catch (NoSuchMethodException | SecurityException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IllegalAccessException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IllegalArgumentException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (InvocationTargetException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public void Test(String someawesometext) {
System.out.println(someawesometext);
}
}
I just get the java.lang.NoSuchMethodException error, and I've tried pretty much everything.
Like using getMethod instead of getDeclaredMethod, add test.getClass() after "Test" in getDeclaredMethod and more.
Here's the stack trace:
java.lang.NoSuchMethodException: ReflectionTest.Test()
at java.lang.Class.getDeclaredMethod(Unknown Source)
at ReflectionTest.main(ReflectionTest.java:10)
I have been Googling for many days now but with no luck. So I does anyone know how I'm supposed to fix this?
You specify a name in getDeclaredMethod but no parameter, although the Test method does have a parameter in its signature.
Try this:
Method m = test.getClass().getDeclaredMethod("Test", String.class);
along with this:
m.invoke(test, "Cool story bro");
Because the first argument of Method.invoke expects an object. However this argument is ignored in case of static methods:
If the underlying method is static, then the specified obj argument is
ignored. It may be null.
There are two problems:
Problem 1 is you must soecify HHS parameter signature of the target method:
Method m = test.getClass().getDeclaredMethod("Test", String.class);
Problem 2 is you must pass the instance to the invoke() method:
m.invoke(test, "Cool story bro");
FYI you would pass the class of the instance as the target to the invoke method if the method were static.
If you check the JavaDoc for Class.getDeclaredMethod() you can see that it expects a parameter type array.
final Class<?> ContextImpl =Class.forName("android.app.ContextImpl");
Method method= ContextImpl.getDeclaredMethod("getImpl",Context.class);
method.setAccessible(true);
Context myContext= (Context) method.invoke(ContextImpl,getApplicationContext());
System.out.println("........... Private Method Accessed. : "+myContext);
Related
I know there is, like, over 5 questions that ask this but mine is different. I am trying to get all classes in a package and run the tick function. Here is what one of my classes look like:
package com.stupidrepo.mydirectory.yayay;
public class test {
public void tick(MinecraftClient client) {
System.out.println(client.player.getName());
}
}
Here is how I am attempting to call this function:
ScanResult scanResult = new ClassGraph().acceptPackages("com.stupidrepo.mydirectory.yayay").enableClassInfo().scan();
private void doIt(MinecraftClient client) {
scanResult.getAllClasses().forEach((classInfo -> {
// System.out.println(classInfo.getName());
try {
classInfo.loadClass().getMethod("tick", MinecraftClient.class).invoke(null, client);
} catch (Exception e) {
e.printStackTrace();
}
}));
}
When I call the doIt function, it keeps giving me the java.lang.NoSuchMethodException error. When I print classInfo.getMethods();, it shows me [public void com.stupidrepo.mydirectory.yayay.test.tick(net.minecraft.client.MinecraftClient)].
So the method is there but java says it isn't. Please help! (By the way the code is for a Fabric MC mod)
The method tick is not static. But, when you are invoking method, you are not giving instance (but null), so it try to run the method as static. Such as It's not static, it failed.
To fix it, you can:
Set your method as static, for example:
package com.stupidrepo.mydirectory.yayay;
public class test {
public static void tick(MinecraftClient client) {
System.out.println(client.player.getName());
}
}
Create a new instance like that:
try {
Class<?> clzz = classInfo.loadClass(); // get class
Object obj = clzz.getConstructor().newInstance(); // create instance
clzz.getMethod("tick", MinecraftClient.class).invoke(obj, client); // get and call method
} catch (Exception e) {
e.printStackTrace();
}
To sum up my project I'm trying to make an event processor that runs methods from a given list of methods. In order to invoke these methods I need to pass in the newInstance of the method. The method is correctly run, however, right after the whole program crashes with a "ConcurrentModificationException".
#EventHandler
private Listener<EventKeyInput> eventKeyInput = new Listener<>(event ->
{
for(Method m : event.getMethods())
{
try {
m.invoke(m.getDeclaringClass().newInstance(), event);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
});
One of the methods I wish to call
#EventAnnotation()
public void eventKeyInputeTest(EventKeyInput event)
{
System.out.println("EventKeyInput test!");
}
Please let me know if I need to provide anymore code. Thank you for any help!
Edit: Added the class where I change the method
Is there any other way to go about this?
for(Method m : listenable.getClass().getMethods())
{
if(m.isAnnotationPresent(EventAnnotation.class))
{
Parameter[] params = m.getParameters();
if(params.length != 1)
{
System.out.println("You need 1 event paramter!");
}
Class<?> eventType= params[0].getType();
try {
Object methods = eventType.getMethod("getMethods").invoke(eventType.newInstance(), null);
Method add = List.class.getDeclaredMethod("add", Object.class);
add.invoke(methods, m);
eventType.getMethod("setMethods", ArrayList.class).invoke(eventType.newInstance(), methods);
}
catch (Exception e)
{
e.printStackTrace();
}
}
}
I have generic class type, T as follow:
class MyClass<T>
Also I know that T is interface with only one method inside but I don't know what interface, I can't write this:
class MyClass< T extends TheInterface >
So is there a way to invoke this method?
public void callMe(T me, Object...params){
// How can I invoke T interface method?
}
I been trying this:
public void callMe(T me, Object... params) {
// methods.length is 244, just as in my activity class
Method[] methods = me.getClass().getMethods();
try {
methods[0].invoke(me, params);
} catch (IllegalArgumentException e) {
e.printStackTrace();
return;
} catch (IllegalAccessException e) {
e.printStackTrace();
return;
} catch (InvocationTargetException e) {
e.printStackTrace();
return;
}
}
But it's not working
Edit: I posted new question that explain why I need this for
Yes, you have to write:
class MyClass< T extends TheInterface >
With this information, the compiler know that T have an operation named callMe
I'm not sure, are you looking for the Strategy pattern?
If you can not change declaration inside MyClass then you can just typecast it.
public void callMe(T me, Object... params) {
Someinterface instance = (Someinterface) me;
list.callMe(me, params);
}
But still declaring it like below should be the best solution
class MyClass<T extends Someinterface >
Below is the simple demonstration of how to do it using reflection
class MyClass<T> {
public void callMe(T me, Object... params) throws SecurityException,
NoSuchMethodException {
// How can I invoke T interface method?
Method size = me.getClass().getMethod("size", null);
Method add = me.getClass().getMethod("add", Object.class);
try {
add.invoke(me, 10);
System.out.println(size.invoke(me, params));
} catch (IllegalArgumentException e) {
e.printStackTrace();
return;
} catch (IllegalAccessException e) {
e.printStackTrace();
return;
} catch (InvocationTargetException e) {
e.printStackTrace();
return;
}
}
}
MyClass<List> myclass = new MyClass<List>();
myclass.callMe(new ArrayList(), null);
Output :
1
I need to code a method, something like :
MyClassObject convert(Class MyClass , String value)
The convert method's job is to convert the String into an object of MyClass, where MyClass can be anything (except a primitive) - Integer, Boolean, Character, Date... the possibilities are huge here - and that's the reason I gave up my stupid if-else block to handle all the cases individually.
I could see something related to this for C# (don't know if it works) , don't know if we have a Java equivalent for this or this
I understand not everything can be converted from a string, I am ready to handle exceptions for non-parseable items.
I don't know if this is possible or not. If not, please help me with a proper design pattern for my code.
Thanks !
Your best bet is probably the ServiceLoader mechanism. This allows you to define a pair of interfaces, e.g.:
interface StringConverterProvider{
StringConverter<T> getConverterFor(Class<T> clazz);
}
interface StringConverter<T>{
T convert(String s);
}
... and then locate all the implementations of these interfaces available at runtime, like so:
ServiceLoader<StringConverterProvider> converterProviderLoader
= ServiceLoader.load(StringConverterProvider.class);
T convert(String s, Class<T> t){
for(StringConverterProvider scProv : converterProviderLoader){
StringConverter<T> converter = scProv.getConverterFor(t);
if (converter != null)
return converter.convert(s);
}
return null;
}
You make your implementation of the interfaces available to ServiceLoader by listing them in a special file in the META-INF directory in your jar file; see the javadoc for details.
Using reflection and hoping that all the wrapper objects for primitives contains a constructor with a string argument for value, you may be able to achieve this like the following
// A sample test with main
public static void main(String[] args) {
Object obj = create(Integer.class, "54896");
Integer val = (Integer) obj;
System.out.println(val);
}
// Method to create the desired object with the given value
private static Object create(Class myClass, String value) {
Object obj = null;
try {
Constructor constructor = myClass.getConstructor(new Class[]{String.class});
obj=constructor.newInstance(value);
} catch (SecurityException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (NoSuchMethodException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IllegalArgumentException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (InstantiationException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IllegalAccessException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (InvocationTargetException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return obj;
}
How would one go about checking to see if a method exists for a class in Java? Would a try {...} catch {...} statement be good practice?
I assume that you want to check the method doSomething(String, Object).
You might try this:
boolean methodExists = false;
try {
obj.doSomething("", null);
methodExists = true;
} catch (NoSuchMethodError e) {
// ignore
}
This will not work, since the method will be resolved at compile-time.
You really need to use reflection for it. And if you have access to the source code of the method you want to call, it's even better to create an interface with the method you want to call.
[Update] The additional information is: There is an interface that may exist in two versions, an old one (without the wanted method) and a new one (with the wanted method). Based on that, I suggest the following:
package so7058621;
import java.lang.reflect.Method;
public class NetherHelper {
private static final Method getAllowedNether;
static {
Method m = null;
try {
m = World.class.getMethod("getAllowedNether");
} catch (Exception e) {
// doesn't matter
}
getAllowedNether = m;
}
/* Call this method instead from your code. */
public static boolean getAllowedNether(World world) {
if (getAllowedNether != null) {
try {
return ((Boolean) getAllowedNether.invoke(world)).booleanValue();
} catch (Exception e) {
// doesn't matter
}
}
return false;
}
interface World {
//boolean getAllowedNether();
}
public static void main(String[] args) {
System.out.println(getAllowedNether(new World() {
public boolean getAllowedNether() {
return true;
}
}));
}
}
This code tests whether the method getAllowedNether exists in the interface, so it doesn't matter whether the actual objects have the method or not.
If the method getAllowedNether must be called very often and you run into performance problems because of that, I will have to think of a more advanced answer. This one should be fine for now.
Reflection API throws NoSuchMethodException when using Class.getMethod(...) functions.
Otherwise Oracle has a nice tutorial about reflection http://download.oracle.com/javase/tutorial/reflect/index.html
In java this is called reflection. The API allows you to discover methods and call them at runtime. Here is a pointer to the docs. It's pretty verbose syntax but it'll get the job done:
http://java.sun.com/developer/technicalArticles/ALT/Reflection/
I would use a separate method to handle the exception and have a null check to check if method exists
Ex : if (null != getDeclaredMethod(obj, "getId", null)) do your stuff...
private Method getDeclaredMethod(Object obj, String name, Class<?>... parameterTypes) {
// TODO Auto-generated method stub
try {
return obj.getClass().getDeclaredMethod(name, parameterTypes);
} catch (NoSuchMethodException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (SecurityException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return null;
}
If you're using Spring in your project you may check ReflectionUtil.findMethod(..). It returns null if method does not exist or does not match your requirements. Documentation.
Roland Illig is correct, but wanted to add in an example of how to check if a method exists that requires a parameter using Class.getMethod. Can also use Class.getDeclaredMethod if you are trying to access a private method.
class World {
public void star(String str) {}
private void mars(String str) {}
}
try {
World.class.getMethod("star", String.class);
World.class.getDeclaredMethod("mars", String.class);
} catch (Exception e) {}
Other solution:
public static <O> boolean existsMethod(final String methodName, final O o) {
return Stream.of(o.getClass().getMethods()).map(Method::getName).anyMatch(methodName::equals);
}