Can't invoke a method obtained through reflection - java

I am getting the error
Cannot invoke "Object.getClass()" because "obj" is null
on the line
m.invoke(null);
Here are the classes:
package device;
public class Conveyor {
private String ID;
public Conveyor(String ID) {this.ID = ID;}
public void Start() {
}
public void Stop() {
}
}
package main;
import java.lang.reflect.Method;
import device.Conveyor;
public class Main {
public static void main(String args[]) {
Conveyor myConveyor = new Conveyor("C1");
Class<Conveyor> conveyorClass = (Class<Conveyor>) myConveyor.getClass();
for (Method m : conveyorClass.getMethods()) {
System.out.println(m.getName());
if (m.getName().equals("Start")) {
try {
m.invoke(null);
} catch (Exception ex) {
System.err.println(ex.getLocalizedMessage());
}
}
}
}
}

Acording to the docs, the invoke method receive the reference of the object that will call the method. So you need to change the code to be:
m.invoke(myConveyor);
See the docs https://docs.oracle.com/javase/8/docs/api/java/lang/reflect/Method.html#invoke-java.lang.Object-java.lang.Object...-

Per #markspace , I edited the invoke to add the invoking object:
m.invoke(myConveyor);

Related

How to Pass Interface Object to a Method

I have a main class as shown below. I want to Pass interface object to another method from Main method. I am Passing it as shown in my Main class below. But I am getting error "; expected". Can some one please help me?
This is my Main Class :
package com.armus.web.server;
import com.armus.common.dtflow.DfService;
public class TriggerAgain
{
public static void main(String[] args){
Long i= 97944605L;
DMSerImpl rdf = new DMSerImpl();
try {
/*********** Section start....Getting Problem In this section...How Can I Pass interface object to a method setDfService*********/
#Override
rdf.setDfService(new DfService()
{
Dfsessn dfsessn=getDfsessnById(i)
{
System.out.println("In main class...In interface method="+i);
}
})
/*************************************************Section End*******************************************************************/
com.armus.dto.Jinfo a=rdf.Trigger(i);
}
catch( Throwable e){
System.out.println("In exception = "+e+" "+i);
e.printStackTrace();
return; // Always must return something
}
}
}
This is my another class to which I want to Pass interface Object to "setDfService" Method.
package com.armus.web.server;
import com.armus.common.dtflow.DfService;
import com.armus.common.dto.Dfsessn;
import com.armus.foundation.client.exception.ServiceException;
import com.armus.dto.Jinfo;
public class DMSerImpl
extends Remoteservletsup
implements DMserv, DMAjxSer
{
private DfService dtflowser;
public void setDfService(DfService dtflowser)
{
this.dtflowser = dtflowser;
}
private Dfsessn getDfsessn(long sessionId)
throws ServiceException
{
try
{
dfSession = this.dtflowser.getDfsessnById(Long.valueOf(sessionId));
}
catch (ServerException e)
{
Dfsessn dfSession;
LOG.error(e.getMessage(), e);
throw new ServiceException(e.getMessage());
}
return dfSession;
}
public com.armus.dto.Jinfo Trigger(long sessionId)
throws ServiceException
{
Dfsessn dfSession = getDfsessn(sessionId);
//some code
}
}
Below is My Interface :
package com.armus.common.dtflow;
import com.armus.common.dto.Dfsessn;
import com.armus.common.exception.ServerException;
public abstract interface DfService
{
public abstract Dfsessn getDfsessnById(Long paramLong)
throws ServerException;
}
Thank you in Advance !!! :)
This is an example of creating an instance of an anonymous class
rdf.setDfService(new DfService() {
#Override
public Dfsessn getDfsessnById(Long paramLong) {
....
}});
You are:
Putting the #Override in the wrong place;
not declaring the method override properly; and
missing a closing semicolon:
rdf.setDfService(new DfService()
{
#Override
public Dfsessn getDfsessnById(Long i)
{
System.out.println("In main class...In interface method="+i);
}
});
#Override
rdf.setDfService(new DfService()
{
Dfsessn dfsessn=getDfsessnById(i)
{
System.out.println("In main class...In interface method="+i);
}
})
Above what you are trying to do is creating an anonymous class instance implementing the DfService interface but you are not doing it correctly(syntax wise).
Read about anonymous inner classes here https://www.geeksforgeeks.org/anonymous-inner-class-java/
Also, DfService is a functional interface(single method interface) so you can also use a lamda here. Something like this.
rdf.setDfService(paramLong -> System.out.println("In main class...In interface method="+i));
Take a look at this for more info https://javarevisited.blogspot.com/2015/01/how-to-use-lambda-expression-in-place-anonymous-class-java8.html

Run method inside a method in java

I'm sending more than 1 request to a web service, below there is an example of that requests. Its important for my application to get the answer from the web service so if there is an exception application will try couple of times to get the answer.
Because of that getting something simple like
deviceList = serviceAdapter.getDevices(); is turn into below code.
boolean flag = true;
int counter = 1;
List<Device> deviceList = null;
while (flag) {
try {
deviceList = serviceAdapter.getDevices();
flag = false;
} catch (Exception e) {
try {
if (counter == 5) {
System.out.println("Timeout Occured!");
flag = false;
} else {
Thread.sleep(1000 * counter);
counter++;
}
} catch (InterruptedException e1) {
}
}
}
And in my application i have lots of requests which means there will be more ugly codes. Is there a way where i will call my request methods as parameter for another method something like this:
deviceList = wrapperMethod(serviceAdapter.getDevices());
Problem is there will be different type of requests, so they will return different type objects (list,array,string,int) and their paramaters will change. Is there a suitable solution in java for this problem?
You can pass a Supplier<T> to the wrapperMethod:
public static <T> T wrapperMethod (Supplier<T> supp) {
boolean flag = true;
int counter = 1;
T value = null;
while (flag) {
try {
value = supp.get();
flag = false;
} catch (Exception e) {
try {
if (counter == 5) {
System.out.println("Timeout Occured!");
flag = false;
} else {
Thread.sleep(1000 * counter);
counter++;
}
} catch (InterruptedException e1) {
}
}
}
}
And call it with:
List<Device> deviceList = wrapperMethod (() -> serviceAdapter.getDevices());
I'm afraid, though, that it will limit the methods you call within the lambda expression to throw only RuntimeExceptions.
You can use some command implementation to execute some specific codes :
Here is a simple example of a command
interface Command{
void run();
}
And a couple of implementations :
class SayHello implements Command{
#Override
public void run() {System.out.println("Hello World");}
}
class KillMe implements Command{
public void run() { throw new RuntimeException();};
}
All we have to do to execute those method is to receive an instance of Command and run the method :
public static void execCommand(Command cmd) {
cmd.run();
}
And to use this
public static void main(String[] args) {
execCommand(new SayHello());
execCommand(new KillMe());
}
Hello World
Exception in thread "main" java.lang.RuntimeException
It also accepts lambda expression :
execCommand(() -> System.out.println("Say goodbye"));
And method reference :
public class Test{
public static void testMe() {
System.out.println("I work");
}
}
execCommand(Test::testMe);
Note that I didn't specify that this could throw Exception so I am limited to unchecked exception like RuntimeException but of course void run() throws Exception could be a solution. That way you can do what ever you want.
Full example (with exceptions) :
public class Test {
public static void main(String[] args) {
try {
execCommand(new SayHello());
execCommand(() -> System.out.println("Say goodbye"));
execCommand(Test::testMe);
execCommand(new KillMe());
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public static void testMe() throws IOException{
System.out.println("I work");
}
public static void execCommand(Command cmd) throws Exception {
cmd.run();
}
}
interface Command{
void run() throws Exception;
}
class SayHello implements Command{
#Override
public void run() {System.out.println("Hello World");}
}
class KillMe implements Command{
public void run() { throw new RuntimeException();};
}
Output:
Hello World
Say goodbye
I work
Exception in thread "main" java.lang.RuntimeException
at main.KillMe.run(Test.java:39)
at main.Test.execCommand(Test.java:25)
at main.Test.main(Test.java:17)
You can use #RetryOnFailure annotation from jcabi-aspects
Create a wrapper method then annotate it to enable auto retry upon Exception
As an example:
#RetryOnFailure(attempts = 5)
List<Device> retryWhenFailed(ServiceAdapter serviceAdapter) throws Exception {
return serviceAdapter.getDevices();
}
This solution uses Generics to be able to handle different Object with most of the same code and a Runnable to execute the fetching.
With this solution, you would need only to write the different adapters extending from ServiceAdapter<T extends Fetchable> to implement the logic to fetch the data for each different class (which would have to implement Fetchable).
Define an interface that abtracts the objects that can be fetched by the different services.
package so50488682;
public interface Fetchable {
}
The ojbect that are to be retrieved implement this interface so you can use the same code for different classes.
package so50488682;
public class Device implements Fetchable{
private String id;
public Device(String id) {
this.id = id;
}
public String toString() {
return "I am device " + id;
}
}
Define an abstract ServiceAdapter that the different service adapters will extend to implement the logic for each kind of object to be retrieved. We add throws Exception to the get() method so this method cand just delegate the exception handling to the FetcherService and decide if it should retry or fail.
package so50488682;
import java.util.List;
public abstract class ServiceAdapter<T extends Fetchable> {
public abstract List<T> get() throws Exception;
}
This is an example of an implementation done to get objects of class Device.
package so50488682;
import java.util.ArrayList;
import java.util.List;
public class DeviceServiceAdapter extends ServiceAdapter<Device>{
#Override
public List<Device> get() throws Exception{
List<Device> rtn = new ArrayList<>();
// fetch the data and put it into rtn, this is a mock
Device d = new Device("1");
rtn.add(d);
d = new Device("2");
rtn.add(d);
d = new Device("3");
rtn.add(d);
//
return rtn;
}
}
Finally this is a generic solution to run the different service adapters.
public class FetcherService<T extends Fetchable> implements Runnable{
List<T> result = new ArrayList<>();
ServiceAdapter<T> serviceAdapter;
#Override
public void run() {
boolean flag = true;
int counter = 1;
while (flag) {
try {
result = serviceAdapter.get();
flag = false;
} catch (Exception e) {
try {
if (counter == 5) {
System.out.println("Timeout Occured!");
flag = false;
} else {
Thread.sleep(1000 * counter);
counter++;
}
} catch (InterruptedException e1) {
throw new RuntimeException("Got Interrupted in sleep", e);
}
}
}
}
public List<T> getResult() {
return result;
}
public void setResult(List<T> result) {
this.result = result;
}
public void setAdapter(ServiceAdapter<T> adapter) {
this.serviceAdapter = adapter;
}
}
From the main or calling program it work like this:
package so50488682;
import java.util.List;
public class SO50488682 {
public static void main(String args[]) {
try {
DeviceServiceAdapter deviceServiceAdapter = new DeviceServiceAdapter();
FetcherService<Device> deviceFetcherService = new FetcherService<>();
deviceFetcherService.setAdapter(deviceServiceAdapter);
deviceFetcherService.run();
List<Device> devices = deviceFetcherService.getResult();
for(Device device : devices) {
System.out.println(device.toString());
}
}catch(Exception e) {
System.out.println("Exception after retrying a couple of times");
e.printStackTrace();
}
}
}

Create object in function based on Class argument

I want to define a function that creates different type objects that share the same base class. I'd like to pass in the object type and have the function creating the object and then modifying its attributes. The problem is that the main class from which all these objects are created, does not have the object's attributes so the code fails to compile.
Example:
public void new_generic_report(Class report_class, String report_name) {
Report new_report = this.reportManager.createReport(report_class);
new_report.set_name(report_name);
}
Calling new_generic_report(GreenReport.class, "green_report"); fails because new_report is of the class Report instead of GreenReport so it does not have the .set_name method.
I know I could implement the .set_name method (and other common methods) in the main Report class but I am writing code to interface with an API that I cannot modify.
If you are sure that createReport returns an instance of the correct class you can just do a cast:
((SpecialClass)new_report).set_name(report_name);
An alternative is to use reflection:
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
public class Test {
static class Base {};
static class Child extends Base {
public void setName(final String name) {
System.out.println("setName("+name+")");
}
}
public static void main(String[] args) {
new Test().new_generic_report(Child.class, "Testname");
}
public void new_generic_report(final Class clazz, final String name) {
Base base = createBase(clazz);
try {
Method m = clazz.getMethod("setName", String.class);
m.invoke(base, name);
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
}
private Base createBase(Class report_class) {
return new Child();
}
}
Of course this only works, if the returned instance implements the method.
Create a parent class for your report for instance :
public abstract class NamedReport extends Report
{
public abstract void setName(String name);
}
class GreenReport extends NamedReport {
#Override
public void setName(String name) {
}
}
Then simply cast your class in your method :
public void new_generic_report(Class report_class, String report_name) {
Report new_report = this.reportManager.createReport(report_class);
if (new_report instanceof NamedReport)
{
((NamedReport)new_report).set_name(report_name);
}
}

Dynamically invoke a method from a varying class

I have a requirement where in i need to invoke method from class in a particular pattern which is obtained as input argument.
public RandomMethod(String ClassName){
//Eg For Class Name Abc , there is a method AbcProcessor which i need to invoke
ClassName.ClassNameProcessor
}
Since i am getting the argument as String , i am not able to figure out how to cast String into a form where i can call something like Abc.AbcProcessor()
I believe there is some way to do this using reflections. But i am not sure how to proceed.
By reflection you can do that, try following sample:
Class A:
public class A {
public void print(){
System.out.println("A");
}
}
Class B:
public class B {
public void print(){
System.out.println("B");
}
}
Invoking print() from A and B:
public class Test {
public static void callPrint(String className){
try {
Class clazz = Class.forName(className);
Object obj = clazz.newInstance();
clazz.getDeclaredMethod("print").invoke(obj);
} catch (Exception ex) {
ex.printStackTrace();
}
}
public static void main(String[] args) {
callPrint("test.A");
callPrint("test.B");
}
}
You need to use reflecton, indeed:
public void randomMethod(String fullyQualifiedClassName, String methodName) throws ReflectiveOperationException {
Class<?> clazz = Class.forName(fullyQualifiedClassName);
clazz.getMethod(methodName).invoke(null);
}
which would work assuming you are calling public static method with no arguments

How to generically implement calling methods stored in a HashMap?

I want to route certain chars to methods, so that when the char is typed in the command-line the method is then executed.
Based on the answer How to call a method stored in a HashMap, I'm mapping these chars to methods by using the "Command" design-pattern.
However I want to generically implement this, so it seems that I need to implement reflection in order to use the Method class as a parameter. My attempt is getting a NullPointerException on the field private Method method in my anonymous class...
Here is my code:
import java.lang.reflect.Method;
public interface InvokesMethod {
public void invokeMethod() throws Exception;
public void setMethod(Method method);
} // end of interface
import java.util.HashMap;
import java.lang.reflect.Method;
public class Terminal {
public HashMap<Character, InvokesMethod> commands;
public Terminal() {
this.commands = new HashMap<Character, InvokesMethod>();
try {
this.setCommand('p',
this.getClass().getDeclaredMethod("printHelloWorld"));
} catch (Exception e) {
e.printStackTrace();
}
}
private void printHelloWorld() {
System.out.println("Hello World!");
}
private void setCommand(char letter, Method method) {
this.commands.put(letter, new InvokesMethod() {
// NullPointerException starts here in the stack-trace:
private Method method;
#Override
public void invokeMethod() throws Exception {
method.invoke(null);
}
#Override
public void setMethod(Method method) {
this.method = method;
}
}).setMethod(method);
}
public void executeCommand(char letter) throws Exception {
this.commands.get(letter).invokeMethod();
}
} // end of class
public class Main() {
public static void main(String[] args) {
Terminal commandLine = new Terminal();
try {
commandLine.executeCommand('p');
} catch (Exception e) {
e.printStackTrace();
}
}
} // end of class
Regards to your code you didn't initiate method. Bear in mind that execute with null you must call public static method:
Your other issue , you didn't initiated interface properly. Here is working example:
InvokesMethodItf
public interface InvokesMethodItf {
public void invokeMethod() throws Exception;
public void setMethod(Method method);
}
InvokesMethod
public class InvokesMethod implements InvokesMethodItf{
private Method method;
#Override
public void invokeMethod() throws Exception {
method.invoke(null);
}
#Override
public void setMethod(Method method) {
this.method = method;
}
}
Terminal
public class Terminal {
public HashMap<Character, InvokesMethodItf> commands;
public Terminal() {
this.commands = new HashMap<Character, InvokesMethodItf>();
try {
this.setCommand('p',
this.getClass().getDeclaredMethod("printHelloWorld"));
} catch (Exception e) {
e.printStackTrace();
}
}
public static void printHelloWorld() {// method.invoke(null) looking for "static" method
System.out.println("Hello World!");
}
private void setCommand(char letter, Method method) {
InvokesMethodItf inv = new InvokesMethod();
inv.setMethod(method);
this.commands.put(letter, inv);
}
public void executeCommand(char letter) throws Exception {
this.commands.get(letter).invokeMethod();
}
}
Main
public class Main {
public static void main(String[] args) {
Terminal commandLine = new Terminal();
try {
commandLine.executeCommand('p');
} catch (Exception e) {
e.printStackTrace();
}
}
}
Output:
Hello World!
Thanks to #Maxim's original suggestion here, I have an alternate solution by setting the methods as Strings in the HashMap instead --
import java.util.HashMap;
import java.lang.reflect.Method;
public class Terminal {
private HashMap<Character, String> commands;
public Terminal() {
this.commands = new HashMap<Character, String>();
this.commands.put('p', "printHelloWorld");
}
private void printHelloWorld() {
System.out.println("Hello World!");
}
public void executeCommand(char letter) throws Exception {
Method method = getClass().getDeclaredMethod(this.commands.get(letter));
method.invoke(this);
}
public class Main {
public static void main(String[] args) {
Terminal commandLine = new Terminal();
try {
commandLine.executeCommand('p');
} catch (Exception e) {
e.printStackTrace();
}
}
} // end of class
Output:
Hello World!
Now to figure out how to pass parameters to the reflected methods...

Categories

Resources