【问题标题】:Executing the ActionListener of a (Primefaces) menu item leads to an IllegalStateException执行 (Primefaces) 菜单项的 ActionListener 会导致 IllegalStateException
【发布时间】:2011-03-25 13:14:24
【问题描述】:

在 JSF 支持的 bean 中,当调用以编程方式添加的 Primefaces 菜单项的以编程方式添加的操作侦听器时,我得到了一个 IllegalStateException。我尝试了requestsession 范围,但都导致了相同的错误。显然,根据堆栈跟踪,需要在执行动作侦听器时恢复视图,我让我的 ToolbarBean 实现 Serializable 没有不同的效果。为了让它发挥作用,我应该考虑什么?

用户界面定义

<?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:f="http://java.sun.com/jsf/core"
    xmlns:h="http://java.sun.com/jsf/html"
    xmlns:ui="http://java.sun.com/jsf/facelets"
    xmlns:p="http://primefaces.prime.com.tr/ui">

<h:head>
    <title>TITLE</title>
</h:head>

<h:body>
    <h:form>
        <p:menu model="#{toolbarBean.model}" type="tiered" />
    </h:form>
</h:body>
</html>

提供菜单的支持 bean

@Named
@Scope("request")
public class ToolbarBean implements Serializable {

    private static final long serialVersionUID = -8556751897482662530L;

    public ToolbarBean() {
        model = new DefaultMenuModel();

        MenuItem item;

        // Direct menu item
        item = new MenuItem();
        item.setValue("Menuitem 1");
        item.addActionListener(new ActionListener() {
            @Override
            public void processAction(ActionEvent event)
                    throws AbortProcessingException {
                System.out.println(event.toString());
            }
        });

        model.addMenuItem(item);

        item = new MenuItem();
        item.setValue("Menuitem 2");
        item.addActionListener(new ActionListener() {
            @Override
            public void processAction(ActionEvent event)
                    throws AbortProcessingException {
                System.out.println(event.toString());
            }
        });

        model.addMenuItem(item);
    }

    private MenuModel model;

    public MenuModel getModel() {
        return model;
    }
}

点击其中一个菜单按钮时出现异常

javax.faces.FacesException: java.lang.IllegalStateException: java.lang.InstantiationException: id.co.sofcograha.baseui.ToolbarBean$1
    at javax.faces.component.UIComponent.invokeOnComponent(UIComponent.java:1284)
    at javax.faces.component.UIComponentBase.invokeOnComponent(UIComponentBase.java:673)
    at javax.faces.component.UIComponent.invokeOnComponent(UIComponent.java:1290)
    at javax.faces.component.UIComponentBase.invokeOnComponent(UIComponentBase.java:673)
    at javax.faces.component.UIComponent.invokeOnComponent(UIComponent.java:1290)
    at javax.faces.component.UIComponentBase.invokeOnComponent(UIComponentBase.java:673)
    at javax.faces.component.UIComponent.invokeOnComponent(UIComponent.java:1290)
    at javax.faces.component.UIComponentBase.invokeOnComponent(UIComponentBase.java:673)
    at com.sun.faces.application.view.StateManagementStrategyImpl.restoreView(StateManagementStrategyImpl.java:297)
    at com.sun.faces.application.StateManagerImpl.restoreView(StateManagerImpl.java:177)
    at com.sun.faces.application.view.ViewHandlingStrategy.restoreView(ViewHandlingStrategy.java:119)
    at com.sun.faces.application.view.FaceletViewHandlingStrategy.restoreView(FaceletViewHandlingStrategy.java:438)
    at com.sun.faces.application.view.MultiViewHandler.restoreView(MultiViewHandler.java:144)
    at javax.faces.application.ViewHandlerWrapper.restoreView(ViewHandlerWrapper.java:284)
    at com.sun.faces.lifecycle.RestoreViewPhase.execute(RestoreViewPhase.java:182)
    at com.sun.faces.lifecycle.Phase.doPhase(Phase.java:97)
    at com.sun.faces.lifecycle.RestoreViewPhase.doPhase(RestoreViewPhase.java:107)
    at com.sun.faces.lifecycle.LifecycleImpl.execute(LifecycleImpl.java:114)
    at javax.faces.webapp.FacesServlet.service(FacesServlet.java:308)

【问题讨论】:

    标签: jsf el primefaces javabeans actionlistener


    【解决方案1】:

    EL(阅读:反射)无法访问/构造匿名类。将它们重构为完全有价值的类。

    所以,替换

        item.addActionListener(new ActionListener() {
            @Override
            public void processAction(ActionEvent event)
                    throws AbortProcessingException {
                System.out.println(event.toString());
            }
        });
    

    通过

        item.addActionListener(new FooActionListener());
    

    public class FooActionListener implements ActionListener {
    
        @Override
        public void processAction(ActionEvent event)
                throws AbortProcessingException {
            System.out.println(event.toString());
        }
    
    }
    

    另见:

    【讨论】:

    • 谢谢巴鲁斯。请代我向奇奇瑞问好。
    【解决方案2】:

    看起来另一个限制是 ActionListener 类没有构造函数参数,这在此处增加了侮辱。据我所知,addActionListener 可能只是存储传递给它的对象的类名。

    事实上,如果意图是通过阻止任何数据从您的支持 bean 传递给侦听器来使该侦听器无法使用,他们几乎无法做更多的事情。

    如果你尝试继承 MenuItem,你会得到另一个 IllegalStateException。

    您不能将包含数据的对象作为值传递给 MenuItem,它需要一个字符串。

    它似乎不允许将侦听器作为内部类。

    但我想我可能已经破解了,方法是将所需的数据放入菜单项的属性映射中。

    这就是我的结论:

    public class MenuSelectListener implements ActionListener {
    public static final String MENU_ACTION_KEY = "menu.action.delegate";
    
    private final static Log log = LogFactory.getLog(MenuSelectListener.class);
    
    @Override
    public void processAction(ActionEvent ae) throws AbortProcessingException {
        System.out.println("listener invoked");
        if (ae.getComponent() instanceof MenuItem) {
            Runnable delegate = (Runnable) ae.getComponent().getAttributes().get(MENU_ACTION_KEY);
            if(delegate != null)
                delegate.run();
            else
                log.error("Menu action has no runnable");
        } else {
            log.error("Listener, wrong component class: " + ae.getComponent().getClass().getName());
        }
    }
    

    }

    要设置一个项目:-

            item.setValue("Cancel");
            sm.getChildren().add(item);
            item.addActionListener(new MenuSelectListener());
            item.getAttributes().put(MenuSelectListener.MENU_ACTION_KEY, new MiscActionDelegate(MiscActions.close));
    

    与:

    private class MiscActionDelegate implements Runnable, Serializable {
    

    (作为内部类工作,但不能匿名)。

    【讨论】:

    • 不,这不是原因。它是一个接口(无论如何都是不可构造的),并且 OP 已将其实例化为匿名类而不是普通的实现类。
    • 是的,但是我尝试按照建议进行操作,但是使用了一个采用构造函数参数的类,并且 IllegalStateException 仍然发生。
    猜你喜欢
    • 2017-03-15
    • 2015-09-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-04
    • 1970-01-01
    • 2014-06-19
    • 1970-01-01
    相关资源
    最近更新 更多