java reflection constructor new-operator instance

Java: nueva instancia de la clase que no tiene un constructor predeterminado



reflection new-operator (6)

Aquí hay una solución genérica que no requiere javassist u otro bytecode "manipulador". Aunque asume que los constructores no hacen nada más que simplemente asignar argumentos a los campos correspondientes, por lo que simplemente selecciona el primer constructor y crea una instancia con valores predeterminados (es decir, 0 para int, null para Object, etc.).

private <T> T instantiate(Class<T> cls, Map<String, ? extends Object> args) throws Exception { // Create instance of the given class final Constructor<T> constr = (Constructor<T>) cls.getConstructors()[0]; final List<Object> params = new ArrayList<Object>(); for (Class<?> pType : constr.getParameterTypes()) { params.add((pType.isPrimitive()) ? ClassUtils.primitiveToWrapper(pType).newInstance() : null); } final T instance = constr.newInstance(params.toArray()); // Set separate fields for (Map.Entry<String, ? extends Object> arg : args.entrySet()) { Field f = cls.getDeclaredField(arg.getKey()); f.setAccessible(true); f.set(instance, arg.getValue()); } return instance; }

PS funciona con Java 1.5+. La solución también supone que no hay un administrador de SecurityManager que pueda evitar la invocación de f.setAccessible(true) .

Estoy intentando construir un marco de prueba automático (basado en jUnit, pero eso no es importante) para la tarea de mis alumnos. Tendrán que crear constructores para algunas clases y también agregarles algunos métodos. Más tarde, con las funciones de prueba que proporciono, verificarán si funcionó bien.

Lo que quiero hacer es, por reflexión , crear una nueva instancia de alguna clase que quiera probar. El problema es que, a veces, no hay un constructor predeterminado . No me importa eso, quiero crear una instancia e inicializar las variables de instancia yo mismo . ¿Hay alguna forma de hacer esto? Lo siento si esto se ha preguntado antes, pero simplemente no he podido encontrar ninguna respuesta.

Gracias por adelantado.


Puede distribuir el siguiente código fuente con su tarea. Indique a los alumnos que lo incluyan en su código fuente. Su código no se compilará a menos que codifique una clase de Asignación con la firma adecuada. El compilador hace la verificación de la firma por usted.

Entonces su programa de prueba no necesita usar reflexión. Simplemente crea una instancia de AssignmentFactory y llama al método make con los argumentos adecuados.

Si usa esta idea, su nuevo reto será que algunos estudiantes modifiquen AssignmentFactory para que se ajuste a su clase de Asignación (rompiendo su programa de prueba).

package assignment ; public class AssignmentFactory { public AssignmentFactory ( ) { super ( ) ; } public AssignmentFactory make ( .... parameters ) { return new Assignment ( .... arguments ) ; } }



Si no ha utilizado marcos de burla (como ezmock), le recomiendo que pruebe.

Puedo estar equivocado y eso puede que no te ayude en absoluto, pero por lo que pude deducir de tu publicación, parece posible que la burla sea exactamente lo que estás buscando (aunque reconozco que no tiene nada que ver con lo que preguntaste para.

Editar: en respuesta al comentario.

No, los marcos de burla modernos te permiten crear una instancia "Falsa" de cualquier clase desde "nada" y pasarla como si fuera una instancia de la clase. No necesita una interfaz, puede ser cualquier clase. También los métodos se pueden programar para devolver una secuencia de valores de un retorno siempre simple "7" a "Cuando se llama con un arg = 7, devuelve 5 la primera llamada, 6 el segundo y 7 el tercero".

Por lo general, se utiliza junto con marcos de prueba para dar una clase de referencia para pasar a la clase que está probando.

Puede que esto no sea exactamente lo que estás buscando, pero mencionaste las pruebas unitarias y las variables de inicialización manual, por lo que parecía que esto es algo que eventualmente podría ser útil.


Utilicé el siguiente código para crear una lista de objetos genéricos de cualquier tipo de nombre de clase que se haya pasado. Utiliza todos los métodos establecidos dentro de la clase para establecer todos los valores pasados ​​a través del conjunto de resultados. Estoy publicando esto en caso de que a alguien también le interese.

protected List<Object> FillObject(ResultSet rs, String className) { List<Object> dList = new ArrayList<Object>(); try { ClassLoader classLoader = GenericModel.class.getClassLoader(); while (rs.next()) { Class reflectionClass = classLoader.loadClass("models." + className); Object objectClass = reflectionClass.newInstance(); Method[] methods = reflectionClass.getMethods(); for(Method method: methods) { if (method.getName().indexOf("set") > -1) { Class[] parameterTypes = method.getParameterTypes(); for(Class pT: parameterTypes) { Method setMethod = reflectionClass.getMethod(method.getName(), pT); switch(pT.getName()) { case "int": int intValue = rs.getInt(method.getName().replace("set", "")); setMethod.invoke(objectClass, intValue); break; case "java.util.Date": Date dateValue = rs.getDate(method.getName().replace("set", "")); setMethod.invoke(objectClass, dateValue); break; case "boolean": boolean boolValue = rs.getBoolean(method.getName().replace("set", "")); setMethod.invoke(objectClass, boolValue); break; default: String stringValue = rs.getString(method.getName().replace("set", "")); setMethod.invoke(objectClass, stringValue); break; } } } } dList.add(objectClass); } } catch (Exception e) { this.setConnectionMessage("ERROR: reflection class loading: " + e.getMessage()); } return dList; }


Llame Class.getConstructor() y luego Constructor.newInstance() pasando los argumentos apropiados. Código de muestra:

import java.lang.reflect.*; public class Test { public Test(int x) { System.out.println("Constuctor called! x = " + x); } // Don''t just declare "throws Exception" in real code! public static void main(String[] args) throws Exception { Class<Test> clazz = Test.class; Constructor<Test> ctor = clazz.getConstructor(int.class); Test instance = ctor.newInstance(5); } }