Search code examples
jsfjsf-2dependency-injectionactionlistenermanaged-property

How can I inject a managed property in an ActionListener


I wanted process data from other bean, in ActionListener method, but it throw NullPointerException, so i try resafe instance of bean to next instance in init() method with @PostConstruct annotation, but it still throw NullPointerException. I know that can obtain bean throught FacesContext.getCurrentInstance().getApplication().evaluateExpressionGet(context, expression, expectedType);but is it possible throught @ManagedProperty? This is the code:

Login.java

package sklad;

import javax.annotation.PostConstruct;
import javax.faces.application.FacesMessage;
import javax.faces.bean.ManagedProperty;
import javax.faces.context.FacesContext;
import javax.faces.event.AbortProcessingException;
import javax.faces.event.ActionEvent;
import javax.faces.event.ActionListener;

public class Login implements ActionListener{
        private Osoba os;

        @ManagedProperty(value="#{osoba}")
        private Osoba osoba;

        @PostConstruct
        public void init(){
            os = osoba;
        }

        @Override
        public void processAction(ActionEvent a) throws AbortProcessingException {
            FacesContext context = FacesContext.getCurrentInstance();
            context.addMessage("zprava", new FacesMessage(os.getId().toString() + " " + os.getHeslo()));

        }

        public Osoba getOsoba() {
            return osoba;
        }

        public void setOsoba(Osoba osoba) {
            this.osoba = osoba;
        }

        public Osoba getOs() {
            return os;
        }

        public void setOs(Osoba os) {
            this.os = os;
        }
    }

Osoba.java

package sklad;

import javax.faces.application.FacesMessage;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.SessionScoped;
import javax.faces.context.FacesContext;
import javax.faces.event.ActionEvent;

    @ManagedBean
    @SessionScoped
    public class Osoba{
        private Integer id;
        private String heslo;

        public Osoba(){}

        public Integer getId() {
            return id;
        }

        public void setId(Integer id) {
            this.id = id;
        }

        public String getHeslo() {
            return heslo;
        }

        public void setHeslo(String heslo) {
            this.heslo = heslo;
        }
    }

login.xhtml

 <!DOCTYPE html>
<html xmlns:h="http://xmlns.jcp.org/jsf/html"
    xmlns:f="http://xmlns.jcp.org/jsf/core"
    xmlns:p="http://primefaces.org/ui">

<h:head>
    <title>title</title>
    <link rel="stylesheet" type="text/css" href="../styles/login.css" />
</h:head>
<h:body>
    <p:growl id="growl" showDetail="true" life="3000" />
    <p:panel id="panel_login" header="Přihlášení" styleClass="panel">
        <p:panelGrid styleClass="panelGrid">
            <h:form>
                <p:row>
                    <p:column>
                        <h:outputText value="ID: " />
                    </p:column>
                    <p:column>
                        <h:inputText id="id_login" value="${osoba.id}" />
                    </p:column>
                </p:row>

                <p:row>
                    <p:column>
                        <h:outputText value="Heslo: " />
                    </p:column>
                    <p:column>
                        <h:inputSecret id="heslo_login" value="${osoba.heslo}" />
                    </p:column>
                </p:row>

                <p:row>
                    <p:column colspan="2">
                        <h:commandButton id="btn_login" value="Přihlásit">
                            <f:actionListener type="sklad.Login"/>
                        </h:commandButton>
                    </p:column>
                </p:row>
            </h:form>
        </p:panelGrid>
    </p:panel>
</h:body>
</html>

Solution

  • The more traditional way of invoking an action listener is to use a method binding, like so:

    @ManagedBean
    @RequestScoped
    public class Login {
      ...
    
      public void doLogin(ActionEvent event){
        // handle action
      }
    }
    

    And then in the button:

    <h:commandButton id="btn_login" value="Přihlásit" actionListener="#{login.doLogin}"/>
    

    This approach has the benefit of turning Login into a ManagedBean, which will make it so the annotations on it will be processed by JSF - and that makes the @ManagedProperty annotation work as expected.