fail using a variable to call a method in java-android - java

I've tried using a variable to invoke a java method, using method.invoke(), as suggested in this example. But it seems there should be an object or something as a parameter in method.invoke(). I've tried using null, but the method didn't get invoked. My code is as follows:
String ACTION = "cart";
Method method = SolverService.class.getDeclaredMethod("Method" + ACTION);
method.invoke(null);
I've got a method as:
public void Methodcart(){
Toast.makeText(this,"Method called",Toast.LENGTH_LONG).show();
}
PS: I HAVE TO make this method.invoke() work. Otherwise, I need to write a very long list of switch-case statements.I've gone through the documentation but couldn't understand much about the object instance i might need to use here as I'm new to android app developing.

You can try something similar to the code shown below (Java Reflection) -
Suppose I have a class ClassWithMethods.java with the methods I want to invoke in some other class as shown below -
public class ClassWithMethods {
private int counter;
public void printIt(){
System.out.println("printIt() no param");
}
public void printItString(String temp){
System.out.println("printIt() with param String : " + temp);
}
}
Now I also have another class TestApp.java which will invoke methods of the ClassWithMethods class at runtime using Java Reflection -
public class TestApp {
public static void main(String[] args) {
//no paramater
Class noparams[] = {};
//String parameter
Class[] paramString = new Class[1];
paramString[0] = String.class;
//int parameter
Class[] paramInt = new Class[1];
paramInt[0] = Integer.TYPE;
try{
//load the ClassWithMethods at runtime
Class cls = Class.forName("com.myapps.ClassWithMethods");
Object obj = cls.newInstance();
//call the printIt method
Method method = cls.getDeclaredMethod("printIt", noparams);
method.invoke(obj, null);
//call the printItString method, pass a String param
method = cls.getDeclaredMethod("printItString", paramString);
method.invoke(obj, new String("someString"));
}catch(Exception ex){
ex.printStackTrace();
}
}

I am using Java Reflection in my current project (since you mentioned you are using Android Studio) to get Battery Capacity of device from PowerProfile class which is internal to the Android OS.
public double getBatteryCapacity() {
Object mPowerProfile = null;
try {
mPowerProfile = Class.forName("com.android.internal.os.PowerProfile")
.getConstructor(Context.class)
.newInstance(getContext());
} catch (Exception e) {
e.printStackTrace();
}
try {
// get access to method named "getAveragePower()" in the class "PowerProfile"
Method getAveragePower = Class.forName("com.android.internal.os.PowerProfile").getMethod("getAveragePower", String.class);
//Get total battery capacity in mAh.
double batteryCapacity = (Double) getAveragePower.invoke(mPowerProfile, "battery.capacity");
return batteryCapacity;
} catch (Exception e) {
e.printStackTrace();
}
return 0.0;
}
Here is a screenshot of how the actual method structure looks like in the PowerProfile class -

Related

How to call a method from another method within same class in java

I have two methods in the same class, the first method isgetEventByEventId and the second method is addEventUserRealtionMapping. I need to call the getEventByEventId method from the addEventUserRelationMapping method. How can I get that done?
public EventBO getEventByEventId(long eventId) throws UserServiceException {
try {
EventDO eventDO = eventDAOImpl.getEventByEventId(eventId);
EventBO eventBO = mapper.mapEventDOToBO(eventDO, new EventBO());
return eventBO;
} catch (UserDataException uExp) {
throw new UserServiceException("Error while getting event for event id " + eventId, uExp);
}
}
public int addEventUserRealtionMapping(ArrayList<UserBO> userBOs, long eventId) throws UserServiceException {
List<EventUserRelationDO> totalAddedCount;
ArrayList<UserDO> userDOs = new ArrayList<>();
try {
for (UserBO userBO : userBOs) {
UserDO userDO = mapper.mapUserBOToDO(userBO, new UserDO());
userDOs.add(userDO);
}
EventBO eventBO =new EventBO();
eventBO =getEventByEventId(eventId);//I am try that while call method1 but it doesn't work
MessageBO messageBO = new MessageBO();
messageBO.setEventId(eventBO.getEventId());
messageBO.setEventTitle(eventBO.getText());
messageBO.setMessage(eventBO.getText());
messageBO.setRingeeUserId(eventBO.getRingeeUserId());
messageBO.setMessageType(IRingeeConstants.MESSAGE_TYPE_INVITATION);
totalAddedCount = eventDAOImpl.addEventUserRelationMapping(userDOs, eventId);
if (totalAddedCount.size() == userDOs.size()) {
manageMessageService.sendMessageToGroup(userBOs, messageBO);
}
} catch (UserDataException dExp) {
throw new UserServiceException(" exception while adding user relationship for eventId " + eventId, dExp);
}
return totalAddedCount.size();
}
You can call it using this.methodName() or directly by writing the methodName()
class ClassName{
public void method1(){
}
public void method2(){
this.method1(); // called the first method of the same class
}
}
You can call function easily but you will need to put getEventByEventId inside try catch or throw UserServiceException form addEventUserRealtionMapping
if you have infinite loop it seem that you mapEventDOToBO calls addEventUserRealtionMapping inside it and you are try getEventByEventId again so that it causes infinite loop you

What security issues come from calling methods with reflection?

I'm working on a project that has hosts and clients, and where hosts can send commands to clients (via sockets).
I'm determined that using JSON to communicate works the best.
For example:
{
"method" : "toasty",
"params" : ["hello world", true]
}
In this example, when this JSON string is sent to the client, it will be processed and a suitable method within the client will be run as such:
public abstract class ClientProcessor {
public abstract void toasty(String s, boolean bool);
public abstract void shutdown(int timer);
private Method[] methods = getClass().getDeclaredMethods();
public void process(String data) {
try {
JSONObject json = new JSONObject(data);
String methodName = (String) json.get("method");
if (methodName.equals("process"))
return;
for (int i = 0; i < methods.length; i++)
if (methods[i].getName().equals(methodName)) {
JSONArray arr = json.getJSONArray("params");
int length = arr.length();
Object[] args = new Object[length];
for (int i2 = 0; i2 < length; i2++)
args[i2] = arr.get(i2);
methods[i].invoke(this, args);
return;
}
} catch (Exception e) {}
}
}
And using the ClientProcessor:
public class Client extends ClientProcessor {
#Override
public void toasty(String s, boolean bool) {
//make toast here
}
#Override
public void shutdown(int timer) {
//shutdown system within timer
}
public void processJSON(String json) {
process(json);
}
}
The JSON is sent by the server to the client, but the server could be modified to send different JSONs.
My questions are:
Is this a safe way of running methods by processing JSON?
Is there a better way to do this? I'm thinking that using reflection is terribly slow.
There's a 100 and 1 ways you can process a JSON message so that some processing occurs, but they'll all boil down to:
parse message
map message to method
invoke method
send response
While you could use a reflective call (performance-wise it would be fine for most cases) to invoke a method, that, imho, would be a little too open - a malicious client could for example crash your system by issuing wait calls.
Reflection also opens you up to having to correctly map the parameters, which is more complicated than the code you've shown in your question.
So don't use Reflection.
Would you could do is define a simple interface, implementations of which would understand how to process the parameters and have your processor (more commonly referred to as a Controller) invoke that, something like this:
public interface ServiceCall
{
public JsonObject invoke(JsonArray params) throws ServiceCallException;
}
public class ServiceProcessor
{
private static final Map<String, ServiceCall> SERVICE_CALLS = new HashMap<>();
static
{
SERVICE_CALLS.put("toasty", new ToastCall());
}
public String process(String messageStr)
{
try
{
JsonObject message = Json.createReader(new StringReader(messageStr)).readObject();
if (message.containsKey("method"))
{
String method = message.getString("method");
ServiceCall serviceCall = SERVICE_CALLS.get(method);
if (serviceCall != null)
{
return serviceCall.invoke(message.getJsonArray("params")).toString();
}
else
{
return fail("Unknown method: " + method);
}
}
else
{
return fail("Invalid message: no method specified");
}
}
catch (Exception e)
{
return fail(e.message);
}
}
private String fail(String message)
{
return Json.createObjectBuilder()
.add("status", "failed")
.add("message", message)
.build()
.toString();
}
private static class ToastCall implements ServiceCall
{
public JsonObject invoke(JsonArray params) throws ServiceCallException
{
//make toast here
}
}
}
Map method names to int constants and just switch(case) on these constants to invoke appropriate method.
"toasty" : 1
"shutdown": 2
switch()
case 1: toasty()
case 2: shutdown()
I believe you are trying to convert JSON string to Java object and vice versa... if that is the requirement then this would not be the right approach...
Try any open source API like Gson...
it is the API by Google for conversin of Java to JSON and vice versa.
Please check ...
https://google-gson.googlecode.com/svn/trunk/gson/docs/javadocs/com/google/gson/Gson.html
Let me know if you have any further questions...

How to overwrite and call a function on a Java object in Oracle Nashorn?

I have a Java object, which needs to get initialized by some Java code. This object will then be put into the nashorn engine. Some JavaScript code will be called, which should overwrite a method on this object. Later back in Java the overwritten method should be called.
This code does not work:
First: the method "test" is not overwritten -> calling it returns "3".
Second: calling the original "test" method fails with an exception "getInterface cannot be called on non-script object"
public static class O
{
public int mV = 0;
public O(int V)
{
mV = V;
}
public Object test (Object o)
{
return mV;
}
}
public static void main(String[] args)
{
ScriptEngineManager factory = new ScriptEngineManager();
ScriptEngine jsEngine = factory.getEngineByName("nashorn");
Invocable iv = (Invocable)jsEngine;
try
{
Object o = new O(3);
jsEngine.put("o", o);
jsEngine.eval("o.test = function(x) { return mV * x; };");
Object test = jsEngine.eval("o.test(8);"); // test is 3 here
o = jsEngine.get("o");
Object result = iv.invokeMethod(o, "test", 4); // this line will throw an exception
System.out.println(result.toString());
}
catch (Exception e1)
{
e1.printStackTrace();
}
Ok, got it. I cannot add functions to Java objects. I create a JS object via helper-function "makeJsObject" and keep a reference to the Java object in a property. I can then add a method to the JS object and call this via invokeMethod from Java.
jsEngine.eval("function makeJsObject(nativeObject) { return {nativeObject:nativeObject}; };");
O o = new O(3);
Object q = iv.invokeFunction("makeJsObject", o);
jsEngine.put("q", q);
jsEngine.eval("q.test = function(x) { return this.nativeObject.test(this.nativeObject.mV * x); };");
Object result = iv.invokeMethod(q, "test", 4);

Java Reflection: "java.lang.NoSuchMethodException"

I am trying to get the method from another class using reflection, but for some reason it keeps on giving me a no such method exception. These are the classes im using:
ScriptTable class:
for(Class<?> script: Scripts) {
System.out.println(script.getName());
try {
Method c = script.getMethod("scriptInfo()", script);
} catch(Exception e) {
e.printStackTrace();
}
}
DummyScript class
public String[] scriptInfo() {
String[] ScriptInfo = {"DummyScript", "Chris", "Does nothing atm"};
return ScriptInfo;
}
This is your problem:
script.getMethod("scriptInfo()", script);
change it to:
script.getMethod("scriptInfo");
and look here to see why:
http://docs.oracle.com/javase/7/docs/api/java/lang/Class.html#getMethod%28java.lang.String,%20java.lang.Class...%29

How to Use Method via Reflection Java

I am trying to use reflection instead of including a jar file. I want to do this to reduce my apk size when I am not using the jar code...but if I include the code, I must include the jar. That being said, I am trying to grasp reflection and not doing well.
I have this code to see the methods available (and it works):
//initialize method params
Class[] paramInitialize = new Class[2];
paramInitialize[0] = Activity.class;
paramInitialize[1] = String.class;
try {
Logger.i(DEBUG_TAG, "try statement");
Class <?> tremorVideoCls = Class.forName("com.tremorvideo.sdk.android.videoad.TremorVideo");
Class <?> tremorSettingsCls = Class.forName("com.tremorvideo.sdk.android.videoad.Settings");
Object object = tremorVideoCls.newInstance();
String apkName = this.getPackageManager().getApplicationInfo(this.getPackageName(), 0).sourceDir;
loader = new dalvik.system.PathClassLoader(apkName, ClassLoader.getSystemClassLoader());
tremorVideoCls = loader.loadClass("com.tremorvideo.sdk.android.videoad.TremorVideo");
Method m[] = tremorVideoCls.getMethods();
Method declaredM[] = tremorVideoCls.getDeclaredMethods();
for (int i = 0; i < m.length; i++) {
Logger.i(DEBUG_TAG, "getMethods is " + m[i].toString());
}
Field []field = tremorSettingsCls.getFields();
for (int i = 0; i < field.length; i++) {
Logger.i(DEBUG_TAG, "getFields is " + field[i].toString());
}
Method tremorInitialize = tremorVideoCls.getMethod("initialize", paramInitialize);
Logger.i(DEBUG_TAG, "tremorInitialize is " + tremorInitialize.toGenericString());
// tremorInitialize.invoke(object, this, ACCUWX.TREMOR_ADSPACE_TEST);
} catch (ClassNotFoundException e) {
} catch (NoSuchMethodException x) {
...
BUT, I get a logcat error throwing an exception:
08-06 11:48:51.134: W/System.err(11688): java.lang.NoSuchMethodException: initialize [class android.app.Activity, class java.lang.String]
Here is the logcat printing out that method:
08-06 11:48:51.118: I/Flagship/MainActivity(11688): getMethods is public static void com.tremorvideo.sdk.android.videoad.TremorVideo.initialize(android.content.Context,java.lang.String)
I'm not sure what do try next...any help greatly appreciated.
If the method which you are trying to invoke is
public static void com.tremorvideo.sdk.android.videoad.TremorVideo.initialize(android.content.Conte‌​xt,java.lang.String)
and the error is
08-06 11:48:51.134: W/System.err(11688): java.lang.NoSuchMethodException: initialize [class android.app.Activity, class java.lang.String]
It clearly indicates that the method expects android.content.Conte‌​xt but what you are passing android.app.Activity
In the call
tremorInitialize.invoke(object, this, ACCUWX.TREMOR_ADSPACE_TEST);
instead of passing this you should pass an instance of android.content.Conte‌​xt.
Hope this helps!!!
The issue is not the invocation of the method but the call to retreiving the method.
Because the Class[] is initialized with Activity.class, a method with the signature
void initialize(Activity activity, String string) is searched for.
This method doesn't exist.
So it should be
paramInitialize[0] = Context.class;
to find the method
initialize(Contex ctxt, String arg).

Categories

Resources