2010-11-08 15 views
8

Como usted sabe, Spring puede inyectar valores a variables de instancias privadas, e Hibernate puede acceder a variables privadas de clases persistentes. Sin embargo, ¡ni siquiera puedo llamar a los métodos protegidos de una clase a través de la reflexión! ¿Cómo pueden Spring e Hibernate violar flagrantemente la seguridad de esa manera? Y más importante, ¿cómo lo hago? : D¿Cómo puede Spring/Hibernate acceder a miembros privados?

+0

Efectivamente un duplicado de http://stackoverflow.com/questions/3391256/how-java-jaxb-works – skaffman

Respuesta

8

Cuando se ejecuta sin un administrador de seguridad prohibitivo, puede obtener una instancia del método correspondiente o campo a través de la reflexión y llamar al setAccessible() en él.

Al usar el administrador de seguridad de Java, por supuesto puede deshabilitarlo escribiendo una política personalizada.

1

Hibernate puede acceder a miembros privados a través del mecanismo de configuración de acceso a nivel 'campo'. De la documentación, sección 5.1.11

"El atributo de acceso le permite controlar cómo Hibernate accede a la propiedad en tiempo de ejecución. De forma predeterminada, Hibernate llamará a la propiedad get/set pair. Si especifica access =" field ", Hibernate omitir el par get/set y acceder al campo directamente usando reflection ".

3

Puede establecer una variable privada de otro objeto a través de la reflexión. Aquí hay un ejemplo de cómo hacerlo. Considere el siguiente objeto con una variable privada:

public class MyBean { 
    private String message; 
} 

Normalmente el campomensaje no sería accesible desde el exterior myBean, sin embargo, SnoopyClass puede establecer y obtener su valor. Escribí dos métodos estáticos: setValue que se puede establecer un valor en un campo privado llamado fieldName de un objeto frijol y un método getValue que se puede obtener el valor de una variable privada denominada fieldName de un frijol Objeto.

El método principal solo demuestra su uso mediante la creación de un objeto de clase myBean, estableciendo el mensaje variable y recuperación de la misma. De hecho, he probado este código como una aplicación independiente y funciona.

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")); 
    } 

} 

La aplicación utiliza getDeclaredField método en la clase de objetos, ya que este método puede buscar todos los campos, incluso privadas. Por el contrario, getField solo puede acceder a miembros públicos. El siguiente paso es llamar al setAccessible en el campo para permitir su lectura y escritura. El último paso es simplemente usar los métodos get y set proporcionados por la clase java.lang.reflect.Field.

Este tipo de manipulación solo está permitida si el administrador de seguridad lo permite. Por defecto, Java no instala ningún administrador de seguridad, por lo que en un programa independiente que ejecute a través de su IDE o la línea de comandos, no tendrá ningún problema para utilizar esta técnica. También lo intenté, en una aplicación de primavera bajo Tomcat, y todavía está funcionando.

La aplicación principal, al menos para mí, es poder establecer variables privadas en mis pruebas unitarias, especialmente para Spring Beans, sin contaminar la interfaz con setters innecesarios.

Cuestiones relacionadas