Basically there is nothing hard to access methods with reflection. It gives opportunities to get from class and its instances everything. But recently I found out some strange behavior which I didn't expect.
The problem is that you cannot access methods introduced with public interface contract but declared in private scope, unless you call setAccessible method.
Lets look at one simple example.
We have widely used interface java.util.List and it describes contract that every class implementing this interface with have public method size(). So when in somewhere in the code we have an instance of a class implementing List interface we can easily call to size and get what we expect.
But everything changes when reflection comes. I thought that usually we can access every method or other class element with reflection in case if it is visible for static code from the same scope.
Suppose we have such decleration:
We can replace this code with reflection based one:
But there is another approach to create names.
The reason is that we access to class in Runtime with getClass() method, but it is private, so we cannot get it's methods:
This time our code will work:
Use public classes to access methods which will be accessible in Runtime or force reflection to get to method with setAccessible.
All the code is available at GitHub.
The problem is that you cannot access methods introduced with public interface contract but declared in private scope, unless you call setAccessible method.
Lets look at one simple example.
We have widely used interface java.util.List and it describes contract that every class implementing this interface with have public method size(). So when in somewhere in the code we have an instance of a class implementing List interface we can easily call to size and get what we expect.
But everything changes when reflection comes. I thought that usually we can access every method or other class element with reflection in case if it is visible for static code from the same scope.
Suppose we have such decleration:
List<String> names = new ArrayList<>();
names.add("Anna");
names.add("Nick");
names.add("Pedro");
names.add("Michael");
So we can do statically this:int size = names.size(); System.out.println(size);And it will compile and run printing 4.
We can replace this code with reflection based one:
Method sizeMethod = names.getClass().getMethod("size");
int reflectedSize = (int) sizeMethod.invoke(names);
System.out.println(reflectedSize);
Result will be the same as previously.But there is another approach to create names.
List<String> names2 = Arrays.asList("Anna", "Nick", "Pedro", "Michael");
From the first view nothing changed. But if we try to get size with reflection again we will get this:java.lang.IllegalAccessException: Class reflect.PublicContractMethodAccessTest can not access a member of class java.util.Arrays$ArrayList with modifiers "public" at sun.reflect.Reflection.ensureMemberAccess(Reflection.java:98) at java.lang.reflect.AccessibleObject.slowCheckMemberAccess(AccessibleObject.java:285) at java.lang.reflect.AccessibleObject.checkAccess(AccessibleObject.java:277) at java.lang.reflect.Method.invoke(Method.java:480)Hey, we didn't change anything! Why does this happen?
The reason is that we access to class in Runtime with getClass() method, but it is private, so we cannot get it's methods:
private static class ArrayList<E> extends AbstractList<E> implements RandomAccess, java.io.Serializable
Public class in Runtime
To get away from this exception, we need to access class which is accessible for us in Runtime. The most common are List and Collection.This time our code will work:
Class<List> listClass = List.class;
Method sizeMethod = listClass.getMethod("size");
int reflectedSize = (int) sizeMethod.invoke(names2);
System.out.println(reflectedSize);
But if we know the type, why don't call method directly?Forcing Reflection to work
So we can make reflection work by forcing access to the class with setAccessible method:Method sizeMethod = names2.getClass().getMethod("size");
sizeMethod.setAccessible(true);
int reflectedSize = (int) sizeMethod.invoke(names2);
System.out.println(reflectedSize);
Note! Be careful with this. In case if security enabled on running JVM this method can lead to SecurityException.Conclusion
In case if you work with reflection be careful with such specifics in Java.Use public classes to access methods which will be accessible in Runtime or force reflection to get to method with setAccessible.
All the code is available at GitHub.