Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How Can Spring/Hibernate Access Private Members?

As you know, Spring can inject values to private instance variables, and Hibernate can access private variables of persistent classes. However, I can't even call protected methods of a class through reflection! How can Spring and Hibernate blatantly breach security like that? And more importantly, how do I do it? :D

like image 376
Tom Tucker Avatar asked Nov 08 '10 19:11

Tom Tucker


People also ask

How does Hibernate access private fields?

Basically Hibernate uses Reflection which can gain access to private instance vairables as well as private methods.

Can private members be accessed from subclass?

A subclass does not inherit the private members of its parent class. However, if the superclass has public or protected methods for accessing its private fields, these can also be used by the subclass. A nested class has access to all the private members of its enclosing class—both fields and methods.

What are the two ways of accessing Hibernate by using spring?

There are two approaches to Spring's Hibernate integration: Inversion of Control with a HibernateTemplate and Callback. Extending HibernateDaoSupport and Applying an AOP Interceptor.

Can a private member be accessed by a member of the same class?

The private modifier specifies that the member can only be accessed in its own class. The protected modifier specifies that the member can only be accessed within its own package (as with package-private) and, in addition, by a subclass of its class in another package.


2 Answers

When running without prohibitive security manager, you can obtain instance of corresponding method or field trough reflection and call setAccessible() on it.

Using Java security manager you can of course disable that by writing a custom policy.

like image 99
Eugene Kuleshov Avatar answered Oct 13 '22 18:10

Eugene Kuleshov


You can set private a variable of another object through reflection. Here is an example on how to do it. Consider the following object with a private variable:

public class MyBean {
    private String message;
}

Normally the message field wouldn't be accessible from outside MyBean, however, SnoopyClass can set and get its value. I wrote two static methods: setValue which can set a value into a private field called fieldName of an Object bean and a getValue method which can get the value of a private variable called fieldName from an Object bean.

The main method just demonstrates its use by creating an Object of MyBean class, setting the message variable and retrieving it. I've actually tested this code as a standalone application and it works.

import java.lang.reflect.Field;

public class SnoopyClass {

    private static void setValue(Object bean, String fieldName, Object value)
            throws IllegalArgumentException, IllegalAccessException, 
            SecurityException, NoSuchFieldException {
        Field privateVar = bean.getClass().getDeclaredField(fieldName);
        privateVar.setAccessible(true);
        privateVar.set(bean, value);
    }

    private static Object getValue(Object bean, String fieldName) 
            throws IllegalArgumentException, IllegalAccessException,
            SecurityException, NoSuchFieldException {
        Field privateVar = bean.getClass().getDeclaredField(fieldName);
        privateVar.setAccessible(true);
        return privateVar.get(bean);
    }

    public static void main(String[] argv) 
            throws IllegalArgumentException, SecurityException,
            IllegalAccessException, NoSuchFieldException {
         MyBean instance = new MyBean();
         setValue(instance, "message", "Shht! Don't tell anyone!");
         System.out.println("The message is '" + getValue(instance, "message"));
    }

}

The implementation uses getDeclaredField method on the class of the Object, because this method can look for all fields, even private. In contrast, getField can only access public members. The next step is calling setAccessible on the field to allow reading and writing it. The last step, is simply use the get and set methods provided by the java.lang.reflect.Field class.

This kind of manipulation is allowed only if the security manager allows that. By default Java doesn't install any security manager, so in a standalone program that you launch through your IDE or the command line, you won't have any problems to use this technique. I've also tried, in a Spring Application under Tomcat, and it's still working.

The primary application, at least for me, is being able to set private variables in my unit tests, especially for Spring Beans, without polluting the interface with unneeded setters.

like image 27
stivlo Avatar answered Oct 13 '22 18:10

stivlo