titledborder poner gui definicion borde java class reflection package-private

java - poner - Acceder a clases no visibles con reflexión



swing java (4)

Estoy tratando de obtener una instancia de una clase no visible, una clase privada de paquete AKA, utilizando la reflexión. Me preguntaba si había una forma de cambiar los modificadores para hacerlo público y luego acceder a él usando Class.forName . Cuando intento eso ahora me impide decir que no puedo hacerlo. Lamentablemente, no hay setAccesible método setAccesible de la clase Class .


Recientemente lanzamos una biblioteca que ayuda mucho a acceder a campos privados, métodos y clases internas a través de la reflexión: BoundBox

Para una clase como

public class Outer { private static class Inner { private int foo() {return 2;} } }

Proporciona una sintaxis como:

Outer outer = new Outer(); Object inner = BoundBoxOfOuter.boundBox_new_Inner(); new BoundBoxOfOuter.BoundBoxOfInner(inner).foo();

Lo único que tienes que hacer para crear la clase BoundBox es escribir @BoundBox(boundClass=Outer.class) y la clase BoundBoxOfOuter se generará instantáneamente.


Tuve la necesidad de copiar el valor del campo de la versión anterior del objeto si el valor es nulo en la versión más reciente. Teníamos estas 2 opciones.

Core Java:

for (Field f : object.getClass().getSuperclass().getDeclaredFields()) { f.setAccessible(true); System.out.println(f.getName()); if (f.get(object) == null){ f.set(object, f.get(oldObject)); } }

Usando Spring [org.springframework.beans.BeanWrapper]:

BeanWrapper bw = new BeanWrapperImpl(object); PropertyDescriptor[] data = bw.getPropertyDescriptors(); for (PropertyDescriptor propertyDescriptor : data) { System.out.println(propertyDescriptor.getName()); Object propertyValue = bw.getPropertyValue(propertyDescriptor.getName()); if(propertyValue == null ) bw.setPropertyValue( new PropertyValue(propertyDescriptor.getName(),"newValue")); }


Class.forName debería funcionar. Si la clase está dentro de una lista de jerarquía de paquetes en la propiedad de seguridad "package.access" , deberá realizar la operación con el privilegio apropiado (generalmente todos los permisos, o no tiene un administrador de seguridad).

Si está intentando usar Class.newInstance , no lo haga. Class.newInstance maneja las excepciones mal. En lugar de eso, obtenga un Constructor y llame a newInstance en eso. Es difícil ver con qué está teniendo problemas sin el rastro de excepción.

Como siempre, la mayoría pero no todos los usos de la reflexión son malas ideas.


clase anidada - clase definida dentro de otra clase (incluye clases estáticas y no estáticas)
clase interna - clase anidada no estática (instancia de clase interna necesita instancia de clase externa para existir)

clases no anidadas (nivel superior)

Según su pregunta, sabemos que el constructor al que desea acceder no es público. Para que su clase se vea así ( A clase está en un paquete diferente al nuestro)

package package1; public class A { A(){ System.out.println("this is non-public constructor"); } }

Para crear una instancia de esta clase, necesitamos llegar al constructor que queremos invocar y hacer que sea accesible. Cuando esté listo, podemos usar Constructor#newInstance(arguments) para crear una instancia.

Class<?> c = Class.forName("package1.A"); //full package name --------^^^^^^^^^^ //or simpler without Class.forName: //Class<package1.A> c = package1.A.class; //In our case we need to use Constructor<?> constructor = c.getDeclaredConstructor(); //note: getConstructor() can return only public constructors //so we needed to search for any Declared constructor //now we need to make this constructor accessible constructor.setAccessible(true);//ABRACADABRA! Object o = constructor.newInstance();

clases anidadas e internas

Si desea acceder a la clase anidada (estática y no estática) con Class.forName , debe usar la sintaxis:

Class<?> clazz = Class.forName("package1.Outer$Nested");

Outer$Nested dice que la clase Nested se declara dentro de la clase Outer . Las clases anidadas son muy similares a los métodos, tienen acceso a todos los miembros de su clase externa (incluidas las privadas).

Pero debemos recordar que la instancia de clase interna que existe requiere una instancia de su clase externa. Normalmente los creamos a través de:

Outer outer = new Outer(); Outer.Inner inner = outer.new Inner();

para que vea que cada instancia de la clase interna tiene información sobre su clase externa (la referencia a esa instancia externa se almacena en this$0 campo this$0 , más información: ¿Qué significa si una variable tiene el nombre "this $ 0" en IntelliJ IDEA mientras depurando Java? )

Por lo tanto, al crear una instancia de Inner clase Inner con Constructor#newInstance() , debe pasar como primer argumento la referencia a la instancia de la clase Outer (para simular outer.new Inner() comportamiento).

Aquí hay un ejemplo.

en el paquete1

package package1; public class Outer { class Inner{ Inner(){ System.out.println("non-public constructor of inner class"); } } }

en paquete2

package package2; import package1.Outer; import java.lang.reflect.Constructor; public class Test { public static void main(String[] args) throws Exception { Outer outerObject = new Outer(); Class<?> innerClazz = Class.forName("package1.Outer$Inner"); // constructor of inner class as first argument need instance of // Outer class, so we need to select such constructor Constructor<?> constructor = innerClazz.getDeclaredConstructor(Outer.class); //we need to make constructor accessible constructor.setAccessible(true); //and pass instance of Outer class as first argument Object o = constructor.newInstance(outerObject); System.out.println("we created object of class: "+o.getClass().getName()); } }

clases anidadas estáticas

Las instancias de clases anidadas estáticas no requieren instancia de clase externa (ya que son estáticas). Entonces, en su caso, no necesitamos buscar constructor con Outer.class como primer argumento. Y no necesitamos pasar instancia de clase externa como primer argumento. En otras palabras, el código será el mismo que para la clase no anidada (nivel superior) (tal vez, excepto el hecho de que necesitaría agregar la sintaxis $Nested en Class.forName() ).