Converter générique et sécurisé
Bonjour,
voici maintenant 4 ans que je "joue" avec JSF et avant hier j'ai eu un idée qui me parait vraiment étrange de ne pas l'avoir eu avant, ni même vue ailleurs sur le net dans divers forums (et en particulier sur celui-ci)
j'ai toujours un peu trouvé fastidieux de faire un converter pour chacune de mes classes métier afin d'avoir un "getAsString" pour que JSF en fasse son affaire, et un "getAsObject" pour que je retrouve mes billes côté JAVA (instances).
Et donc j'ai écrit le converter suivant qui me simplifie la vie (très largement) :
Code:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| @ManagedBean
@ViewScoped
public class GenericSecuredConverter implements Converter, Serializable {
private Map <UUID, Object> temporaryStore = new HashMap <UUID, Object> ();
@Override
public Object getAsObject(FacesContext context, UIComponent component, String value) {
return temporaryStore.get(UUID.fromString(value));
}
@Override
public String getAsString(FacesContext context, UIComponent component, Object value) {
UUID id = UUID.randomUUID();
temporaryStore.put(id, value);
return id.toString();
}
} |
L'idée de ce Converter est d'associer temporairement, le temps de la vue (D'où le @ViewScoped), une Map de UUID et d'instance d'objet.
Ensuite pour utiliser ce genre de converter, j'utilise l'attribut "converter" et une EL, sur mon composant JSF :
Code:
1 2 3 4
| <h:selectOneMenu value="#{userBean.rank}" converter="#{genericSecuredConverter}">
<f:selectItem itemDisabled="true" itemLabel="Select a rank ..." />
<f:selectItems value="#{rankFacade.rankList}" var="localRank" itemLabel="#{localRank.fullText}" />
</h:selectOneMenu> |
Ca marche parfaitement bien. En plus côté "HTML", j'ai donc des UUID sous forme de String qui sont dans la page. Ces UUID, qui n'existent que le temps de la vue, ont une vocation unique ce qui permet de sécuriser l'application (d'où le nom d'oiseau à mon converter : "GenericSecuredConverter" :oops:)
Ca marche tellement bien que je me demande s'il n'y a pas un "loup" derrière tout ça. J'ai confronté mon "Converter" à d'autres développeurs, et eux aussi trouvent ça très bien et ne voient aucun problème ... ce qui me parait d'autant plus étrange.
Je suis ouvert à vos critiques (à part sur les UUID qui peuvent entrer en conflit, je ne sais plus quelle est la probabilité, mais elle est totalement négligeable)
PS : désolé si y'a pas la JavaDoc dans mon extrait de code, trop pressé d'avoir vos commentaires ... :aie:
Je n'arrive pas à le faire fonctionner
Bonjour,
Merci pour le partage de ce composant qui m'a l'air vraiment utile et bien fait.
Cependant, je n'arrive pas à le faire fonctionner correctement.
En mettant des Sysout un peu partout je vois que mes objets transitent bien dans le converter et qu'ils sont bien retrouvés au retour.
Cependant l'objet cible n'est pas sétté. sa valeur ne change pas. Comme si mon selectOneRadio ne sétté pas mon objet cible avec l'objet récupéré du converter.
voici mon code JSF :
Code:
1 2 3 4 5 6 7
|
<h:selectOneRadio id="situationPro" value="#{CandidatService.situationPro}" layout="pageDirection" converter="#{entityConverter}">
<f:selectItems value="#{SituationProService.findAll()}" />
<f:ajax execute="@this" render="test"/>
</h:selectOneRadio>
<h:outputText id="test" value="#{CandidatService.situationPro.libelleSituationPro}" /> |
Et ton converteur, auquel j'ai modifié les annotations pour que spring et jsf retrouvent leurs billes.
Code:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
|
@Component("entityConverter")
@FacesConverter("entityConverter")
public class EntityConverter implements Converter, Serializable {
private Map <UUID, Object> temporaryStore = new HashMap <UUID, Object> ();
@Override
public Object getAsObject(FacesContext context, UIComponent component, String value) {
System.out.println("ici "+temporaryStore.get(UUID.fromString(value)));
return temporaryStore.get(UUID.fromString(value));
}
@Override
public String getAsString(FacesContext context, UIComponent component, Object value) {
System.out.println("la "+(value instanceof SituationPro));
UUID id = UUID.randomUUID();
temporaryStore.put(id, value);
return id.toString();
}
} |
Dans le getAsString j'ai bien des "true", donc ce sont bien les objets entiers qui transitent et non un simple string.
et au retour dans le getAsObject, il retrouve bien un object (de type SituationPro).
Seulement, mon objet '#{CandidatService.situationPro}' n'est pas sétté au moment de la requête ajax ...
Code:
1 2 3 4 5 6 7 8 9
|
@Component("CandidatService")
@Scope("session")
public class CandidatService implements ICandidatService{
// + getter et setter
SituationPro situationPro = new SituationPro();
... |
Merci d'avance pour votre réponse.
Bonne journée.