@Inject в фильтре не работает - PullRequest
1 голос
/ 17 октября 2011

Насколько я знаю, CDI должен работать в фильтрах, но я не могу заставить его работать на меня.Код выглядит следующим образом:

@WebFilter(filterName="authFilter",servletNames={"Faces Servlet"})
public class AuthFilter implements Filter {

    @Inject UserBean userBean;

    public AuthFilter() {
    }

    @Override
    public void doFilter(ServletRequest request, ServletResponse response,
            FilterChain chain) throws IOException, ServletException {
        userBean.doSomething(); // Causes NullPointerException
        chain.doFilter(request, response);
    }
}  

UserBean.class

@Stateless
public class UserBean extends JPABean{
// Omitted
}

CDI включен, и инъекция работает, если я делаю это вручную через InitialContext.doLookup () или в сервлете, вот так:

@WebServlet(name = "MyServlet", urlPatterns = {"/MyPage"})
@ServletSecurity(@HttpConstraint(rolesAllowed={"somerole"}))
public class MyServlet extends HttpServlet {

    @Inject private UserBean userBean;

    @Override
    protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        userBean.doStuff(); // Works
        response.sendRedirect(request.getContextPath());
}

Не работает CDI в фильтрах?В таком случае, почему бы и нет?Если это так, что я могу делать не так?

1 Ответ

3 голосов
/ 10 сентября 2012

В этом примере я вставляю боб CODI @ViewAccessScoped (RegisterView) в фильтр, устанавливаю свойство в бине и перехожу к представлению, которое использует бин. Когда страница загружается, я вижу имя пользователя "fred". Это также работает с @SessionScoped (но не с @RequestScoped или @ViewScoped). Я думаю, что динамическое внедрение требуется для безопасности потока, потому что в веб-контейнере есть только один экземпляр фильтра и, следовательно, все переменные экземпляра.

Проблема, которую это решает, заключается в том, что сервлет Faces не запускается при выполнении фильтра, поэтому FacesContext отсутствует. Умная работа, проделанная getFacesContext (), которую я извлек прямо из этого блога с 2004 года, я не знаю, для кого он был написан, и в течение нескольких лет не было добавлено никакого контента, но если кто-то знает, пусть я знаю! Может быть, это был BalusC в его молодые дни. Он использует статический внутренний класс для доступа к защищенному методу FacesServlet # setCurrentInstance ().

Не работает, если вы используете response.sendRedirect ().

package uk.co.myco.jsfbeans.helper;

import java.io.IOException;
import javax.enterprise.inject.Instance;
import javax.faces.FactoryFinder;
import javax.faces.component.UIViewRoot;
import javax.faces.context.FacesContext;
import javax.faces.context.FacesContextFactory;
import javax.faces.lifecycle.Lifecycle;
import javax.faces.lifecycle.LifecycleFactory;
import javax.inject.Inject;
import javax.servlet.DispatcherType;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import uk.co.sportquest.entities.User;
import uk.co.sportquest.general.BaseClass;
import uk.co.sportquest.general.Log;
import uk.co.sportquest.jsfbeans.RegisterView;

/*
 * @author Brendan Healey
 * 
 * http://www.thoughtsabout.net/blog/archives/000033.html
 * 
 */

@WebFilter(filterName = "SocialAuthFilter", urlPatterns = {"/pages/socialAuthFilter.xhtml"},
dispatcherTypes = {DispatcherType.FORWARD, DispatcherType.ERROR, DispatcherType.REQUEST, DispatcherType.INCLUDE})
public class SocialAuthFilter extends BaseClass implements Filter {

    @Inject
    private Instance<RegisterView> rvDynamic;

    private ServletContext servletContext;

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        servletContext = filterConfig.getServletContext();
    }

    @Override
    public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {

        HttpServletRequest request = (HttpServletRequest) req;
        HttpServletResponse response = (HttpServletResponse) res;

        Log.log("testFilter: " + request.getPathInfo());

        FacesContext ctx = getFacesContext(req, res);

        RegisterView registerView;
        registerView = rvDynamic.get();

        User user = new User();
        user.setUserName("fred");
        registerView.setInputUser(user);

        FacesContext.getCurrentInstance().getExternalContext().redirect("/pages/register.xhtml");

    }

    @Override
    public void destroy() {
    }

    private abstract static class InnerFacesContext extends FacesContext {

        protected static void setFacesContextAsCurrentInstance(FacesContext facesContext) {
            FacesContext.setCurrentInstance(facesContext);
        }
    }

    private FacesContext getFacesContext(ServletRequest request, ServletResponse response) {
        // Try to get it first  
        FacesContext facesContext = FacesContext.getCurrentInstance();
        if (facesContext != null) {
            return facesContext;
        }

        FacesContextFactory contextFactory = (FacesContextFactory) FactoryFinder.getFactory(FactoryFinder.FACES_CONTEXT_FACTORY);
        LifecycleFactory lifecycleFactory = (LifecycleFactory) FactoryFinder.getFactory(FactoryFinder.LIFECYCLE_FACTORY);
        Lifecycle lifecycle = lifecycleFactory.getLifecycle(LifecycleFactory.DEFAULT_LIFECYCLE);

        // Either set a private member servletContext = filterConfig.getServletContext(); 
        // in you filter init() method or set it here like this:
        // ServletContext servletContext = ((HttpServletRequest)request).getSession().getServletContext();
        // Note that the above line would fail if you are using any other protocol than http

        // Doesn't set this instance as the current instance of FacesContext.getCurrentInstance 
        facesContext = contextFactory.getFacesContext(servletContext, request, response, lifecycle);

        // Set using our inner class
        InnerFacesContext.setFacesContextAsCurrentInstance(facesContext);

        // set a new viewRoot, otherwise context.getViewRoot returns null
        UIViewRoot view = facesContext.getApplication().getViewHandler().createView(facesContext, "");
        facesContext.setViewRoot(view);

        return facesContext;
    }

}
...