mousouchop
mousouchop

Reputation: 195

Trouble with simple CDI Injection... "Passivation" related error when using @Inject in SessionScoped Controller bean

Okay— I am assuming I am making a very obvious mistake here— but I can’t seem to find my answer through the several Google/SO searches I have done. My background with Java programming is heavily JSF based, and at work I only have experience using Faces to manage my beans (using the @Managed annotation). However, I am working on a personal project in which I am trying to use CDI for the first time. I am having trouble injecting a Service bean into a SessionScoped controller bean… It’s odd because I inject the same service bean into a different RequestScoped bean no problem… I don’t see what I am missing. I have the SessionScoped bean implementing Serializable, yet I am still getting the following error when I try to deploy, ONLY once I have added an @Inject variable to the bean (without which the bean will be pretty useless…): Caused by: org.apache.webbeans.exception.WebBeansConfigurationException: Passivation capable beans must satisfy passivation capable dependencies. Here’s a bit of my service and controller beans code:

UserService.java

import ds.nekotoba.model.User;
import java.util.Date;
import java.util.List;
import javax.enterprise.context.RequestScoped;
import javax.enterprise.inject.Produces;
import javax.inject.Inject;
import javax.inject.Named;
import javax.persistence.EntityManager;
import org.apache.deltaspike.jpa.api.transaction.Transactional;
import org.apache.shiro.authc.credential.DefaultPasswordService;
import org.apache.shiro.authc.credential.HashingPasswordService;
import org.apache.shiro.crypto.hash.Hash;

@Named
@Transactional//Makes all methods in bean transactional
public class UserService {

    @Inject
    private EntityManager em;

    public User findById(Long id) {
        return em.find(User.class, id);
    }

    public User findByUsername(String username) {
        return em.createNamedQuery("User.findByUsername", User.class)
                .setParameter("username", username)
                .getSingleResult();
    }

    public User find(String username, String password) {
        List<User> found = em.createNamedQuery("User.find", User.class)
                .setParameter("username", username)
                .setParameter("password", password)
                .getResultList();
        return found.isEmpty() ? null : found.get(0);
    }

    @Produces
    @Named("users")
    @RequestScoped
    public List<User> list() {
        return em.createNamedQuery("User.list", User.class).getResultList();
    }

    public Long create(User user) {
        ….
    }

    public void update(User user){
        em.merge(user);
    }

    public void delete(User user){
        em.remove(em.contains(user) ? user : em.merge(user));
    }
}

LoginController.java Note: The @Inject calls in this bean work no problem!

import ds.nekotoba.model.User;
import ds.nekotoba.service.UserService;
import ds.nekotoba.util.Globals;
import java.io.IOException;
import javax.enterprise.context.RequestScoped;
import javax.inject.Inject;
import javax.inject.Named;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.web.util.SavedRequest;
import org.apache.shiro.web.util.WebUtils;
import org.omnifaces.util.Faces;
import org.omnifaces.util.Messages;

@Named(value="login")
@RequestScoped
public class LoginController {

    public LoginController() {
    }

    @Inject ProfileController profile;
    @Inject UserService userService;

    //Variables
    private String username;
    private String password;
    private boolean remember;

    //<editor-fold desc="Getters/Setters">
    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    public boolean isRemember() {
        return remember;
    }

    public void setRemember(boolean remember) {
        this.remember = remember;
    }
    //</editor-fold>

    public void submit() throws IOException {
        try {//Attempt login
            SecurityUtils.getSubject().login(new UsernamePasswordToken(username, password, remember));
        } catch (AuthenticationException ae) {
            Messages.addGlobalError("不明なユーザ、また試してみてください。");
            ae.printStackTrace();
        }

        //If successful, set User in ProfileController, get full user info 
        if(SecurityUtils.getSubject().isAuthenticated()){
            User user = new User();
            user.setUsername(username);
            user.setPassword(password);
            profile.setUserInfo(user);
            //profile.refreshUserInfo(); //COMMENTED OUT DUE TO ERROR INJECTED IN ProfileController.java
        }

        //Redirect to intended page
        SavedRequest savedRequest = WebUtils.getAndClearSavedRequest(Faces.getRequest());
        Faces.redirect(savedRequest != null ? savedRequest.getRequestUrl() : Globals.HOME_URL);
    }

}

ProfileController.java (The error mentioned above manifests once I use any @Inject calls in this bean…)

import ds.nekotoba.model.User;
import ds.nekotoba.service.UserService;
import java.io.Serializable;
import javax.enterprise.context.SessionScoped;
import javax.inject.Inject;
import javax.inject.Named;

@Named(value="profile")
@SessionScoped
public class ProfileController implements Serializable {

    @Inject UserService userService;//CAUSES ERROR MENTIONED ABOVE

    //Variables
    private User userInfo;


    public ProfileController() {
    }

    public void refreshUserInfo() {
        userInfo = userService.findByUsername(userInfo.getUsername());
    }

    //<editor-fold desc="Getters/Setters">
    public User getUserInfo() {
        return userInfo;
    }

    public void setUserInfo(User userInfo) {
        this.userInfo = userInfo;
    }
    //</editor-fold>
}

Like I said, I am a new-comer to CDI injection, so I am sure I am missing something obvious… I just can’t figure it out. Any help would be greatly appreciated.

Other Project Info:
JSF 2.2
JPA 2.0
TomEE 1.7.1
OmniFaces 1.8.1
Apache Shiro 1.3.0-SNAPSHOT
Apache DeltaSpike (could this be a conflicting point?)

Upvotes: 0

Views: 1608

Answers (1)

Harald Wellmann
Harald Wellmann

Reputation: 12855

Foo implements Serializable is necessary but not sufficient for Foo to be serializable. All members of Foo also have to be serializable.

In your case, ProfileController is serializable, but its UserService member is not.

Upvotes: 2

Related Questions