Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

java.lang.IllegalStateException: java.lang.InstantiationException while implementing a custom tag handler in JSF

Tags:

jsf

jsf-2.2

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 just meant to redirect to a page, when conversion fails.

This is used on an 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> just like converter="javax.faces.Long"

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

The associated JSF managed bean:

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

    public TestManagedBean() {}

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

When the given <p:commandButton> is pressed, 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 in its entirely, when a post back is made, for example.

Is there any solution?


Crucial :

In the conditional check inside the apply() method,

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

When the given button is clicked, this condition is evaluated to false as obvious. Hence, there should not be any problem.

Surprisingly, the exception disappears, when the only line inside the if statement is removed like as follows.

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

It doesn't throw the exception as mentioned above, when the given <p:commandButton> is pressed though the condition is evaluated to false, in this case.

Never saw this kind of situation :)

like image 612
Tiny Avatar asked May 23 '14 06:05

Tiny


People also ask

What is an IllegalStateException in Java?

Generally, this method is used to indicate a method is called at an illegal or inappropriate time. Example: After starting a thread we are not allowed to restart the same thread once again otherwise we will get Runtime Exception saying IllegalStateException.

What to do when illegalargumentexception is thrown in Java?

When the IllegalArgumentException is thrown, you must check the call stack in Java’s stack trace and locate the method that produced the wrong argument. The IllegalArgumentException is very useful and can be used to avoid situations where your application’s code would have to deal with unchecked input data.

Why we get IllegalStateException when we call start () method only once?

In the above example if we call start () method only once on thread t then we will not get any java.lang.IllegalStateException because we are not calling the start () method after the starting of thread (i.e we are not calling the start () method at an illegal or an inappropriate time.) Writing code in comment?

What is the purpose of this exception in Java?

This exception is rise explicitly by programmer or by the API developer to indicate that a method has been invoked at the wrong time. Generally, this method is used to indicate a method is called at an illegal or inappropriate time.


1 Answers

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

This line

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

adds one to the UIViewRoot component and this then needs to be serialized.

You've 4 options:

  1. Let it implement Serializable.
  2. Let it implement Externalizable.
  3. Unsubscribe the listener when it's done with its job.
  4. Use SystemEventListener instead of ComponentSystemEventListener.

In this particular case, as long as you don't need to support the nesting of the tag inside the individual <f:viewParam>, but only in <f:metadata>, then option 4 should suffice. Replace the ComponentSystemEventListener interface by SystemEventListener, implement the isListenerForSource() method to return true for UIViewRoot only, finally use UIViewRoot#subscribeToViewEvent() instead to subscribe 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);
            }
        }
    }

}
like image 86
BalusC Avatar answered Nov 02 '22 23:11

BalusC