2014-05-23 12 views
6

Data la seguente classe di gestione tag.java.lang.IllegalStateException: java.lang.InstantiationException durante l'implementazione di un gestore tag personalizzato in JSF

public final class ViewParamValidationFailed extends TagHandler implements ComponentSystemEventListener 
{ 
    private final String redirect; 

    public ViewParamValidationFailed(TagConfig config) { 
     super(config); 
     redirect = getRequiredAttribute("redirect").getValue(); 
    } 

    @Override 
    public void apply(FaceletContext context, UIComponent parent) throws IOException { 
     if (parent instanceof UIViewRoot && !context.getFacesContext().isPostback()) { 
      ((UIViewRoot) parent).subscribeToEvent(PostValidateEvent.class, this); 
     } 
    } 

    @Override 
    public void processEvent(ComponentSystemEvent event) throws AbortProcessingException { 
     FacesContext context = FacesContext.getCurrentInstance(); 

     if (context.isValidationFailed()) { 
      try { 
       ExternalContext externalContext = context.getExternalContext(); 
       externalContext.redirect(externalContext.getRequestContextPath() + redirect); 
      } 
      catch (IOException e) { 
       throw new AbortProcessingException(e); 
      } 
     } 
    } 
} 

Il gestore tag ha lo scopo di reindirizzare a una pagina, quando la conversione fallisce.

Viene utilizzato su pagine XHTML come segue.

<?xml version='1.0' encoding='UTF-8' ?> 
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> 
<html xmlns="http://www.w3.org/1999/xhtml" 
     xmlns:h="http://xmlns.jcp.org/jsf/html" 
     xmlns:p="http://primefaces.org/ui" 
     xmlns:my="http://example.com/ui" 
     xmlns:f="http://xmlns.jcp.org/jsf/core"> 

    <h:head> 
     <title>Test</title> 
    </h:head> 

    <h:body> 
     <f:metadata> 
      <f:viewParam name="id" required="true" value="#{testManagedBean.id}"/> 
      <my:viewParamValidationFailed redirect="/public_resources/PageNotFound.jsf"/> 
     </f:metadata> 

     <h:form id="form" prependId="true"> 
      <p:commandButton value="Submit" actionListener="#{testManagedBean.submitAction}"/> 
     </h:form> 
    </h:body> 
</html> 

possiamo avere un attributo convertitore opzionale <f:viewParam> proprio come converter="javax.faces.Long"

In realtà, c'è un modello in cui <f:metadata> è racchiuso all'interno di <ui:define name="metaData">.

Il JSF associato bean gestito:

@ManagedBean 
@RequestScoped 
public final class TestManagedBean 
{ 
    private Long id; // Getter and setter. 

    public TestManagedBean() {} 

    public void submitAction() { 
     System.out.println("submitAction() called."); 
    } 
} 

quando si preme il data <p:commandButton>, il seguente viene generata un'eccezione.

SEVERE: java.lang.IllegalStateException: java.lang.InstantiationException: tags.ViewParamValidationFailed 
    at javax.faces.component.StateHolderSaver.restore(StateHolderSaver.java:153) 
    at javax.faces.component.UIComponent$ComponentSystemEventListenerAdapter.restoreState(UIComponent.java:2633) 
    at javax.faces.component.StateHolderSaver.restore(StateHolderSaver.java:165) 
    at javax.faces.component.UIComponentBase.restoreAttachedState(UIComponentBase.java:1793) 
    at javax.faces.component.UIComponentBase.restoreSystemEventListeners(UIComponentBase.java:1911) 
    at javax.faces.component.UIComponentBase.restoreState(UIComponentBase.java:1607) 
    at javax.faces.component.UIViewRoot.restoreState(UIViewRoot.java:1771) 
    at com.sun.faces.application.view.FaceletPartialStateManagementStrategy$2.visit(FaceletPartialStateManagementStrategy.java:380) 
    at com.sun.faces.component.visit.FullVisitContext.invokeVisitCallback(FullVisitContext.java:151) 
    at javax.faces.component.UIComponent.visitTree(UIComponent.java:1690) 
    at com.sun.faces.application.view.FaceletPartialStateManagementStrategy.restoreView(FaceletPartialStateManagementStrategy.java:367) 
    at com.sun.faces.application.StateManagerImpl.restoreView(StateManagerImpl.java:138) 
    at com.sun.faces.application.view.ViewHandlingStrategy.restoreView(ViewHandlingStrategy.java:123) 
    at com.sun.faces.application.view.FaceletViewHandlingStrategy.restoreView(FaceletViewHandlingStrategy.java:590) 
    at com.sun.faces.application.view.MultiViewHandler.restoreView(MultiViewHandler.java:150) 
    at javax.faces.application.ViewHandlerWrapper.restoreView(ViewHandlerWrapper.java:353) 
    at org.omnifaces.viewhandler.RestorableViewHandler.restoreView(RestorableViewHandler.java:66) 
    at javax.faces.application.ViewHandlerWrapper.restoreView(ViewHandlerWrapper.java:353) 
    at com.sun.faces.lifecycle.RestoreViewPhase.execute(RestoreViewPhase.java:197) 
    at com.sun.faces.lifecycle.Phase.doPhase(Phase.java:101) 
    at com.sun.faces.lifecycle.RestoreViewPhase.doPhase(RestoreViewPhase.java:121) 
    at com.sun.faces.lifecycle.LifecycleImpl.execute(LifecycleImpl.java:198) 
    at javax.faces.webapp.FacesServlet.service(FacesServlet.java:646) 
    at org.apache.catalina.core.StandardWrapper.service(StandardWrapper.java:1682) 
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:344) 
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:214) 
    at org.primefaces.webapp.filter.FileUploadFilter.doFilter(FileUploadFilter.java:70) 
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:256) 
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:214) 
    at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:316) 
    at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:160) 
    at org.apache.catalina.core.StandardPipeline.doInvoke(StandardPipeline.java:734) 
    at org.apache.catalina.core.StandardPipeline.invoke(StandardPipeline.java:673) 
    at com.sun.enterprise.web.WebPipeline.invoke(WebPipeline.java:99) 
    at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:174) 
    at org.apache.catalina.connector.CoyoteAdapter.doService(CoyoteAdapter.java:357) 
    at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:260) 
    at com.sun.enterprise.v3.services.impl.ContainerMapper.service(ContainerMapper.java:188) 
    at org.glassfish.grizzly.http.server.HttpHandler.runService(HttpHandler.java:191) 
    at org.glassfish.grizzly.http.server.HttpHandler.doHandle(HttpHandler.java:168) 
    at org.glassfish.grizzly.http.server.HttpServerFilter.handleRead(HttpServerFilter.java:189) 
    at org.glassfish.grizzly.filterchain.ExecutorResolver$9.execute(ExecutorResolver.java:119) 
    at org.glassfish.grizzly.filterchain.DefaultFilterChain.executeFilter(DefaultFilterChain.java:288) 
    at org.glassfish.grizzly.filterchain.DefaultFilterChain.executeChainPart(DefaultFilterChain.java:206) 
    at org.glassfish.grizzly.filterchain.DefaultFilterChain.execute(DefaultFilterChain.java:136) 
    at org.glassfish.grizzly.filterchain.DefaultFilterChain.process(DefaultFilterChain.java:114) 
    at org.glassfish.grizzly.ProcessorExecutor.execute(ProcessorExecutor.java:77) 
    at org.glassfish.grizzly.nio.transport.TCPNIOTransport.fireIOEvent(TCPNIOTransport.java:838) 
    at org.glassfish.grizzly.strategies.AbstractIOStrategy.fireIOEvent(AbstractIOStrategy.java:113) 
    at org.glassfish.grizzly.strategies.WorkerThreadIOStrategy.run0(WorkerThreadIOStrategy.java:115) 
    at org.glassfish.grizzly.strategies.WorkerThreadIOStrategy.access$100(WorkerThreadIOStrategy.java:55) 
    at org.glassfish.grizzly.strategies.WorkerThreadIOStrategy$WorkerThreadRunnable.run(WorkerThreadIOStrategy.java:135) 
    at org.glassfish.grizzly.threadpool.AbstractThreadPool$Worker.doWork(AbstractThreadPool.java:564) 
    at org.glassfish.grizzly.threadpool.AbstractThreadPool$Worker.run(AbstractThreadPool.java:544) 
    at java.lang.Thread.run(Thread.java:722) 
Caused by: java.lang.InstantiationException: tags.ViewParamValidationFailed 
    at java.lang.Class.newInstance0(Class.java:357) 
    at java.lang.Class.newInstance(Class.java:325) 
    at javax.faces.component.StateHolderSaver.restore(StateHolderSaver.java:150) 
    ... 54 more 

Questo tag handler deve essere associato solo con <f:viewParam> e dovrebbe essere saltato nella sua interezza, quando un palo è fatto, per esempio.

C'è qualche soluzione?


cruciale:

Nel controllo condizionale all'interno del metodo apply(),

if (parent instanceof UIViewRoot && !context.getFacesContext().isPostback()) { 
    System.out.println("Inside if"); 
    ((UIViewRoot) parent).subscribeToEvent(PostValidateEvent.class, this); 
} 

Quando il pulsante proposta viene cliccato, questa condizione viene valutata false come ovvio. Quindi, non dovrebbe esserci alcun problema.

Sorprendentemente, l'eccezione scompare quando l'unica riga all'interno dell'istruzione if viene rimossa come segue.

if (parent instanceof UIViewRoot && !context.getFacesContext().isPostback()) { 
    //Debug statements only. 
} 

Esso non genera l'eccezione come detto sopra, quando viene premuto il dato <p:commandButton> se la condizione viene valutata false, in questo caso.

non ha mai visto questo tipo di situazione :)

risposta

9

Per impostazione predefinita, JSF serializza lo stato di visualizzazione (il componente albero di Stato) per qualsiasi <h:form> nella visualizzazione (come <input type="hidden" name="javax.faces.ViewState">). Questo viene ripristinato durante la fase di visualizzazione di ripristino della richiesta di postback su tale modulo. Lo stato di visualizzazione JSF copre tra gli altri gli ascoltatori di eventi di sistema componente dei componenti nella struttura.

Questa linea

((UIViewRoot) parent).subscribeToEvent(PostValidateEvent.class, this); 

aggiunge uno alla componente UIViewRoot e questo allora deve essere serializzato.

Tu hai 4 opzioni:

  1. Let it implementare Serializable.
  2. Lasciare implementare Externalizable.
  3. Annullare l'iscrizione all'ascoltatore quando ha terminato il proprio lavoro.
  4. Utilizzare SystemEventListener anziché ComponentSystemEventListener.

In questo caso particolare, fino a quando non è necessario per sostenere la nidificazione del tag all'interno dell'individuo <f:viewParam>, ma solo in <f:metadata>, quindi l'opzione 4 dovrebbe essere sufficiente. Sostituire l'interfaccia ComponentSystemEventListener con SystemEventListener, implementare il metodo per restituire true solo per UIViewRoot, infine utilizzare UIViewRoot#subscribeToViewEvent() per sottoscrivere il listener.

public final class ViewParamValidationFailed extends TagHandler implements SystemEventListener { 
    private final String redirect; 

    public ViewParamValidationFailed(TagConfig config) { 
     super(config); 
     redirect = getRequiredAttribute("redirect").getValue(); 
    } 

    @Override 
    public void apply(FaceletContext context, UIComponent parent) throws IOException { 
     if (parent instanceof UIViewRoot && !context.getFacesContext().isPostback()) { 
      ((UIViewRoot) parent).subscribeToViewEvent(PostValidateEvent.class, this); 
     } 
    } 

    @Override 
    public boolean isListenerForSource(Object source) { 
     return source instanceof UIViewRoot; 
    } 

    @Override 
    public void processEvent(SystemEvent event) throws AbortProcessingException { 
     FacesContext context = FacesContext.getCurrentInstance(); 

     if (context.isValidationFailed()) { 
      try { 
       ExternalContext externalContext = context.getExternalContext(); 
       externalContext.redirect(externalContext.getRequestContextPath() + redirect); 
      } 
      catch (IOException e) { 
       throw new AbortProcessingException(e); 
      } 
     } 
    } 

}