Reputation: 117665
I know that we can access private constructor via reflection as @Sanjay T. Sharma mentioned in his answer of my question: Does “instanceof Void” always return false?
you can access private everything with reflection - methods, constructors, data members, everything.
Upvotes: 27
Views: 68046
Reputation: 7849
Example as below:
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
class Test
{
private int a = 5; // Private data member
private void call(int n) // Private method
{
System.out.println("in call() n: " + n);
}
}
public class Sample
{
public static void main(String args[]) throws ClassNotFoundException, NoSuchMethodException, SecurityException, InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException, NoSuchFieldException
{
Class c = Class.forName("Test");
Object obj = c.newInstance();
//---- Accessing a private method
Method m=c.getDeclaredMethod("call",new Class[]{int.class});
m.setAccessible(true);
m.invoke(obj,7);
//---- Accessing a private data member
Field d = c.getDeclaredField("a");
d.setAccessible(true);
System.out.println(d.getInt(obj));
}
}
Upvotes: 1
Reputation: 41
To answer your third question:
Answer:
Yes, you can restrict the access (you can throw an exception when someone tries to access your private constructor/method/data)
Refer to the below example:
******JavaSingleton Class******
package server;
public class JavaSingleton {
private static final JavaSingleton INSTANCE = new JavaSingleton();
private JavaSingleton() {
if (INSTANCE != null) {
throw new IllegalStateException("Inside JavaSingleton(): JavaSingleton " +
"instance already created.");
}
System.out.println("Inside JavaSingleton(): Singleton instance is being created.");
}
public static final JavaSingleton getInstance() {
return INSTANCE;
}
}
***Listing 2: JavaSingleton client***
import server.JavaSingleton;
import java.lang.reflect.*;
public class TestSingleton {
public static void main(String[] args) throws ReflectiveOperationException {
System.out.println("Inside main(): Getting the singleton instance using getInstance()...");
JavaSingleton s = JavaSingleton.getInstance();
System.out.println("Inside main(): Trying to use reflection to get another instance...");
Class<JavaSingleton> clazz = JavaSingleton.class;
Constructor<JavaSingleton> cons = clazz.getDeclaredConstructor();
cons.setAccessible(true);
JavaSingleton s2 = cons.newInstance();
}
}
Output:
C:\singleton>java TestSingleton
Inside main(): Getting the singleton instance using getInstance()...
Inside JavaSingleton(): Singleton instance is being created.
Inside main(): Trying to use reflection to get another instance...
Exception in thread "main" java.lang.reflect.InvocationTargetException
at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
at sun.reflect.NativeConstructorAccessorImpl.newInstance(Unknown Source)
at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(Unknown Source)
at java.lang.reflect.Constructor.newInstance(Unknown Source)
at TestSingleton.main(TestSingleton.java:13)
Caused by: java.lang.IllegalStateException: Inside JavaSingleton(): JavaSingleton instance already created.
at server.JavaSingleton.<init>(JavaSingleton.java:7)
... 5 more
This example was for a singleton class (checking in the constructor), but you can still implement this logic for the private methods that you want to prevent access from other classes.
In this case you will also declare a static instance and check the value of it in the private method and throw an error in case of any unwanted value.
Upvotes: 0
Reputation: 124275
1) How can I access the private methods and the private data members?
You can do it with a little help of the setAccessible(true)
method:
class Dummy{
private void foo(){
System.out.println("hello foo()");
}
private int i = 10;
}
class Test{
public static void main(String[] args) throws Exception {
Dummy d = new Dummy();
/*--- [INVOKING PRIVATE METHOD] ---*/
Method m = Dummy.class.getDeclaredMethod("foo");
//m.invoke(d); // Exception java.lang.IllegalAccessException
m.setAccessible(true);//Abracadabra
m.invoke(d); // Now it's OK
/*--- [GETING VALUE FROM PRIVATE FIELD] ---*/
Field f = Dummy.class.getDeclaredField("i");
//System.out.println(f.get(d)); // Not accessible now
f.setAccessible(true); // Abracadabra
System.out.println(f.get(d)); // Now it's OK
/*--- [SETTING VALUE OF PRIVATE FIELD] ---*/
Field f2 = Dummy.class.getDeclaredField("i");
//f2.set(d,20); // Not accessible now
f2.setAccessible(true); // Abracadabra
f2.set(d, 20); // Now it's OK
System.out.println(f2.get(d));
}
}
2) Is it possible to access a local variable via reflection?
No. Local variables cannot be accessed outside of a block in which they were created (someone could say that you can assign such a variable to a field like field = localVariable;
and later access such a field via reflection, but this way we will be accessing the value, not the variable).
3) Is there any way to prevent anyone from accessing private constructors, methods, and data members?
I think for constructors
or methods
you could use stacktrace to check if it was invoked by Reflection
.
For fields I can't find a solution to prevent accessing them via reflection.
class Dummy {
private void safeMethod() {
StackTraceElement[] st = new Exception().getStackTrace();
// If a method was invoked by reflection, the stack trace would be similar
// to something like this:
/*
java.lang.Exception
at package1.b.Dummy.safeMethod(SomeClass.java:38)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
-> at java.lang.reflect.Method.invoke(Method.java:601)
at package1.b.Test.main(SomeClass.java:65)
*/
//5th line marked by "->" is interesting one so I will try to use that info
if (st.length > 5 &&
st[4].getClassName().equals("java.lang.reflect.Method"))
throw new RuntimeException("safeMethod() is accessible only by Dummy object");
// Now normal code of method
System.out.println("code of safe method");
}
// I will check if it is possible to normally use that method inside this class
public void trySafeMethod(){
safeMethod();
}
Dummy() {
safeMethod();
}
}
class Dummy1 extends Dummy {}
class Test {
public static void main(String[] args) throws Exception {
Dummy1 d1 = new Dummy1(); // safeMethod can be invoked inside a superclass constructor
d1.trySafeMethod(); // safeMethod can be invoked inside other Dummy class methods
System.out.println("-------------------");
// Let's check if it is possible to invoke it via reflection
Method m2 = Dummy.class.getDeclaredMethod("safeMethod");
// m.invoke(d);//exception java.lang.IllegalAccessException
m2.setAccessible(true);
m2.invoke(d1);
}
}
Output from Test
main method:
code of safe method
code of safe method
-------------------
Exception in thread "main" java.lang.reflect.InvocationTargetException
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:601)
at package1.b.Test.main(MyClass2.java:87)
Caused by: java.lang.RuntimeException: method safeMethod() is accessible only by Dummy object
at package1.b.Dummy.safeMethod(MyClass2.java:54)
... 5 more
Upvotes: 76
Reputation: 11
Area s=(Area)c.newInstance();
s.setRadius(10);
System.out.println("Area: "+s.calculateArea(4));
Method m[]=c.getDeclaredMethods();
Constructor c1[]=c.getConstructors();
for(int i=0;i<m.length;i++)
System.out.println(""+m[i]);
for(int i=0;i<c1.length;i++)
System.out.println(""+c1[i]);
Upvotes: 1
Reputation: 10112
To access a private field you will need to call the
Class.getDeclaredField(String name)
or enter code here
method.
Check this simple code:
public class PrivateObject {
private String privateString = null;
public PrivateObject(String privateString) {
this.privateString = privateString;
}
}
PrivateObject privateObject = new PrivateObject("The Private Value");
Field privateStringField = PrivateObject.class.
getDeclaredField("privateString");
privateStringField.setAccessible(true);
String fieldValue = (String) privateStringField.get(privateObject);
System.out.println("fieldValue = " + fieldValue
To access a private method you will need to call the Class.getDeclaredMethod(String name, Class[] parameterTypes) or Class.getDeclaredMethods() method.
Check this simple code:
public class PrivateObject {
private String privateString = null;
public PrivateObject(String privateString) {
this.privateString = privateString;
}
private String getPrivateString(){
return this.privateString;
}
}
PrivateObject privateObject = new PrivateObject("The Private Value");
Method privateStringMethod = PrivateObject.class.
getDeclaredMethod("getPrivateString", null);
privateStringMethod.setAccessible(true);
String returnValue = (String)
privateStringMethod.invoke(privateObject, null);
System.out.println("returnValue = " + returnValue);
Read detail at http://tutorials.jenkov.com/java-reflection/private-fields-and-methods.html
Upvotes: 3
Reputation: 692161
Upvotes: 9