Suite à la lecture de l’article de Chiral Software sur les annotations Seam @Factory et @Unwrap, j’ai pensé qu’il serait bon d’apporter quelques précisions sur le fontionnement de la bijection dans Seam à la lumière de mon expérience sur le sujet.
L’une des erreurs les plus répandues lorsque l’on utilise Seam est d’être trop confiant dans sa « magie ».
L’un des premiers pièges dans lequel vous pouvez tomber en commençant avec Seam concerne la surjection (traduction libre du concept d’outjecting).
Prenez ce code par exemple :
@Name("registerHdl")
@Scope(ScopeType.CONVERSATION)
public class RegisterHandler implements Serializable{
@Out
private Registrant registrant=new Registrant();
@Create
public void create()
{
}
}
...
@Entity
public class Registrant {
private Long id;
private String firstName;
private String lastName;
private String email;
private String origine;
(getters and setters skiped)
}
On définit un composant dans le scope conversation avec un champ privé contenant une entité surjectée avec le nom « registrant ».
Plus tard on voudra exploiter cette variable dans une vue :
pages.xml :
...
<page view-id="/register.xhtml">
<begin-conversation join="true" />
<navigation>
<rule if-outcome="ok">
<end-conversation />
<redirect view-id="/thanks.xhtml"></redirect>
</rule>
</navigation>
</page>
...
register.xhtml :
...
<span class="inputLabel">Your name : </span><br/>
<h:inputText id="Name" styleClass="inputShort" required="true"
value="#{registrant.lastName}"/>
...
Mais ça ne marche pas (une exception se déclenche lors de la soumission du formulaire). On a pourtant démarré une conversation dans le fichier pages.xml et fait appel à notre « registrant » surjecté dans le composant « registerHdl ».
Alors qu’est-ce qui cloche ?
Le problème vient du fait que le composant registerHdl n’est jamais créé et que le fait de solliciter la variable de contexte surjecté « registrant » n’entraîne pas la création du composant.
Pour déclencher cette création, on doit solliciter une méthode du composant. On pourrait mapper nos champ avec #{registerHdl.registrant} dans la vue après avoir défini des getter et setter sur registrant par exemple. Mais il y a mieux.
C’est ici que l’annotation @Factory entre en scène.
@Name("registerHdl")
@Scope(ScopeType.CONVERSATION)
public class RegisterHandler implements Serializable{
private Registrant registrant=new Registrant();
@Factory
public Registrant getRegistrant() {
return registrant;
}
public void setRegistrant(Registrant registrant) {
this.registrant = registrant;
}
@Create
public void create()
{
}
}
Nous avons supprimé l’annotation @Out et avons ajouté un getter avec l’annotation @Factory. Cette nouvelle configuration déclenche la création du composant registerHdl lorsque l’on utilise #{registrant…} dans une vue.
En résumé @Out surjecte un champ comme variable de contexte après la création du composant, alors que @Factory déclenche si nécessaire la création du composant pour sujecter la valeur retournée par une méthode de ce dernier. @Out n’est visible que dans le cycle de vie du composant alors que @Factory est visible dans toute l’application.
Mais ce n’est pas la seule différence entre @Factory et @Out comme nous le verrons dans la deuxième partie de cet article



