Java.lang.IllegalStateException: java.lang.InstantiationException when implementing a special tag handler in JSF

Given the following tag handler class.

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); } } } } 

The tag handler is intended only to redirect to the page if the conversion fails.

This is used on XHTML pages as follows.

 <?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> 

we can have an optional converter attribute with <f:viewParam> , like converter="javax.faces.Long"

In fact, there is a template in which <f:metadata> enclosed in <ui:define name="metaData"> .

JSF related bean:

 @ManagedBean @RequestScoped public final class TestManagedBean { private Long id; // Getter and setter. public TestManagedBean() {} public void submitAction() { System.out.println("submitAction() called."); } } 

When this <p:commandButton> , the following exception is thrown.

 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 

This tag handler should only be associated with <f:viewParam> and should be skipped completely when, for example, feedback is created.

Is there any solution?


Decisive:

In conditional check inside apply() method

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

When this button is pressed, this condition is evaluated as false as obvious. Therefore, there should be no problems.

Surprisingly, the exception disappears when the only line inside the if is deleted, as shown below.

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

It does not throw an exception, as indicated above, when the given <p:commandButton> pressed, although in this case the condition evaluates to false.

I have never seen such a situation :)

+6
source share
1 answer

By default, JSF serializes the view state (component tree state) for any <h:form> in the view (as <input type="hidden" name="javax.faces.ViewState"> ). This is restored during the review phase of the recovery of the postback request in this form. The JSF view state covers, among others, system listeners for system events of component components in the tree.

This line

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

adds one to the UIViewRoot component, and then it is necessary for serialization.

You have 4 options:

  • Let it implements Serializable .
  • Let it implements Externalizable .
  • Unsubscribe from the listener when he has completed his work.
  • Use SystemEventListener instead of ComponentSystemEventListener .

In this particular case, if you do not need to maintain the nesting of the tag inside a separate <f:viewParam> , but only in <f:metadata> , then option 4 should be sufficient. Replace the ComponentSystemEventListener interface with SystemEventListener , implement the isListenerForSource() method to return true for UIViewRoot only, and finally use UIViewRoot#subscribeToViewEvent() to subscribe to the 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); } } } } 
+9
source

Source: https://habr.com/ru/post/969734/


All Articles