Trouble invoking a non-static method through reflection (Java) - java

I'm having problems invoking non-static methods through reflection. My code is below. When I try to do "ClassnameRemoved.printMessageToLogger(Level.INFO, "Test");", I get "Could not find method 'log' in class Logger. This is a normal Java class, so you are probably using a modified/outdata Java version.". Thanks in advance!
private static void printMessageToLogger(Level lvl, String message) {
try{
Class<?> clazz = Class.forName("net.packgeName.omitted.Main");
Field logger = clazz.getDeclaredField("tcLog");
Method logMethod = logger.getDeclaringClass().getDeclaredMethod("log", Level.class, String.class);
logMethod.invoke(logger, lvl, message);
}
// catch methods omitted to save space
}

If the method is not static, you need an instance of the class.
Look at this example:
Class classDefinition = Class.forName(className);
object = classDefinition.newInstance();

Related

new className().methodName(); VS className ref = new className();

I came across a code which my colleague uses inside an eventListner, which is :
private void someActionPerformed(java.awt.event.ActionEvent evt) {
new className().methodName(); //public class and public void methodName()
}
I was pretty sure that :
private void someActionPerformed(java.awt.event.ActionEvent evt) {
className ref = new className(); //public class and public void
ref.methodName();
}
is the better option than his, as the previous method instantiates a class every time it is called.
Am I wrong? Any suggestion is appreciated, Please correct me if I am wrong
.
Both do the same thing, however one of them (the first) is 1 line shorter.
Your approach is usually recommended when you need to go through more than 2-3 objects, so new Foo().getBar1().getBar2().doStuff() is usually not recommended since it can degrade into spaghetti code and hinder the understandability of the code.
The first code-sample instantiates a new Object of Type className.methodName.
For this to work, methodName has to be a static nested class of Type className.
Attention: This could as well be a typo. Did you mean new className().methodName()?
The second sample creates a new instance of className and calls its method methodName.
Some example code:
public class Test {
public static void main(String[] args) {
new Test.test(); // instantiates the inner class
Test t = new Test(); // instantiates Test
t.test(); // calls method #test of Test-instance
}
public String test() {
return "Test";
}
public static class test {
}
}
In order to judge what's the best solution your example does not give enought information. Is the method some static utility code or is an instance of className useful? It depends...
Whenever an object is instantiated but is not assigned a reference variable, it is called anonymous object instantiation.
With anonymous object you can call it's instance method also:
new className().methodName();
In your case this is the anonymous object which doesn't have reference variable.
In the statements:
className ref = new className();
ref.methodName();
ref is the reference variable to hold the className object, so you can call instance methods of className on ref variable.
The benefit of using anonymous notation is, if you want to do only limited (may be calling single method and so on..) operation with the underlying object the it is a good approach. But if you needs to perform more operation with the underlying object then you need to keep that object in a reference variable so that you can use that reference to perform multiple operations with that object.
Regarding the performance there are not much difference as both are in methods scope, as soon as method completes both the objects are valid candidates for the garbage collection.
Both the methods instantiates a class in the code. If you want to reuse the class object every time the method is called, you can declare it as a member of the class where the method resides. For eg:
class AnotherClass{
private ClassName ref;
AnotherClass(){
ref = new ClassName()
}
private void someActionPerformed(java.awt.event.ActionEvent evt) {
ref.methodName();
}
}
This way, everytime your method someActionPerformed is called on an object of AnotherClass, it will reuse the ref object instead of instantiating it everytime.
About the edit,
public class ClassName {
static class InnerClass{
// A static inner class
}
public void methodName() {
// A method
}
}
class AnotherClass{
private void someActionPerformed(java.awt.event.ActionEvent evt){
// This creates an instance of the inner class `InnerClass`
new ClassName.InnerClass();
// However I believe, you wanted to do:
new ClassName().methodName();
}
}
new className.methodName(); --> if you are using this convention in your code then calling another method name will result to different object's method name and you lose your values.
className ref = new className();
ref.methodName(); -> here you are creating a reference and make assiging a newly created object and you are calling the method's on it. Suppose if you want to call another method on the same object it will helps.
The first approach they will mostly use for listenere which is anonymous class.
Both options create a new Class every time they are called. The advantage of the second over the first option would be if you wanted to reuse that class later in the method.
IMHO this is a little bit more understandable code for the answer provided by DaniEll
public class Test {
public static void main(String[] args) {
new Test.test(); // instantiates the inner class
Test t = new Test(); // instantiates Test
t.test(); // calls method #test of Test-instance
}
public void test() {
System.out.println("Outer class");
}
public static class test {
public test() {
System.out.println("Inner class");
}
}
}

Java Class.forName won't compile. Getting "cannot find symbol symbol : method"

I'm trying to use Class.forName and my Intellij is throwing a compile error. My IntelliJ highlights "theResponse" in red (in testMethod) and gives me this error:
cannot find symbol symbol : method
Here is the code (and test) I'm working with...
package http.response;
public class TestClass {
public TestClass() {
PublicRoute publicRoute = new PublicRoute();
}
public String testMethod() throws ClassNotFoundException {
Class c = Class.forName("http.response.PublicRoute");
return c.theResponse("hi");
}
}
package http.response;
import org.junit.Test;
import static junit.framework.Assert.assertEquals;
public class TestClassTest {
#Test
public void test() throws ClassNotFoundException {
TestClass testClass = new TestClass();
assertEquals("public", testClass.testMethod());
}
}
UPDATE: What I was trying to do was "polymorphically" call theResponse from the class that is returned as a String from a HashMap. How would I do this? I'm (loosely) following this example but I didn't understand it fully (http://sourcemaking.com/refactoring/replace-conditional-with-polymorphism). Here is a simplified version of what I'm trying to do. Hopefully that makes sense.
package http.response;
import java.util.HashMap;
public class TestClass {
HashMap map;
public TestClass(HashMap map) {
this.map = map;
}
public String testMethod(String lookupValue) throws ClassNotFoundException {
String className = map.get(lookupValue);
Class c = Class.forName("http.response." + className);
return c.theResponse();
}
}
Class.forName() returns an object of type java.lang.Class. java.lang.Class has no method theResponse, as you can see from its Javadoc.
It sounds like what you actually want to do is construct an instance of the PublicRoute class, and call the method on the instance. But you've already constructed such an instance: it's the publicRoute variable you create in your constructor. Why not just use that object instead?
Edit: Ah, I see what you're trying to do. You basically want a form of the Service Locator pattern.
Create an interface, like so:
public interface ResponseProvider {
String theResponse();
}
Then make all your classes implement that interface:
public class PublicRoute implements ResponseProvider {
#Override
public String theResponse() {
// do whatever
}
}
Then, when you load your Class<?>, you can use the asSubclass() method to turn your Class<?> into a Class<? extends ResponseProvider> -- then newInstance() will give you back a ResponseProvider object that you can call theResponse() on, like so:
String className = ...;
Class<?> klass = Class.forName(className);
Class<? extends ResponseProvider> responseProviderClass
= klass.asSubclass(ResponseProvider.class);
ResponseProvider responseProvider = responseProviderClass.newInstance();
return responseProvider.theResponse();
But don't do that by hand -- instead, use the java.util.ServiceLoader class, which is designed for exactly this purpose. You create a special META-INF/services/com.my.package.ResponseProvider file, with a list of all the possible classes that implement that interface, and then ServiceLoader can give you back instances of each of them.
But... consider not doing that, either. The types of problems that you can solve with the Service Locator pattern are often better solved by using Dependency Injection (see also my answer to another question about Dependency Injection). The Guice DI framework, for example, offers a feature called multibindings which looks like exactly what you need.
If theResponse() belongs to http.response.PublicRoute then it should have been
Class c = Class.forName("http.response.PublicRoute");
return ((PublicRoute) c.newInstance()).theResponse("hi");
But, then there's really no need for Class.forName() as you could use constructor as
return new PublicRoute().theResponse("hi");
The class Class does not have a method named theResponse. From the rest of your code, it doesn't look like you should be using reflection here; you're already referring statically to the PublicRoute class, so there's no point loading it dynamically.
I think you just want to write either this:
return PublicRoute.theResponse("hi");
or this:
return new PublicRoute().theResponse("hi");
(depending whether theResponse is a static method or an instance method).
Let me see if I understand what you're trying to do. You've got a hashmap that will contain a list of classes that you're going to try to call the theResponse(String response) method on, right? I'm assuming you won't know the String that will be put into the hashmap either, right?
Others are right in that you can't just do:
Class c = Class.forName("http.response.PublicRoute");
c.theResponse("hi"); // errors because c has no knowledge of theResponse()
You'll need to cast c to http.response.PublicRoute but then as #Ravi Thapliyal pointed out, you won't need Class.forName anymore! You've got a hashmap of names that could potentially be anything so this won't work.
If I'm understanding you correctly to do what you need, you'll need to use reflection in order to attempt to instance the class then call the method on it.
Here's how you'd do it assuming the theResponse method is a public non-static method and has only 1 parameter.
// Declare the parameter type
Class[] paramString = new Class[1];
paramString[0] = String.class;
String className = map.get(lookupValue);
// Instance the class
Class cls = Class.forName("http.response." + className);
Object obj = cls.newInstance();
// Call the method and pass it the String parameter
method = cls.getDeclaredMethod("theResponse", paramString);
method.invoke(obj, new String("hi"));
Of course you'll need to handle Exceptions but you'd surround the above code with the loop for your hashmap.
I hope this helps!

How do I call a method that has a method as its argument?

Here is a piece of code I have: (what I am trying to do with it is: define a method "renamingrule" in my main class, instantiate a instance of my other class "renamescript" and call its rename method passing as a parameter the "renamingrule" method i've defined in the main class. Everything is well in the RenamScript class, no errors, but i dont know how to call the rename method of the script class from my main class/method. thanks)
public class RenameScript2 {
...
public void rename(Method methodToCall) throws IOException, IllegalAccessException, InvocationTargetException {
try
{
...
String command = "cmd /c rename "+_path+"\\"+"\""+next_file+"\" "
+"\""+methodToCall.invoke(next_file, next_index)+"\"";
p = Runtime.getRuntime().exec(command);
}catch(IOException e1) {} catch(IllegalAccessException IA1) {} catch(InvocationTargetException IT1) {} ;
}//end of rename
} //end of class
//=======================================
public class RenameScriptMain2 {
public static String RenamingRule(String input, int file_row)
{
String output = "renamed file "+(file_row+1)+".mp3";
return output;
}
public static void main(String[] args) throws IOException
{
RenameScript2 renamer = new RenameScript2();
renamer.setPath("c:\\users\\roise\\documents\\netbeansprojects\\temp\\files");
try{
renamer.rename(RenamingRule);
}catch(IOException e2) {};
System.out.println("Done from main()\n\n");
}
} //end of class
You get hold of the Method object through Class.getMethod method. Something like this:
RenameScript2.class.getMethod("rename", parameters);
However, I suggest you consider writing an interface for a class that can perform the renaming, instead of passing a Method.
Such interface could look like
interface RenameAction {
void performRename();
}
To wrap the script in a RenameAction object you would do something like
RenameAction action = new RenameAction() {
void performRename() {
// ...
String command = "cmd /c rename "+_path+"\\"+"\""+next_file+"\" "...
p = Runtime.getRuntime().exec(command);
// ...
}
};
You would then simply do like this:
public void rename(RenameAction action) {
action.performRename();
}
Firstly, aioobe is definitely correct, passing a Method object is a little ugly. I'll assume that you're stuck with it!
To get a method, you'll need to use reflection. The below code grabs the method called toString on the class Integer. It then invokes the toString method.
Method method = Integer.class.getMethod("toString");
Object o = method.invoke(new Integer(7));
System.out.println(o);
Static methods don't need to pass the first parameter to method.invoke
Method method = File.class.getMethod("listRoots");
System.out.println(method.invoke(null));
This shows the reason why you shouldn't use it. That string "toString" and "listRoots" are not refactorable. If someone renames a method, then instead of a compile-time error, you'll get a runtime exception thrown (hence the exceptions you'll need to catch, NoSuchMethodException and IllegalAccessException). It's also much slower to use reflection than to use normal code.
Here is how you should do:
Make class RenameScript2 abstract by adding an abstract method public static String RenamingRule(String input, int file_row)
Then have your main class RenameScriptMain2 extend above class RenameScript2 and provide implementation of the method RenamingRule().
Now inside main method create instance of the class RenameScriptMain2 and call method RenamingRule()

Using Java reflection to create eval() method

I have a question about reflection
I am trying to have some kind of eval() method. So i can call for example:
eval("test('woohoo')");
Now I understand the there is no eval method in java but there is reflection. I made the following code:
String s = "test";
Class cl = Class.forName("Main");
Method method = cl.getMethod(s, String.class);
method.invoke(null, "woohoo");
This works perfectly (of course there is a try, catch block around this code). It runs the test method. However I want to call multiple methods who all have different parameters.
I don't know what parameters these are (so not only String.class). But how is this possible? how
can I get the parameter types of a method ?
I know of the following method:
Class[] parameterTypes = method.getParameterTypes();
But that will return the parameterTypes of the method I just selected! with the following statement:
Method method = cl.getMethod(s, String.class);
Any help would be appreciated !
You will need to call Class.getMethods() and iterate through them looking for the correct function.
For (Method method : clazz.getMethods()) {
if (method.getName().equals("...")) {
...
}
}
The reason for this is that there can be multiple methods with the same name and different parameter types (ie the method name is overloaded).
getMethods() returns all the public methods in the class, including those from superclasses. An alternative is Class.getDeclaredMethods(), which returns all methods in that class only.
You can loop over all methods of a class using:
cls.getMethods(); // gets all public methods (from the whole class hierarchy)
or
cls.getDeclaredMethods(); // get all methods declared by this class
.
for (Method method : cls.getMethods()) {
// make your checks and calls here
}
You can use getMethods() which returns an array of all methods of a class.
Inside the loop you can inspect the parameters of each method.
for(Method m : cl.getMethods()) {
Class<?>[] params = m.getParameterTypes();
...
}
Otherwise you can use getDelcaredMethods() which will allow you to "see" private methods (but not inherited methods). Note that if you want to invoke a private methods you must first apply setAccessible(boolean flag) on it:
for(Method m : cl.getDelcaredMethods()) {
m.setAccessible(true);
Class<?>[] params = m.getParameterTypes();
...
}
Ok thanxs to all the people who answered my question here the final solution:
import java.lang.reflect.Method;
public class Main {
public static void main(String[] args){
String func = "test";
Object arguments[] = {"this is ", "really cool"};
try{
Class cl = Class.forName("Main");
for (Method method : cl.getMethods()){
if(method.getName().equals(func)){
method.invoke(null, arguments);
}
}
} catch (Exception ioe){
System.out.println(ioe);
}
}
public static void test(String s, String b){
System.out.println(s+b);
}
}

How does one access a method from an external jar at runtime?

This is a continuation of the question posted in: How to load a jar file at runtime
I am uncertain as to how to continue to the method invocation level. From my understanding,
from the clazz object, I would used getMethod or getDeclaredMethod to get a Method object from which I would call invoke. Of course, invoke requires an instance. Would that then be what is called doRun in the example code?
Do I need to perform the doRun.run() method call even though I want to execute a different method than main (assuming that it is main on the doRun object that is called with the run invocation)?
Just for more clarification of the original post, I ask:
Does doRun.run() start a new thread executing the instance of the class object of type clazz?
Thanks for helping to clear this up for me.
I did look at "how-should-i-load-jars-dynamically-at-runtime" (sorry, only allowed one hyperlink), however this looked to violate the Class.newInstance evilness admonition in the first post I referenced.
Here is some reflection code that doesn't cast to an interface:
public class ReflectionDemo {
public void print(String str, int value) {
System.out.println(str);
System.out.println(value);
}
public static int getNumber() { return 42; }
public static void main(String[] args) throws Exception {
Class<?> clazz = ReflectionDemo.class;
// static call
Method getNumber = clazz.getMethod("getNumber");
int i = (Integer) getNumber.invoke(null /* static */);
// instance call
Constructor<?> ctor = clazz.getConstructor();
Object instance = ctor.newInstance();
Method print = clazz.getMethod("print", String.class, Integer.TYPE);
print.invoke(instance, "Hello, World!", i);
}
}
Writing the reflected classes to an interface known by the consumer code (as in the example) is generally better because it allows you to avoid reflection and take advantage of the Java type system. Reflection should only be used when you have no choice.
The code example
ClassLoader loader = URLClassLoader.newInstance(
new URL[] { yourURL },
getClass().getClassLoader()
);
Class<?> clazz = Class.forName("mypackage.MyClass", true, loader);
Class<? extends Runnable> runClass = clazz.asSubclass(Runnable.class);
// Avoid Class.newInstance, for it is evil.
Constructor<? extends Runnable> ctor = runClass.getConstructor();
Runnable doRun = ctor.newInstance();
doRun.run();
assumes that the class you are loading implements a particular interface Runnable, and therefore it's reasonale to cast to that type using asSubclass() and invoke run().
What do you know about the classes you are loading? Can you assume that they implement a particualr interface? If so adjust the asSubClass() line to reference the interafce you prefer.
Then, yes if you are working with instance methods create an instance using the contructor, ctor in the example.
There is no starting of a thread in the example. Creating a new thread would just have needed a couple of lines more code
Thread myThread = new Thread(doRun);
myThread.start();
Sample Program:
Project Printer:
public class Printer {
public void display(String printtext)
{
System.out.println(printtext);
}
}
This project is exported as Printer.jar.
Printer Class has method display() which takes string as input.
Invoking code:
URL url = new URL("file:Printer.jar");
URLClassLoader loader = new URLClassLoader (new URL[] {url});
Class<?> cl = Class.forName ("Printer", true, loader);
String printString = "Print this";
Method printit = cl.getMethod("display", String.class);
Constructor<?> ctor = cl.getConstructor(); //One has to pass arguments if constructor takes input arguments.
Object instance = ctor.newInstance();
printit.invoke(instance, printString);
loader.close ();
Output:
Print this

Categories

Resources