在JSF支持的bean中,当以编程方式添加了一个以编程方式添加的Primefaces菜单项的动作侦听器时,我得到了IllegalStateException
。我尝试了request
和session
范围,但两者都导致了同样的错误。显然需要 - 根据堆栈跟踪 - 在执行动作侦听器时恢复视图,并让我的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)
答案 0 :(得分:8)
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());
}
}
答案 1 :(得分:1)
看起来一个额外的限制是ActionListener类没有构造函数参数,这种类型会在这里增加侮辱。据我所知,addActionListener可能只存储传递给它的对象的类名。
事实上,如果意图是通过阻止任何数据从你的支持bean传递给监听器而使这个监听器无法使用,那么他们几乎不可能做得更多。
如果尝试继承MenuItem,则会出现另一个IllegalStateException。
您不能将包含数据的对象作为值传递给MenuItem,它需要一个String。
似乎不允许将侦听器作为内部类。
但是我想我可能已经破解了它,把所需的数据放在菜单项的属性图中。
这就是我最后的结果:
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 {
(作为内部类,但不能匿名)。