Solucionado (ver solução)
Solucionado
(ver solução)
14
respostas

Dúvida CDI - ScopeMap

Pessoal, estou aplicando um pouco da implementação do projeto do curso em um projeto pessoal, usando o wildfly.

Estou tendo problemas em injetar as informações gravadas na sessão em um listener. Quando eu tento fazer:

RHServidor servidor = (RHServidor) sessionMap.get("usuarioLogado");

Sempre eu obtenho null. Só que antes de chegar neste ponto, eu já tinha colocado informação neste objeto.

sessionMap.put("usuarioLogado", this.servidor);

Eu até consigo obter este valor em outros pontos do sistema. Só não estou conseguindo no injetar este valor no phaseListener, que é um Restore View after.

Alguém saberia dizer qual seria o problema ou teria alguma ideia do que poderia ser?

Segue a implementação da minha classe Autorizador.

@SuppressWarnings("serial")
    public class Autorizador implements PhaseListener {

        @Inject @ScopeMap(Scope.SESSION)
        private transient Map<String, Object> sessionMap;

        @Inject
        protected FacesContext context;

        @Inject
        private NavigationHandler handler;


         public void autoriza() {
                String nomePagina = context.getViewRoot().getViewId();

                System.out.println(nomePagina);

                if ("/login.xhtml".equals(nomePagina)) {
                    return;
                }

                RHServidor servidor = (RHServidor) sessionMap.get("usuarioLogado");

                if (servidor != null) {
                    return;
                }

                // redirecionamento para login.xhtml

                handler.handleNavigation(context, null, "/login?faces-redirect=true");
                context.renderResponse();
            }


        @Override
        public void afterPhase(PhaseEvent arg0) {
            autoriza();

        }

        @Override
        public void beforePhase(PhaseEvent arg0) {
            //autoriza();

        }

        @Override
        public PhaseId getPhaseId() {
            // TODO Auto-generated method stub
            return PhaseId.RESTORE_VIEW;
        }


}
14 respostas

Fala aí Emerson, blz?

Você está usando a mesma abordagem do curso, onde eu tenho uma lib com várias facilidades e depois importo ela no projeto web?

Não Fernando, estou colocando dentro do mesmo projeto.

Fernando, se ao invés de eu fazer:

@Inject @ScopeMap(Scope.SESSION)
private transient Map<String, Object> sessionMap2;

 RHServidor servidor2 = (RHServidor) sessionMap2.get("usuarioLogado");

eu fizer:

@Inject
protected FacesContext context;

Map<String, Object> sessionMap = context.getExternalContext().getSessionMap();
RHServidor servidor = (RHServidor) sessionMap.get("usuarioLogado");

tudo funciona

Estranho, manda o código da sua anotação @Scoped e do produtor dela por favor.

ScopeMap

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

import javax.inject.Qualifier;

@Qualifier
@Target({ElementType.METHOD,ElementType.PARAMETER, ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
public @interface ScopeMap {
    ScopeMap.Scope value();

    enum Scope{
        REQUEST,SESSION, APPLICATION;
    }
}

Produtor do ScopeMap


import java.util.Map;

import javax.enterprise.context.RequestScoped;
import javax.enterprise.inject.Produces;
import javax.faces.application.NavigationHandler;
import javax.faces.context.ExternalContext;
import javax.faces.context.FacesContext;

import br.jus.trt13.sisvoto.annotation.ScopeMap;
import br.jus.trt13.sisvoto.annotation.ScopeMap.Scope;


public class JSFFactory {

    @RequestScoped
    @Produces
    public FacesContext getFacesContext() {
        return FacesContext.getCurrentInstance();
    }


    @Produces
    @ScopeMap(Scope.SESSION)
    public Map<String, Object> sessionMap(){
        return getExternalContext().getSessionMap();
    }

    private ExternalContext getExternalContext() {
        return getFacesContext().getExternalContext();
    }

    @Produces
    @RequestScoped
    public NavigationHandler getNavigationHandler(){
        return getFacesContext().getApplication().getNavigationHandler();
    }


}

Aparentemente está tudo certo Emerson, por que você precisa que o atributo seja transient ?

Já tentou assim:

@Inject @ScopeMap(Scope.SESSION)
private Map<String, Object> sessionMap2;

Isso foi só um teste que fiz Fernando. Quando eu tiro o transient o erro persiste. :(

Estranho. Vamos tentar isolar o problema.

Creio que no seu projeto não tenha mais nada que produza Map<String,Object>, certo? Se sim tire o qualificador do produtor e injete sem o qualificador.

Veja se assim funciona.

Acabei de testar Fernando dá o mesmo erro.

Um dado interessante é que o objeto sessionMap obtido de:

Map<String, Object> sessionMap = context.getExternalContext().getSessionMap();

tem o seguinte valor:

{com.sun.faces.application.view.activeViewContexts={0={}, 984119934={WELD%ManagedBean%Sisvoto.war|Sisvoto.war/WEB-INF/classes|br.jus.trt13.sisvoto.bean.UsuarioBean|null|false=com.sun.faces.application.view.ViewScopeContextObject@7b018081}}, com.sun.faces.renderkit.ServerSideStateHelper.LogicalViewMap={-5205793769675279145={-8583682000300471978=[Ljava.lang.Object;@589440a4}}, org.jboss.weld.context.conversation.ConversationIdGenerator=org.jboss.weld.context.conversation.ConversationIdGenerator@55681a29, org.jboss.weld.context.ConversationContext.conversations={}, usuarioLogado=br.jus.trt13.mentorh.entity.RHServidor@2bb79b7e, javax.faces.request.charset=UTF-8, com.sun.faces.application.view.activeViewMaps={7dfec6b3-0b99-44d2-a259-4c9d15e5a605={}}}

Já o objeto sessionMap obtido de:

@Inject
private Map<String, Object> sessionMap2;

não tem nada: {}

Em outras telas(beans), esta injeção funciona perfeitamente. Será que não tenha haver que seja porque estou tentando injetar em um PhaseListener e então quando ele vai criar o objeto, ele não tem todas as dependências prontas?

solução!

O fato de estar injetando no PhaseListener pode ter haver sim. Mas se você está conseguindo injetar outras coisas, deveria injetar esse também.

Se fosse pelo fato das dependências não estarem prontas podemos simular com uma injeção Lazy:

@Inject @ScopeMap(Scope.SESSION)
private Instance<Map<String, Object> sessionMap;

O Instance faz uma injeção lazy, e dentro do método que você precisa usar o objeto Map<String. Object> você faz um get. Ao fazer o get ele faz a injeção.

Bingo Fernando. Deu certo.

Eu usei a definição

@Inject @ScopeMap(Scope.SESSION)
private Instance<Map<String, Object>> sessionMap2;

e usei assim na classe Autorizador

Map<String, Object> mapa = sessionMap2.get();
RHServidor servidor2 = (RHServidor) mapa.get("usuarioLogado");

No entanto, qual seria a explicação técnica para isso já que no projeto do curso funciona?

Que bom que funcionou.

Então no projeto do curso não injetamos nada no PhaseListener. /=

https://github.com/alura-cursos/alura-cdi/tree/master/alura-lib/src/main/java/br/com/alura/alura_lib/jsf/phaselistener

A explicação mais cabível que encontrei foi que o ExternalContext não instanciou uma implementação de Map até o inicio do PhaseListener.

Que foi basicamente o que você comentou.

Que bom que funcionou.

Então no projeto do curso não injetamos nada no PhaseListener. /=

https://github.com/alura-cursos/alura-cdi/tree/master/alura-lib/src/main/java/br/com/alura/alura_lib/jsf/phaselistener

A explicação mais cabível que encontrei foi que o ExternalContext não instanciou uma implementação de Map até o inicio do PhaseListener.

Que foi basicamente o que você comentou.

Verdade Fernando, já tinha esquecido do projeto. Fui até rever aqui. Obrigado pela ajuda!