Accueil > Intranet Michel Buffa > Cours composants distribués pour l'entreprise / EJB 2012-2013 > FAQ JSF2 : solutions aux erreurs les plus courantes

FAQ JSF2 : solutions aux erreurs les plus courantes

De $1

Q: Quand je crée un JSF Managed Bean il y a toujours @ManagedBean au lieu de @Named comme dans les TPs, pourquoi ?

Il s'agit d'un bug de Netbeans, c'est parceque dans le projet web il manque dans le répertoire WEB-INF un fichier beans.xml. La présence de ce fichier active CDI (Context and Dependency Injection, l'injection de code dans les .java du projet Web). Vous pouvez en rajouter un vide à la main ou bien faire sur le répertoire WEB-INF dans le projet web, un clic droit puis others/Context and Dependency Injection/add a beans.xml file.

Une fois ce fichier présent dans WEB-INF si vous ajoutez un JSF Managed Bean au projet il sera bien généré avec @Named et les bons imports.

Q : je suis perdu avec les imports pour les Scoped, pour Named, pour Managed Bean

  • Réponse : on va donner un exemple avec @RequestScoped. Tout va dépendre de la manière dont vous déclarez le bean managé, soit avec @ManagedBean, soit avec @Named (recommandé, netbeans le fait par défaut)

Avec :

  • @ManagedBean
  • @RequestScoped

Il faut importer les deux classes depuis le package javax.faces.xxx

Avec :

  • @Named
  • @RequestScoped

Il faut importer depuis CDI les deux classes (soit javax.enterprise.xxx)

Tout mélange donne des résultats innatendus, et surtout -> AUCUNE ERREUR !

Moralité : utiliser toujours javax.enterprise.xxx pour les scopes et Named, sauf pour ViewScoped et ManagedBean où là il faut importer les deux depuis javax.faces

PIEGE : si on ne met rien comme scope, par exemple si on met juste @Named, c'est le @Dependant qui est pris par défaut (un nouvel objet est créé à chaque référence), mais dans le mauvais package ! Conclusion :

Avec @Named, toujours préciser le scope et vérifier que l'import vien de javax.entreprise.xxx !

Q: J'utilise faces-redirect=true et mes messages ne s'affichent pas

Réponse: Utiliser cette méthode au lieu de la méthode facesContext.addMessage :

private void addFlashMessage(FacesMessage message) {
    FacesContext facesContext = FacesContext.getCurrentInstanc<wbr/>e();
    Flash flash = facesContext.getExternalContex<wbr/>t().getFlash();
    flash.setKeepMessages(true);
    flash.setRedirect(true);
    facesContext.addMessage(null, message);
  }

Pour info : la mémoire flash de JSF permet de faire durer une variable "une requête de plus"...

Exemple d'utilisation:

 


Q: Je veux selectionner une ligne dans une datatable et popper un dialogue avec de quoi modifier la ligne

Le piège classique est d'avoir une structure comme ceci :

 

<h:form>
<p:dataTable ........../>
<p:dialog............./>
<p:dialog.........../>
</h:form>
 

Alors qu'il en faut une comme cela (un form par dialogue):

 

<h:form>
<p:dataTable ........../>
</h:form>
<h:form>
<p:dialog............./>
</h:form>
<h:form>
<p:dialog.........../>
</h:form>
 

Le projet suivant donne un exemple, il travaille avec la base de données sample de netbeans: Dialog2.rar

Q: J'ai un <p:menuItem action=...> qui ne rafraichit pas ma page

Mettre ajax="false" comme attribut, ou bien mettre un attribut update="..." pour updater le composant qui doit être mis à jour en Ajax.

Q : j'ai des erreurs jaunes sur les namespaces avec Primefaces

Si vous avez dans la page d'accueil de votre projet une dizaine de lignes en orange donnant des erreurs de namespace primefaces, il faut retirer la librairie de votre projet, puis la rajouter et faire clean and build, puis redéployer. Cela arrive rarement mais cette solution fonctionne si vous rencontrez cette erreur.

Q : un Managed Bean peut-il en appeler un autre ? En avoir un autre comme attribut ?

Voici un Bean (premier source) qui est utilisé par un autre (second source) :

import java.io.Serializable;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.SessionScoped;
 
@ManagedBean(name="message")
@SessionScoped
public class MessageBean implements Serializable {
 
	//business logic and whatever methods...
 
}
import java.io.Serializable;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.ManagedProperty;
import javax.faces.bean.SessionScoped;
 
@ManagedBean
@SessionScoped
public class HelloBean implements Serializable {
 
	@ManagedProperty(value="#{message}")
	private MessageBean messageBean;
 
	//must povide the setter method
	public void setMessageBean(MessageBean messageBean) {
		this.messageBean = messageBean;
	}
 
	//...
}
 

Q : J'ai l'erreur  Managed bean declaring a passivating scope must be passivation capable. 

  • Réponse : le bean doit être Serializable, rajoutez "implements Serializable"

L'erreur complète est en fait :

GRAVE: Exception while loading the app : WELD-000072 Managed bean declaring a passivating scope must be passivation capable.  Bean:  Managed Bean [class controller.OperationMBean] with qualifiers [@Any @Default @Named],

Ce qui se traduit par, "avec ce scope, ce bean doit être sérializable.

Q : Il ne s'affiche rien dans ma datatable et je n'ai pas de message d'erreur

  • Réponse :
    1. soit vous vous êtes trompés dans le nom du backing bean (par ex : #{customerMBean.customers} au lieu de #{CustomerMBean.customers} par exemple, en effet EL ne provoque pas d'erreur en cas de bean non trouvé dans aucun des scopes.
    2. Vous avez oublié d'activer l'injection de code dans le projet. Vous pouvez réactiver cela en créeant un fichier beans.xml VIDE dans le répertoire WEB-INF de la partie web du projet.
    3. Vous vous êtes trompés dans les imports des Scope. Par exemple javax.faces.context.SessionScoped au lieu de javax.entreprise.context.SessionScoped.

Q : ma table PrimeFaces ne se trie pas

  • Réponse :
    1. Il faut cacher la variable qui contient la liste des objets à afficher dans le tableau. Le getter de la propriété étant appelé plusieurs fois, si la liste retournée est updatée plusieurs fois le tri ne peut avoir lieu. Exemple : dans getCustomers() du TP1 : cacher la liste. Attention si vous êtes en SessionScoped, si les données changent -> pas de modifications visibles étant donné qu'on a caché la variable. Solution : un bouton refresh ou passer avec un autre Scope.

Q : j'ai une erreur au déploiement EJBvalidator ou EJBBundle errors

  • Réponse :
    1. Suite à un clean and build, netbeans 7.0 peut ajouter des ejb-refs dans le fichier web.xml, c'est un bug. Solution : virer les lignes ejb-ref et ejb-local-ref du fichier web.xml, redéployer.

Q : J'ai une erreur Caused by: java.lang.IllegalStateException: PWC3999: Cannot create a session after the response has been committed

  • Réponse :
    1. c'est une erreur sur les datatables PrimeFaces entre autres, intervient en ViewScope ou ConversationScope lorsque le buffer de sortie est trop gros. C'est un bug mojara ou PF, les deux parties sont en train de discuter pour corriger.
    2. Solutions à voir sur : http://java.net/jira/browse/JAVASERVERFACES-2215
    3. Ce bug n'intervient que sur des gros tableaux...  

 Solution donc : ajouter un événement preRenderView dans la page qui contient la dataTable (ligne 8) :

<h:head>
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
        <link href="./resources/css/default.css" rel="stylesheet" type="text/css" />
        <link href="./resources/css/cssLayout.css" rel="stylesheet" type="text/css" />
    </h:head>
    <h:body>

<f:event type="javax.faces.event.PreRenderViewEvent" listener="#{customerMBean.preRenderView}"/> 


        <f:view>
            <h:form>
                <h1><h:outputText value="List"/></h1>
                    <p:dataTable value="#{customerMBean.customers}" var="item" 
                                 emptyMessage="No customer found with given criteria" 
                                 widgetVar="customerTable"
                                 paginator="true"
                                 rows="10">

Ajouter dans la méthode envoyée par l'événement, il faut la forcer à créer une session bidon avant toutes choses :

@ManagedBean 
@ViewScoped
public class CustomerMBean implements Serializable {

    @EJB
    private DiscountCodeManager discountCodeManager;
    @EJB
    private CustomerManager customerManager;
    /* Client courant dans la session, utilisé pour afficher ses détails ou
     * pour faire une mise à jour du client modifié dans la base */
    private Customer customer;
    private List<Customer> customers;
    /**
     * Id du client dont on veut les détails.
     */
    private int idDetails;

     public void preRenderView() {
      HttpSession session = ( HttpSession ) FacesContext.getCurrentInstance().getExternalContext().getSession( true );
      //tune session params, eg. session.setMaxInactiveInterval(..);

      //perform other pre-render stuff, like setting user context...
   }

Q : comment marche le ConversationScoped ?

  • Réponse :
    1. Pas facile de trouver des exemples, on se perd facilement sur le net à cause du même scope qui existe dans le framework Seam de JBoss.

Voici un exemple d'utilisation : on ajoute @ConversationScoped dans le backing bean et on injecte une variable de type Conversation. Puis on appelle conversation.begin() et conversation.end() pour contrôler la création et la suppression de l'instance du bean.

Exemple (voir lignes 7, 10, 11, 16, 27...) :

import javax.enterprise.context.Conversation;
import javax.enterprise.context.ConversationScoped;
import javax.inject.Inject;


@Named(value = "customerMBean")
@ConversationScoped
public class CustomerMBean implements Serializable {

    @Inject
    Conversation conversation;
    @EJB
    private DiscountCodeManager discountCodeManager;

    public String showDetails(Customer customer) {
        conversation.begin();
        this.customer = customer;
        currentDiscoutCode = customer.getDiscountCode().getDiscountCode().toString();
        return "CustomerDetails";
    }

...
    public String update() {
        DiscountCode code = discountCodeManager.getDiscountCodeFromStringCode(currentDiscoutCode);
        customer.setDiscountCode(code);
        customer = customerManager.update(customer);
        conversation.end();
        return "CustomerList";
    }

 Piège : à tout begin() doit correspondre un end(), attention !

 Q : quel Scope si on fait de l'Ajax depuis des formulaires ?

Ah ! Surtout pas @RequestScoped sinon -> une requête par appel Ajax et donc une nouvelle instance du backing bean !

  • Réponse : utiliser @ViewScoped qui est prévu pour cela, ou @ConversationScoped, ou @SessionScoped

Q : mes liens dans mes templates ne sont pas bons, mes CSS ne s'affichent pas

  • Réponse : utiliser des <h:link value="texte du lien" outcome="destinationpage.xhtml"/> au lieu de <a href...> html, utiliser <h:outputStylesheet library="dossier de la ressource" name="nom du fichier css" /> au lieu de <h:link...> de html.
  • Les fichiers css doivent être dans un répertoire "resources", ou dans un sous-répertoire. Par exemple si vous avez au même niveau que index.xhtml le répertoire "resources/css/default.css", vous incluerez <h:outputStylesheet library="css" name="default.css"/>

Q : comment inclure une librairie javascript dans une page JSF ?

  • Réponse : utiliser <h:outputScript library="dossier de la ressource" name="nom du fichier js" />
  • Même contrainte que pour les stylesheets, les fichiers js doivent être dans "resources" ou dans un sous-répertoire. Voir entrée précédente de la FAQ pour les stylesheet css.

Q :Avertissement: PWC4011: Unable to set request character encoding to UTF-8>

Si vous avez l'erreur : "Avertissement: PWC4011: Unable to set request character encoding to UTF-8 from context /xxxxx, because request parameters have already been read, or ServletRequest.getReader() has already been called...", ne paniquez pas !

Pour l'enlever, il suffit d'ajouter <parameter-encoding default-charset="UTF-8"/> dans le fichier glassfish-web.xml.

Q: Je clique sur un <h:commandButton> ou <h:commandLink> et il ne se passe rien

  • Réponse: vérifier que vous êtes bien dans un <h:form> !

 

Mots clés:
FichierTailleDateAttaché par 
 Dialog2.rar
Aucune description
45.33 Ko16:41, 14 Déc 2012MichelBuffaActions
Images (0)
 
Commentaires (0)
Vous devez être connecté pour poster un commentaire.