2010-01-07 5 views
13

Je vois beaucoup d'exemples Java en utilisant l'injection de dépendance avec des champs privés sans setter public comme ceci:Injecter dans un domaine privé, paquet ou public ou fournir un setter?

public SomeClass { 
    @Inject 
    private SomeResource resource; 
} 

Mais c'est une mauvaise idée quand l'injection doit être effectuée manuellement par exemple dans les tests unitaires.

Il existe plusieurs possibilités pour résoudre ce:

  • ajouter un setter public: setSomeResource(SomeResource r)
  • rendre le champ public
  • faire le paquet de champ protégé

Je voudrais évitez le setter, puisque rien ne s'y passe vraiment. Donc je préfère public ou paquet protégé. Que recommandez-vous?

+0

http://stackoverflow.com/q/20270391/975169 injection automatique avec Mockito – Sllouyssgort

Répondre

7

Je préfère le poseur

  • il est plus facile à déboguer (mettre un point d'arrêt dans un setter plutôt que sur l'accès champ/modification)
  • plus facile de se connecter
  • plus facile d'ajouter une validation (bien que ce n'est pas toujours le meilleur endroit)
  • plus facile à soutenir bidirectionnelle maintainance (bien que contenant du CIO peut prendre en charge que)
  • tout autre objet « AOP manuel »

Mais c'est juste mon avis

+0

Ce sont de bons arguments. Je vais utiliser setter ou injection de constructeur (disponible depuis EJB 3.1) maintenant. – deamon

+4

Rendre l'objet mutable qui pourrait être un problème – willcodejavaforfood

4

Je recommande d'utiliser setter. En this question sont les avantages de l'utilisation de getters et setters.

12

Une façon d'éviter la création d'un setter pour le champ est par injection constructeur. Cela vous permet même de déclarer le champ comme final.

Il va comme ceci:

public class SomeClass { 
    private final SomeResource resource; 

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

Ajout setters n'est pas une solution optimale, puisque vous ajoutez le code de production qui ne sont pas nécessaires.

Une alternative est d'utiliser la classe ReflectionTestUtils de printemps pour injecter vos dépendances de test en utilisant la réflexion, voir http://static.springsource.org/spring/docs/2.5.x/api/org/springframework/test/util/ReflectionTestUtils.html

EDIT (2017): Cependant, la réflexion est une solution encore pire que d'ajouter setters. La cause de ce bordel est le fait que Spring permet d'injecter des valeurs sans setters ou constructeurs. Ma position actuelle est de s'en tenir à l'un ou l'autre de ceux-ci et d'éviter d'utiliser des pratiques d'injection de magie noire.

3

Avec l'aide de la réponse à ma (par rapport à celui-ci) question:

How do app servers inject into private fields?

Je codé cet exemple simple sur la façon d'injecter sans setters.Peut-être aide

//...................................................... 
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 

Run sortie: Avec injection à base de champ

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

Merci pour la suggestion. Vous pouvez utiliser @Inject de JSR 330. – deamon

0

, vous rencontrez le problème que vous décrivez avec des tests. Avec une injection basée sur un setter, une instance d'une classe peut être créée dans un état incomplet lors de l'exécution de tests si vous oubliez de définir certaines dépendances. Je pratique l'injection de constructeurs plus récemment, car elle vous oblige à définir toutes les dépendances chaque fois que vous créez une instance d'une classe pendant les tests. La réponse ci-dessus par Andre Rodrigues explique comment cela serait accompli.

0

solutions possibles à cela:

  • Utiliser un framework de test CDI-aware comme JGlue CDI-Unit. De cette façon, vous n'avez pas besoin de setter. Vous ne définissez la dépendance que dans vos tests, en utilisant généralement un objet Mockito. À mon humble avis, c'est la meilleure solution, car il ne vous oblige pas à faire quoi que ce soit d'autre pour les tests. Injecter dans le constructeur ou l'accesseur. C'est vrai, vous pouvez injecter dans les setters! More details here.

  • Utilisez un setter protégé. Simple et fonctionne dans tous les cas. Comme il est protégé, vous pouvez y accéder à partir de votre classe de test (qui doit avoir la même définition de paquetage que votre classe testée), et aucun autre paquet ne peut y accéder.

  • Utilisez un getter et remplacez-le lors des tests. Dans votre classe de test, créez une nouvelle classe interne qui étend la classe testée et remplace le getter. Ceci, cependant, a un gros inconvénient: votre classe de test doit utiliser le getter en interne au lieu du champ. Beaucoup de boilerplate potentiellement mis sur écoute ...

Questions connexes