java.lang.IllegalStateException:在JSF中实现自定义标记处理程序时出现java.lang.InstantiationException [英] java.lang.IllegalStateException: java.lang.InstantiationException while implementing a custom tag handler in JSF

查看:81
本文介绍了java.lang.IllegalStateException:在JSF中实现自定义标记处理程序时出现java.lang.InstantiationException的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

给出以下标记处理程序类.

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.

这在XHTML页面上的用法如下.

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>

我们可以像converter="javax.faces.Long"

实际上,有一个模板,其中<f:metadata>包含在<ui:define name="metaData">中.

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

关联的JSF托管bean:

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

按下给定的<p:commandButton>时,将引发以下异常.

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

例如,此标记处理程序应仅与<f:viewParam>关联,并且在进行回发时应完全跳过该标记处理程序.

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.

有什么解决办法吗?

关键:

apply()方法内部的条件检查中,

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

当单击给定的按钮时,这种情况明显被评估为false.因此,应该没有任何问题.

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

令人惊讶的是,当按如下方式删除if语句中的唯一行时,该异常消失了.

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.
}

在这种情况下,即使条件被评估为false,当按下给定的<p:commandButton>时,它也不会引发如上所述的异常.

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.

从未见过这种情况:)

推荐答案

默认情况下,JSF序列化视图中任何<h:form>的视图状态(组件树状态)(为<input type="hidden" name="javax.faces.ViewState">).在该表单上的回发请求的还原视图阶段,将还原该文件. JSF视图状态涵盖了树中组件的 component 系统事件侦听器.

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.

此行

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

将一个添加到UIViewRoot组件,然后需要对其进行序列化.

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

您有4个选项:

  1. 让它实现 Serializable
  2. 让它实现 Externalizable
  3. 完成工作后,取消订阅侦听器.
  4. 使用SystemEventListener代替ComponentSystemEventListener.
  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.

在这种特殊情况下,只要您不需要在单个<f:viewParam>中支持标签嵌套,而仅在<f:metadata>中,则选项4就足够了.将ComponentSystemEventListener接口替换为SystemEventListener,实现isListenerForSource()方法以仅对UIViewRoot返回true,最后使用UIViewRoot#subscribeToViewEvent()代替订阅侦听器.

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

}

这篇关于java.lang.IllegalStateException:在JSF中实现自定义标记处理程序时出现java.lang.InstantiationException的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆