@ManagedProperty in a Spring managed bean is null

Alexander Bering picture Alexander Bering · Sep 3, 2012 · Viewed 13.6k times · Source

I've some trouble with injecting one managedbean in another by defining a managedproperty. I'm googling and stackoverflowing now for 3 days, but with no result...

I'm developing with eclipse 4.2 and deploying to an integrated Tomcat 7

So, can anybody tell me, why my property is null?

pom.xml

<properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <spring.version>3.0.5.RELEASE</spring.version>
        <java.version>1.6</java.version>
    </properties>    
<dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-web</artifactId>
            <version>${spring.version}</version>
        </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-expression</artifactId>
        <version>${spring.version}</version>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-orm</artifactId>
        <version>${spring.version}</version>
        <type>jar</type>
        <scope>compile</scope>
    </dependency>

web.xml

    <web-app version="3.0" xmlns="http://java.sun.com/xml/ns/javaee" 
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation=" 
    http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd">
  <context-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>/WEB-INF/applicationContext*.xml</param-value>
  </context-param>
  <listener>
    <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
  </listener>

I have set the beans in applicationContext for scanning @Autowired annotation. (Yes, i tried it without beans in applicationContext, but ManagedProperty will not be set, too.)

applicationContext.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:context="http://www.springframework.org/schema/context"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:tx="http://www.springframework.org/schema/tx"
    xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd
    http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd">

<context:annotation-config />

<context:component-scan base-package="myPackage" />

<bean class="org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor"/>

<bean class="myPackage.dao.UserDao" id="userDao" />
<bean class="myPackage.dao.WorldDao" id="worldDao" />
<bean class="myPackage.dao.BuildingTypeDao" id="buildingTypeDao" />
<bean class="myPackage.dao.BuffTypeDao" id="buffTypeDao" />
<bean class="myPackage.dao.ClanDao" id="clanDao" />

<bean class="myPackage.bean.MainBean" id="mainBean" />
<bean class="myPackage.bean.UserBean" id="userBean" />
<bean class="myPackage.bean.AdminBean" id="adminBean" />

MainBean

package myPackage.bean;
import java.io.Serializable;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.SessionScoped;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import myPackage.model.MainModel;

@ManagedBean
@SessionScoped
public class MainBean implements Serializable {

private static final long serialVersionUID = 1L;

private static final Logger logger = LoggerFactory.getLogger(MainBean.class);

private MainModel model;

/**
 * @return the model
 */
public MainModel getModel() {
    if (model == null) {
        model = new MainModel();
    }
    return model;
}

/**
 * @param model the model to set
 */
public void setModel(MainModel model) {
    this.model = model;
    }
}

UserBean

package myPackage.bean;

import java.io.Serializable;

import javax.faces.application.FacesMessage;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.ManagedProperty;
import javax.faces.bean.RequestScoped;
import javax.faces.context.FacesContext;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;

import myPackage.dao.UserDao;
import myPackage.entity.User;

@ManagedBean
@RequestScoped
public class UserBean implements Serializable {

private static final long serialVersionUID = 1L;

private static final Logger logger = LoggerFactory.getLogger(UserBean.class);

@ManagedProperty(value="#{mainBean}")
private MainBean mainBean;

@Autowired
private UserDao userDao;

/**
 * @return the mainBean
 */
public MainBean getMainBean() {
    return mainBean;
}

/**
 * @param mainBean the mainBean to set
 */
public void setMainBean(MainBean mainBean) {
    this.mainBean = mainBean;
}

public String doLogin() {
    User user = userDao.getUserByUsernameAndPassword(getMainBean().getModel().getUser().getUsername(), getMainBean().getModel().getUser().getPassword());
    if (user != null) {
        getMainBean().getModel().setUser(user);
        logger.info("User '"+getMainBean().getModel().getUser().getUsername()+"' logged in");
        getMainBean().getModel().setSelectedTab(0);
    } else {
        FacesContext.getCurrentInstance().addMessage(null, new FacesMessage(FacesMessage.SEVERITY_ERROR,"Login failed", "Username and/or password wrong!"));
        logger.warn("User '"+getMainBean().getModel().getUser().getUsername()+"' login failed");
    }
    return null;
}

UserDao

package myPackage.dao;

import java.util.List;

import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.Query;

import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Transactional;

import myPackage.entity.User;

@Repository
public class UserDao {

@PersistenceContext
private EntityManager entityManager;

@Transactional
public void save(User user) {
    if (user.getId() == null) {
        entityManager.persist(user);    
    } else {
        entityManager.merge(user);
    }
}

@SuppressWarnings("unchecked")
public List<User> list() {
    return entityManager.createQuery("select u from User u")
            .getResultList();
}

public User getUserByUsername(String username) {
    try {
        Query q = entityManager.createQuery("select u from User u where u.username = :username");
        q.setParameter("username", username);
        User u = (User) q.getSingleResult();
        return u;
    } catch (Exception e) {
        return null;
    }
}

public User getUserByUsernameAndPassword(String username, String password) {
    try {
        Query q = entityManager.createQuery("select u from User u where u.username = :username and u.password = :password");
        q.setParameter("username", username);
        q.setParameter("password", password);
        User u = (User) q.getSingleResult();
        return u;
    } catch (Exception e) {
        return null;
    }
}

@Transactional
public User getUserById(Long id) {
    return entityManager.find(User.class, id);
}

@Transactional
public void delete(User user) {
    entityManager.remove(user);
}

public void deleteById(Long id) {
    delete(getUserById(id));
}

}

And now the Exception...

Caused by: java.lang.NullPointerException
    at myPackage.bean.UserBean.doLogin(UserBean.java:47)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
    at java.lang.reflect.Method.invoke(Method.java:597)

Line 47:

    User user = userDao.getUserByUsernameAndPassword(getMainBean().getModel().getUser().getUsername(), getMainBean().getModel().getUser().getPassword());

Debugging shows that getMainBean() returns null.

I'm open for suggests to improve my concept!

Answer

axtavt picture axtavt · Sep 3, 2012

Your JSF backing beans (MainBean and UserBean) should be managed either by JSF or by Spring, but not by both of them.

If your beans are managed by JSF:

  • You annotate them with @ManagedBean and @...Scoped
  • You don't need to declare them in applicationContext.xml
  • You use @ManagedProperty instead of @Autowired, even if you need to inject beans managed by Spring (don't forget setters, @ManagedProperty requires it):

    @ManagedProperty("#{userDao}")
    private UserDao userDao;
    

If your beans are managed by Spring:

  • You declare them in applicationContext.xml with appropriate scopes (view scope is not supported)
  • You don't need @ManagedBean and @...Scoped
  • You use @Autowired instead of @ManagedProperty and you cannot inject beans managed by JSF this way

In both cases you need to configure Spring-JSF bridge in faces-context.xml:

<application>
    <el-resolver>
        org.springframework.web.jsf.el.SpringBeanFacesELResolver
    </el-resolver>
</application>