2010-01-07 12 views
13

que ver muchos ejemplos de Java utilizando la inyección de dependencia con los campos privados sin un regulador público así:¿Inyectar en un campo privado, de paquete o público o proporcionar un setter?

public SomeClass { 
    @Inject 
    private SomeResource resource; 
} 

Pero eso es una mala idea cuando la inyección se debe realizar de forma manual, por ejemplo, en las pruebas unitarias.

Hay varias posibilidades para resolver esto:

  • añadir un regulador público: setSomeResource(SomeResource r)
  • hacer que el campo público
  • hacer el paquete de campo protegida

me gustaría evitar al colocador, ya que en realidad no pasa nada. Entonces preferiría el público o el paquete protegido. ¿Que recomiendas?

+0

http://stackoverflow.com/q/20270391/975169 inyección automática con Mockito – Sllouyssgort

Respuesta

7

Yo prefiero el colocador

  • es más fácil de depurar (poner un punto de interrupción en una incubadora en lugar de en el campo de acceso/modificación)
  • más fácil que entrar
  • más fácil de añadir un poco de validación (aunque esto no es siempre el mejor lugar)
  • más fácil de soportar mantenimiento bidireccional (aunque contenedor COI puede hacerse cargo de eso)
  • cualquier otro "manual de AOP" propósito

Pero eso es sólo mi opinión

+0

Éstos son buenos argumentos. Usaré la inyección setter o constructor (disponible desde EJB 3.1) ahora. – deamon

+4

Haría el objeto mutable que podría ser un problema – willcodejavaforfood

4

Recomiendo usar setter. En this question son los beneficios de usar getters y setters.

12

Una forma de evitar la creación de una incubadora para el campo es el uso de la inyección de constructor. Esto incluso le permite declarar el campo como final.

dice así:

public class SomeClass { 
    private final SomeResource resource; 

    @Inject 
    public SomeClass(SomeResource resource) { 
     this.resource = resource; 
    } 
} 
7

Adición set no es una solución óptima, ya que va a agregar el código de producción que no es necesario.

Una alternativa es utilizar la clase ReflectionTestUtils de primavera para inyectar sus dependencias de prueba utilizando la reflexión, ver http://static.springsource.org/spring/docs/2.5.x/api/org/springframework/test/util/ReflectionTestUtils.html

EDITAR (2017): Sin embargo, la reflexión es una solución aún peor que la adición de los emisores. La causa de este lío es el hecho de que Spring permite inyectar valores sin setters o constructores. Mi postura actual es seguir usando cualquiera de ellos y evitar el uso de prácticas de inyección de magia negra.

3

Con la ayuda de la respuesta a mi (relacionado con éste) pregunta:

How do app servers inject into private fields?

codifiqué este sencillo ejemplo de cómo inyectar sin definidores. Tal vez esto sirva

//...................................................... 
import java.lang.annotation.*; 
import java.lang.reflect.*; 

//...................................................... 
@Target(value = {ElementType.FIELD}) 
@Retention(RetentionPolicy.RUNTIME) 
@interface Inject { 
} 

//...................................................... 
class MyClass { 

    @Inject 
    private int theValue = 0; 

    public int getTheValue() { 
     return theValue; 
    } 
} // class 

//...................................................... 
public class Example { 

    //...................................................... 
    private static void doTheInjection(MyClass u, int value) throws IllegalAccessException { 

     Field[] camps = u.getClass().getDeclaredFields(); 

     System.out.println("------- fields : --------"); 
     for (Field f : camps) { 
      System.out.println(" -> " + f.toString()); 
      Annotation an = f.getAnnotation(Inject.class); 
      if (an != null) { 
       System.out.println("  found annotation: " + an.toString()); 
       System.out.println("  injecting !"); 
       f.setAccessible(true); 
       f.set(u, value); 
       f.setAccessible(false); 
      } 
     } 

    } //() 

    //...................................................... 
    public static void main(String[] args) throws Exception { 

     MyClass u = new MyClass(); 

     doTheInjection(u, 23); 

     System.out.println(u.getTheValue()); 

    } // main() 
} // class 

salida Run:

------- fields : -------- 
-> private int MyClass.theValue 
     found annotation: @Inject() 
     injecting ! 
23 
+0

Gracias por la sugerencia. Puede usar @Inject de JSR 330. – deamon

0

Con la inyección a base de campo, se encuentra con el problema que describes con las pruebas. También con inyección basada en setter, una instancia de una clase puede crearse en un estado incompleto al ejecutar pruebas si olvida establecer algunas de las dependencias. He estado practicando la inyección de constructor más recientemente debido a que te obliga a configurar todas las dependencias cada vez que creas una instancia de una clase durante la prueba. La respuesta anterior por Andre Rodrigues explica cómo se lograría esto.

0

soluciones posibles a este:

  • Utilice un marco de pruebas CDI-conscientes como JGlue CDI-Unit. De esta manera no necesitas setter. Solo defines la dependencia dentro de tus pruebas, usualmente usando un objeto falso de Mockito. En mi humilde opinión, esta es la mejor solución, ya que no requiere que hagas nada extra para probar.

  • Inyectar en Constructor o setter. Así es, ¡puedes inyectar en setters! More details here.

  • Use un setter protegido. Simple y funciona en todos los casos. Como está protegido, puede acceder a él desde su clase de prueba (que debe tener la misma definición de paquete que su clase probada), y ningún otro paquete puede acceder a él.

  • Utilice un captador y anule el mismo cuando lo pruebe. En su clase de prueba, cree una nueva clase interna que amplíe la clase probada y anule el getter. Esto, sin embargo, tiene una gran desventaja: su clase de prueba tiene que usar el getter internamente en lugar del campo. Las porciones de texto modelo potencialmente pinchado ...

Cuestiones relacionadas