0

My specs:

  • Dynamic Web Module 3.1
  • GlassFish Web Extensions 4.0
  • Java 1.8
  • JavaScript 1.0
  • JavaServer Faces 2.2
  • Server: glassfish-4.1.1
  • OS: Win 10
  • IDE: Version: Neon.2 Release (4.6.2)

Please, note that I have researched this topic and found several related posts.

e.g.

@ManagedProperty + @PostConstruct + init() = Nullpointer

@ManagedProperty injected AFTER @PostConstruct

But neither of the proposed solutions worked for me or applied to my situation. I don't mix CDI and/or JSF and/or Spring. It's JSF 2.2 annotations only.

I inject @ManagedProperty("#{country}") Country country; to my ChangeCountrySystemEventListener but the value of the @ManagedProperty country is null. I don't really see where the issue is. The Country constructor does get invoked.

Any tips where the issues is?

Here's my full code:

index.xhtml

    <!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:ui="http://xmlns.jcp.org/jsf/facelets"
        xmlns:h="http://xmlns.jcp.org/jsf/html"
        xmlns:f="http://xmlns.jcp.org/jsf/core">
    <h:head>
        <title>Title</title>
    </h:head>
    <h:body>

        <h3><h:outputText value="#{country.name}" /> </h3>
        <h:form>

            <h:commandButton
                id="changeCountryNameBtn"
                value="Change"
                action="result"
                actionListener="#{appBean.changeCountryName}"
             />

        </h:form>
    </h:body>
    </html>

AppBean.java

    package com.test.beans;

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

    @ManagedBean
    @SessionScoped
    public class AppBean {

        public void changeCountryName(ActionEvent ev) {

            FacesContext context = FacesContext.getCurrentInstance();
            Application app = context.getApplication();
            app.publishEvent(context, ChangeCountrySystemEvent.class, ev.getSource());
            System.out.println(">>>> AppBean.publishEvent(ChangeCountrySystemEvent) fired... " + ev.getSource());

        }

    }

ChangeCountrySystemEvent.java

    package com.test.beans;
    import javax.faces.event.SystemEvent;

    public class ChangeCountrySystemEvent extends SystemEvent {

        private static final long serialVersionUID = -1587717461942271611L;

        public ChangeCountrySystemEvent(Object source) {
            super(source);
            System.out.println(">>>> ChangeCountrySystemEvent.class :: constructor invoked!");
        }

    }

ChangeCountrySystemEventListener.java

    package com.test.beans;

    import javax.faces.bean.ManagedProperty;
    import javax.faces.context.FacesContext;
    import javax.faces.event.SystemEvent;
    import javax.faces.event.SystemEventListener;

    public class ChangeCountrySystemEventListener implements SystemEventListener {

        @ManagedProperty("#{country}")
        Country country;

        // getters and setters
        public Country getCountry() {
            return country;
        }

        public void setCountry(Country country) {
            this.country = country;
        }

        public ChangeCountrySystemEventListener(FacesContext fc) {
            super();
            System.out.println(">>>> ChangeCountrySystemEventListener.class :: Listener constructor invoked!!!");
        }

        @Override
        public void processEvent(SystemEvent se) {

            if (country != null) {
                country.setName("Sweden");
                System.out.println(">>>> ChangeCountrySystemEventListener.class :: SYSTEM EVENT PROCESSED... <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< ");
            } else if (country == null) {
                System.out.println(">>>> ChangeCountrySystemEventListener.class :: processEvent() > country managed property is EMPTY !!!!");
            }
        }

        @Override
        public boolean isListenerForSource(Object source) {
            return true; // needs to be set to true, otherwise "processEvent" won't be called...
        }

    }

Country.java

    package com.test.beans;

    import javax.annotation.PostConstruct;
    import javax.faces.application.Application;
    import javax.faces.bean.ManagedBean;
    import javax.faces.bean.SessionScoped;
    import javax.faces.context.FacesContext;

    @ManagedBean(name = "country", eager = true)
    @SessionScoped
    public class Country {

        private String name = "Norway";

        public Country() {
            System.out.println(">>>> Country constructor called...");
        }

        public String getName() {
            return name;
        }

        public void setName(String name) {
            this.name = name;
        }

        @PostConstruct
        public void init() {
            FacesContext fc = FacesContext.getCurrentInstance();
            Application app = fc.getApplication();
            app.subscribeToEvent(ChangeCountrySystemEvent.class, new ChangeCountrySystemEventListener(fc));
            System.out.println(">>>> Country.class :: app.subscribeToEvent() called... ");
        }
    }

Console output:

2017-04-02T21:49:51.392-0300|Info: JSF_TestProject was successfully deployed in 579 milliseconds.
2017-04-02T21:49:52.251-0300|Info: >>>> Country constructor called...
2017-04-02T21:49:52.277-0300|Info: >>>> ChangeCountrySystemEventListener.class :: Listener constructor invoked!!!
2017-04-02T21:49:52.277-0300|Info: >>>> Country.class :: app.subscribeToEvent() called...
2017-04-02T21:50:16.572-0300|Info: >>>> ChangeCountrySystemEvent.class :: constructor invoked!
2017-04-02T21:50:16.572-0300|Info: >>>> ChangeCountrySystemEventListener.class :: processEvent() > country managed property is EMPTY !!!!
2017-04-02T21:50:16.572-0300|Info: >>>> AppBean.publishEvent(ChangeCountrySystemEvent) fired... javax.faces.component.html.HtmlCommandButton@424c250c
Community
  • 1
  • 1
BustedSanta
  • 1,368
  • 7
  • 28
  • 55

1 Answers1

1

The ManagedProperty can be used on a field of a class annotated with ManagedBean to inject a value into this property.

If this annotation is present on a class that does not have the ManagedBean annotation, the implementation must take no action on this annotation.

Please see http://docs.oracle.com/javaee/6/api/javax/faces/bean/ManagedProperty.html

Since the class ChangeCountrySystemEventListener is not annotated with ManagedBean, no action is taken on the ManagedProperty field country and its null.

OTM
  • 656
  • 5
  • 8
  • thank you for your reply. Unfortunately, adding the ManagedBean annotation (and even SessionScoped) doesn't resolve the issue. Even if all four classes (AppBean, ChangeCountrySystemEvent, ChangeCountrySystemEventListener, Country) are annotated with ManagedBean, the issue persists. – BustedSanta Apr 03 '17 at 02:12
  • Please use the below code in the listener to access the country managed bean. – OTM Apr 03 '17 at 02:22
  • 1
    country = (Country) FacesContext.getCurrentInstance().getExternalContext().getSessionMap().get("country"); – OTM Apr 03 '17 at 02:31
  • Thanks very much. Your proposed solution worked for me. :) – BustedSanta Apr 05 '17 at 00:42