简单的 CDI 注入有问题... "Passivation" 在 SessionScoped Controller bean 中使用 @Inject 时出现相关错误

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

好吧——我假设我在这里犯了一个非常明显的错误——但我似乎无法通过我所做的几次 Google/SO 搜索找到我的答案。我的 Java 编程背景主要基于 JSF,在工作中我只有使用 Faces 管理 bean 的经验(使用 @Managed 注释)。但是,我正在做一个个人项目,这是我第一次尝试使用 CDI。我在将服务 bean 注入到 SessionScoped 控制器 bean 时遇到问题……这很奇怪,因为我将相同的服务 bean 注入到不同的 RequestScoped bean 没问题……我看不出我错过了什么。我有 SessionScoped bean 实现 Serializable,但是当我尝试部署时我仍然收到以下错误,ONLY 一旦我添加了 @Inject bean 的变量(没有它,bean 将毫无用处……):Caused by: org.apache.webbeans.exception.WebBeansConfigurationException: Passivation capable beans must satisfy passivation capable dependencies. 这是我的一些服务和控制器 bean 代码:

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 注意:这个 bean 中的 @Inject 调用没有问题!

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(一旦我在这个 bean 中使用任何 @Inject 调用就会出现上述错误...)

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>
}

就像我说的,我是 CDI 注入的新手,所以我确信我遗漏了一些明显的东西……我就是想不通。任何帮助将不胜感激。

其他项目信息:
JSF 2.2
JPA 2.0
TomEE 1.7.1
OmniFaces 1.8.1
Apache Shiro 1.3.0-SNAPSHOT
Apache DeltaSpike(这会是一个矛盾点吗?)

Foo implements Serializable 是必要的但不足以使 Foo 可序列化。 Foo 的所有成员也必须是可序列化的。

在你的例子中,ProfileController 是可序列化的,但它的 UserService 成员不是。