How to invoke Kotlin object method using reflection in Java? - java

I want to invoke setApiHelper method in the below code using java reflection. How can I do so?
object PlayerUtils {
private var apiHelper: String? = null
fun setApiHelper(apiHelper: String) {
this.apiHelper = apiHelper
println(apiHelper)
}
fun getApiHelper(): String? {
return this.apiHelper
}
}
My Implementation
private static void testingPlayerUtils() {
try {
Class<?> cls = Class.forName("reflection.PlayerUtils");
cls.newInstance();
Method method = cls.getDeclaredMethod("setApiHelper");
method.invoke(cls.newInstance(), "TESTING");
} catch (ClassNotFoundException | NoSuchMethodException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
}
this gives an error
java.lang.IllegalAccessException: Class TestingReflection2 can not access a member of class reflection.PlayerUtils with modifiers "private"
at sun.reflect.Reflection.ensureMemberAccess(Reflection.java:102)
at java.lang.Class.newInstance(Class.java:436)
at TestingReflection2.testingPlayerUtils(TestingReflection2.java:20)
at TestingReflection2.main(TestingReflection2.java:14)

Usually when you want to access object declared in Kotlin using Java code, you can do like below code snippet:
PlayerUtils.INSTANCE.setApiHelper("");
//or
PlayerUtils.INSTANCE.getApiHelper();
Now that being said, in order to access methods of PlayerUtils in Java using reflection, you'll need to access it's static member called INSTANCE first.
And you can do that by using Field from Class declaration, something like below:
Class<?> cls = Class.forName("reflection.PlayerUtils");
Object instance = cls.getField("INSTANCE");
Method method = cls.getDeclaredMethod("setApiHelper");
method.invoke(instance, "TESTING");
Refer here for detailed info.

You need to set accessible true for the method as below -
Class<?> cls = Class.forName("reflection.PlayerUtils");
cls.newInstance();
Method method = cls.getDeclaredMethod("setApiHelper");
method.setAccessible(true);
method.invoke(cls.newInstance(), "TESTING");

Related

Android how do to reflection in android.telecom.Call class

I want to block a phone call and i try using reflection android.telecom.Call class with following code but this class does not has constructor .
try {
Class c = Class.forName("android.telecom.Call");
Method m = c.getMethod("disconnect");
m.setAccessible(true);
Object o = m.invoke(c, new Object[] {});
} catch (Exception e) {
Log.e("Exception of Reflection", e.getLocalizedMessage());
}
You need to instantiate Class Call because you'll use the instance as a target for you method invocation.
The method getMethod ignores non-public method. You should use getDeclaredMethod to find your private method.
Your code may look like this:
try
{
Class<?> c = Class.forName("android.telecom.Call");
Object instance = c.newInstance();
Method m = c.getDeclaredMethod("disconnect");
m.setAccessible(true);
m.invoke(instance, new Object[] {});
}
catch (Exception e)
{
Log.e("Exception of Reflection", e.getLocalizedMessage());
}

Reflection invoke throws IllegalArgumentException

what am i missing here?
I get the exception: java.lang.IllegalArgumentException: object is not an instance of declaring class
public boolean onSave(Object entity,Serializable id,Object[] state, String[] propertyNames, Type[] types) {
Class<?> clazz=entity.getClass();
System.out.println(" Clazzz is:"+clazz);
Method[] methods = clazz.getMethods();
for(Method method : methods){
if(method.getName().startsWith("get") && String.class.equals(method.getReturnType())){
System.out.println("getter: " + method);
try {
String s=(String) method.invoke(clazz,(Object[]) null); //java.lang.IllegalArgumentException: object is not an instance of declaring class
System.out.println(" value in s is:"+s);
} catch (IllegalAccessException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
You need to write
String s=(String) method.invoke(entity, (Object[]) null);
The first parameter of Method.invoke is null for static methods or the object on which the method should be invoked.

Java Method.invoke() throwing IllegalArgumentException: argument type mismatch

I am trying to invoke a static method with a Object[] parameter type. When I debug, the correct method is identified and the parameter type I put in seems to me to be of the correct type.
public String convertToJSFunction(Method method, Object[] params) {
String function = method.getName();
for (Method m : JavaToJS.class.getDeclaredMethods()) {
if (m.getName().equals(function))
try {
return (String) m.invoke(null,params);
} catch (IllegalAccessException e) {
e.printStackTrace();
return null;
} catch (InvocationTargetException e) {
e.printStackTrace();
return null;
} catch (IllegalArgumentException e) {
e.printStackTrace();
return null;
}
}
return null;
}
JavaToJS has only static methods. After debugging, the m I am trying to invoke is this method:
public static String setRegionNumber(Object[] params)
This throws an IllegalArgumentException: argument type mismatch. How is this possible?
i guess you are calling
Method setRegionNumber=...; // "setRegionNumber" Method
Object[] params=...; // your Object-Array Parameter
convertToJSFunction(setRegionNumber, params);
but what you need to do is
Method setRegionNumber=...; // "setRegionNumber" Method
Object[] params=...; // your Object-Array Parameter
convertToJSFunction(setRegionNumber, new Object[] { params });
this is because Method.invoke expects the parameter list of the called method as an object Array. So if you pass your object array directly then it interprets that as the parameter list. so if you have an Object[] Parameter you need to wrap it in an Object-Array just like any other parameter.

Reflection in inhertited classes

I use this method to remove Html code from my Strings in classes:
public void filterStrings() {
Field[] fields = this.getClass().getDeclaredFields();
if (fields == null) {
return;
}
for (Field f : fields) {
if (f.getType() == java.lang.String.class) {
try {
String value = (String) f.get(this);
f.set(this, methodToRemoveHtml(value));
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
}
}
Works fine. Since I caught myself putting this method in many classes I use, I thought I'd let all those classes inherit from a BaseClass and implement the method only there.
But when I do this, I get a: java.lang.IllegalAccessException: access to field not allowed on every try.
Why is this happening and
How can I fix this?
I guess the fields are private, so they can only be accessed from code inside the class that contains them, and not a superclass.
You have to make them accessible by calling setAccessible(true); on them or making them public or protected.
for (Field f : fields) {
if (f.getType() == java.lang.String.class) {
try {
f.setAccessible(true); // make field accessible.
String value = (String) f.get(this);
// ...
May be you need to call:
f.setAccessible(true);

Using reflection in Java to create a new instance with the reference variable type set to the new instance class name?

All the examples I look at for reflection show creating a new instance of an unknown implementation, and casting that implementation to it's interface. The issue with this is that now you can't call any new methods (only overrides) on the implementing class, as your object reference variable has the interface type. Here is what I have:
Class c = null;
try {
c = Class.forName("com.path.to.ImplementationType");
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
InterfaceType interfaceType = null;
try {
interfaceType = (InterfaceType)c.newInstance();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
If I only have a reference to "com.path.to.ImplementationType", and I don't know what that type might be (it is coming from a config file), then how can I use the class name to cast it to ImplementationType? Is this even possible?
This line seems to sum up the crux of your problem:
The issue with this is that now you can't call any new methods (only overrides) on the implementing class, as your object reference variable has the interface type.
You are pretty stuck in your current implementation, as not only do you have to attempt a cast, you also need the definition of the method(s) that you want to call on this subclass. I see two options:
1. As stated elsewhere, you cannot use the String representation of the Class name to cast your reflected instance to a known type. You can, however, use a String equals() test to determine whether your class is of the type that you want, and then perform a hard-coded cast:
try {
String className = "com.path.to.ImplementationType";// really passed in from config
Class c = Class.forName(className);
InterfaceType interfaceType = (InterfaceType)c.newInstance();
if (className.equals("com.path.to.ImplementationType") {
((ImplementationType)interfaceType).doSomethingOnlyICanDo();
}
} catch (Exception e) {
e.printStackTrace();
}
This looks pretty ugly, and it ruins the nice config-driven process that you have. I dont suggest you do this, it is just an example.
2. Another option you have is to extend your reflection from just Class/Object creation to include Method reflection. If you can create the Class from a String passed in from a config file, you can also pass in a method name from that config file and, via reflection, get an instance of the Method itself from your Class object. You can then call invoke(http://java.sun.com/javase/6/docs/api/java/lang/reflect/Method.html#invoke(java.lang.Object, java.lang.Object...)) on the Method, passing in the instance of your class that you created. I think this will help you get what you are after.
Here is some code to serve as an example. Note that I have taken the liberty of hard coding the params for the methods. You could specify them in a config as well, and would need to reflect on their class names to define their Class obejcts and instances.
public class Foo {
public void printAMessage() {
System.out.println(toString()+":a message");
}
public void printAnotherMessage(String theString) {
System.out.println(toString()+":another message:" + theString);
}
public static void main(String[] args) {
Class c = null;
try {
c = Class.forName("Foo");
Method method1 = c.getDeclaredMethod("printAMessage", new Class[]{});
Method method2 = c.getDeclaredMethod("printAnotherMessage", new Class[]{String.class});
Object o = c.newInstance();
System.out.println("this is my instance:" + o.toString());
method1.invoke(o);
method2.invoke(o, "this is my message, from a config file, of course");
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (NoSuchMethodException nsme){
nsme.printStackTrace();
} catch (IllegalAccessException iae) {
iae.printStackTrace();
} catch (InstantiationException ie) {
ie.printStackTrace();
} catch (InvocationTargetException ite) {
ite.printStackTrace();
}
}
}
and my output:
this is my instance:Foo#e0cf70
Foo#e0cf70:a message
Foo#e0cf70:another message:this is my message, from a config file, of course
//====Single Class Reference used to retrieve object for fields and initial values. Performance enhancing only====
Class<?> reference = vector.get(0).getClass();
Object obj = reference.newInstance();
Field[] objFields = obj.getClass().getFields();
I'm not absolutely sure I got your question correctly, but it seems you want something like this:
Class c = null;
try {
c = Class.forName("com.path.to.ImplementationType");
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
T interfaceType = null;
try {
interfaceType = (T) c.newInstance();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
Where T can be defined in method level or in class level, i.e. <T extends InterfaceType>
As an addendum to akf's answer you could use instanceof checks instead of String equals() calls:
String cname="com.some.vendor.Impl";
try {
Class c=this.getClass().getClassLoader().loadClass(cname);
Object o= c.newInstance();
if(o instanceof Spam) {
Spam spam=(Spam) o;
process(spam);
}
else if(o instanceof Ham) {
Ham ham = (Ham) o;
process(ham);
}
/* etcetera */
}
catch(SecurityException se) {
System.err.printf("Someone trying to game the system?%nOr a rename is in order because this JVM doesn't feel comfortable with: ā€œ%sā€", cname);
se.printStackTrace();
}
catch(LinkageError le) {
System.err.printf("Seems like a bad class to this JVM: ā€œ%sā€.", cname);
le.printStackTrace();
}
catch(RuntimeException re) {
// runtime exceptions I might have forgotten. Classloaders are wont to produce those.
re.printStackTrace();
}
catch(Exception e) {
e.printStackTrace();
}
Note the liberal hardcoding of some values. Anyways the main points are:
Use instanceof rather than equals(). If anything, it will co-operate better when refactoring.
Be sure to catch these runtime errors and security ones too.
You want to be able to pass in a Class and get a type-safe instance of that class? Try the following:
public static void main(String [] args) throws Exception {
String s = instanceOf(String.class);
}
public static <T> T instanceOf (Class<T> clazz) throws Exception {
return clazz.newInstance();
}
If you knew the Class of ImplementationType you could create an instance of it. So what you are trying to do is not possible.

Categories