web-dev-qa-db-fra.com

Initialisation de la liste dans un bean géré JSF

J'ai une question sur l'initialisation de la liste dans le POJO car il suit le code suivant:

public class Person {

 //other fields...
 private List<String> friends=new ArrayList<>();

     public List<String> getFriends() {
        return friends;
     }
     public void setFriends(List<String> friends) {
        this.friends = friends;
    }

}

OU est-ce mieux comme ça et avoir une initalisation dans une autre classe (comme par exemple Bean (JSF))

public class Person {

 //other fields...
 private List<String> friends;

     public List<String> getFriends() {
        return friends;
     }
     public void setFriends(List<String> friends) {
        this.friends = friends;
    }

}

Donc, ma question est quelle approche est la meilleure?

12
Mitja Rogl

Si c'est un bean géré comme vous le dites, vous devriez le faire dans une méthode annotée avec @PostConstruct

public class Person {
    private List<String> friends;
    @PostConstruct
    public void init(){
         friends = new ArrayList<String>();
    }

    //getter and setter...
}
  1. Toute pratique d'initialisation dans le getter et le setter est généralement mal vue dans le contexte de JSF. Voir Pourquoi JSF appelle les Getters plusieurs fois

  2. De plus, pour l'API de @PostConstruct , le contrat spécifie des fonctionnalités de sécurité et garantit que si une exception est renvoyée dans une méthode annotée en tant que telle, le bean ne doit pas être mis en service. Il n'y a pas de telles garanties sur un constructeur ordinaire.

  3. Dans un haricot géré, l'injection a lieu immédiatement après la construction. Cela signifie que les opérations que vous effectuez dans le constructeur ne peuvent dépendre d'aucune ressource injectée (via @ManagedProperty). Alors que dans une méthode @PostConstruct, vous aurez accès à toutes les ressources déclarées sur le bean géré

EDIT: Il est important de noter que il ne peut en exister qu'un seul@PostConstruct pour tout @ManagedBean, toutes les initialisations importantes doivent donc y être effectuées. 

Il est également intéressant de noter que, si la méthode @PostConstruct est l’endroit idéal pour initialiser une variable de bean de support/List, il existe des implications en ce qui concerne la portée du bean géré.

  1. @RequestScoped: Dans un bean géré avec cette annotation, la méthode sera appelée par soumission de la vue JSF concernée. Un bean @RequestScoped est détruit et recréé à chaque demande. Cela a pour conséquence qu'en fonction de votre configuration, la liste initialisée dans le @PostConstruct peut être réinitialisée à des valeurs vides ou par défaut lors de chaque demande. Dans certaines circonstances, des erreurs de conversion peuvent survenir à la suite de la réinitialisation de la demande de liste mi-JSF.

  2. @ViewScoped: dans un bean géré avec cette annotation, la méthode @PostConstruct sera exécutée une fois, si et seulement si vous traitez avec la même instance du bean @ViewScoped. Si le bean en vue est détruit et recréé, la méthode @PostConstruct sera exécutée à nouveau.

  3. @SessionScoped: un bean avec cette annotation est créé une fois et reste actif jusqu'à la fin de la session HTTP de l'utilisateur. Dans ce scénario, la méthode @PostConstruct est garantie d'être exécutée une et une seule fois jusqu'à la destruction du bean

Voir également

24
kolossus

Je suggérerais ceci:

public class Person {
     //other fields...
     private List<String> friends=new ArrayList<>();

     // returns a copy to protect original list
     public List<String> getFriends() {
        Collections.unmodifiableList(new ArrayList<>(friends));
     }
     public void addFriend(String> friend) {
        this.friends.add(friend);
     }
     public void addFriends(List<String> friends) {
        this.friends.addAll(friends);
     }
}
4
anubhava

À mon avis, il serait préférable de gérer cela dans les constructeurs. Si un constructeur par défaut est utilisé, initialisez la liste dans le constructeur.

public Person() {
    friends = new ArrayList<>();
}

Si un constructeur acceptant des paramètres est utilisé, laissez la classe appelante passer dans une liste.

public Person(ArrayList<> friends) {
    this.friends = friends;//friends
}
3
Haz

Ma suggestion, ajouter un chèque nul dans le getter:

public class Person {
  //other fields...
  private List<String> friends;

  public List<String> getFriends() {
     if (this.friends == null) friends = new ArrayList<String>();
     return friends;
  }
}

Mais notez aussi que j'ai omis le passeur. Au lieu de cela, dans n'importe quel code client, appelez comme ceci:

personInstance.getFriends().add("Some Item");

Ou si vous avez une liste complète à ajouter:

personInstance.getFriends().addAll(someStringCollection);
2
cobaltduck

Ça dépend. Habituellement, la première solution est préférable, car vous souhaiterez peut-être ajouter quelque chose à la collection ultérieurement. Si vous ne savez pas si votre collection a été initialisée ou non, vous devez la vérifier à chaque fois.

1
Maxim Kolesnikov