Выполнение ActionListener элемента меню (Primefaces) приводит к IllegalStateException - PullRequest
6 голосов
/ 25 марта 2011

В бине с поддержкой JSF я получил IllegalStateException, когда вызывается программно добавленный слушатель действия программно добавленного пункта меню Primefaces. Я пробовал оба request и session scope, но оба приводят к одной и той же ошибке. Очевидно, что в соответствии с трассировкой стека необходимо восстановить представление, когда слушатель действия выполняется, и я позволил своему 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>

Поддерживаемый компонент с меню

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

Ответы [ 2 ]

8 голосов
/ 25 марта 2011

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 голос
/ 26 октября 2011

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

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

Вы получаете другое 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 {

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

...