Выполнение ActionListener пункта меню (Primefaces) приводит к IllegalStateException

в JSF backed bean я получил IllegalStateException при вызове программно добавленного прослушивателя действий программно добавленного элемента меню Primefaces. Я попробовал оба 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>

Backed 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
    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)

2 ответов


EL (read: reflection) не может получить доступ/построить анонимные классы. Рефакторинг их в fullworthy классов.

Так, замените

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

by

    item.addActionListener(new FooActionListener());

и

public class FooActionListener implements ActionListener {

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

}

Читайте также:


похоже, что дополнительное ограничение заключается в том, что класс ActionListener не имеет аргументов contructor, что добавляет оскорбление к травме здесь. Насколько я вижу, addActionListener, вероятно, просто хранит имя класса переданного ему объекта.

на самом деле, если целью было сделать этот прослушиватель непригодным для использования, предотвращая передачу каких-либо данных слушателю от вашего резервного компонента, они вряд ли могли бы сделать больше.

вы получаете еще одно исключение IllegalStateException если вы попробуете подкласс MenuItem.

вы не можете передать объект, содержащий данные в 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 {

(работает как внутренний класс, но не может быть анонимным).