Solucionado (ver solução)

Importante

Você está vendo a versão anterior da nova experiência da Alura que estamos preparando para você. Em breve, ela ganha uma identidade visual novinha totalmente pensada em potencializar seus estudos!

Solucionado
(ver solução)
11
respostas

Injeção com valor null para o conversor

Boa tarde, quando injeto o EntityManager pelo CDI, não funciona, um nullpointexception acontece, mas quando uso o new funciona normal.

import javax.faces.component.UIComponent;
import javax.faces.context.FacesContext;
import javax.faces.convert.Converter;
import javax.faces.convert.FacesConverter;
import javax.persistence.EntityManager;

@FacesConverter("cargoConverter")
public class CargoConverter implements Converter {

        @Override
    public Object getAsObject(FacesContext context, UIComponent component, String valor) {
        Long id = Long.valueOf(valor);
        EntityManager em = new EntityFactory().createEntityManager();
        return em.find(Cargo.class, id);
    }

    @Override
    public String getAsString(FacesContext context, UIComponent component, Object object) {

        if (object != null) {
            return  ((Cargo) object).getId().toString();
        }
        return "";
    }

}
@ApplicationScoped
public class EntityFactory implements Serializable {

    private static final long serialVersionUID = 1L;

    @Produces
    @RequestScoped
    public EntityManager createEntityManager() {
        EntityManagerFactory emf = Persistence.createEntityManagerFactory("projeto");
        return emf.createEntityManager();
    }

    public void destroyEntityManager(@Disposes EntityManager entity) {
        if (entity.isOpen()) {
            entity.close();
        }
    }

}
11 respostas

Olá Gilmar, tudo bem?

tente mudar o escopo da classe EntityFactory para RequestScoped. Os escopos de quem produz deve ser igual ou menor que o de quem usa o metodo.

Gilmar tudo bem? Primeiramente o Samir é uma maquina de conhecimento, se ele falo vai dar certo kkk, mais tenho uma discussão construtiva aqui.

O porque dessa anotação ai?

@ApplicationScoped
public class EntityFactory implements Serializable {

No próprio metodo você já tá colocando a duração da sua requisição.

 @Produces
    @RequestScoped
    public EntityManager createEntityManager() {
        EntityManagerFactory emf = Persistence.createEntityManagerFactory("projeto");
        return emf.createEntityManager();
    }

Deve tar dando algum tipo de conflito essas 2 anotações ai, tira anotação da sua classe e deixa essa requestScoped no seu metodo, acho que não faz muito sentido do jeito que você tá fazendo, posso tar errado e falando besteira.

Mais tira ela e testa

Também não deu certo.

threw exception [null] with root cause
java.lang.NullPointerException
    at com.planner.desafio.converter.CargoConverter.getAsObject(CargoConverter.java:37)
    at com.sun.faces.renderkit.html_basic.HtmlBasicInputRenderer.getConvertedValue(HtmlBasicInputRenderer.java:171)
    at com.sun.faces.renderkit.html_basic.MenuRenderer.convertSelectOneValue(MenuRenderer.java:201)
    at com.sun.faces.renderkit.html_basic.MenuRenderer.getConvertedValue(MenuRenderer.java:318)
    at org.primefaces.component.selectonelistbox.SelectOneListboxRenderer.getConvertedValue(SelectOneListboxRenderer.java:43)
    at javax.faces.component.UIInput.getConvertedValue(UIInput.java:1045)
    at javax.faces.component.UIInput.validate(UIInput.java:975)
    at javax.faces.component.UIInput.executeValidate(UIInput.java:1248)
    at javax.faces.component.UIInput.processValidators(UIInput.java:712)
    at javax.faces.component.UIComponentBase.processValidators(UIComponentBase.java:1261)
    at javax.faces.component.UIForm.processValidators(UIForm.java:253)
    at javax.faces.component.UIComponentBase.processValidators(UIComponentBase.java:1261)
    at javax.faces.component.UIComponentBase.processValidators(UIComponentBase.java:1261)
    at javax.faces.component.UIViewRoot.processValidators(UIViewRoot.java:1195)
    at com.sun.faces.lifecycle.ProcessValidationsPhase.execute(ProcessValidationsPhase.java:76)
    at com.sun.faces.lifecycle.Phase.doPhase(Phase.java:101)
    at com.sun.faces.lifecycle.LifecycleImpl.execute(LifecycleImpl.java:198)
    at javax.faces.webapp.FacesServlet.service(FacesServlet.java:658)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:291)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
    at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:239)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
    at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:217)
    at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:106)
    at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:502)
    at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:142)
    at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:79)
    at org.apache.catalina.valves.AbstractAccessLogValve.invoke(AbstractAccessLogValve.java:616)
    at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:88)
    at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:518)
    at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1091)
    at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:673)
    at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1500)
    at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.run(NioEndpoint.java:1456)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
    at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
    at java.lang.Thread.run(Unknown Source)

Minhas tentativas:

  • Apenas o método anotado;
  • O bean que faz a chamada e o método com mesma anotação;
  • Tudo com a mesma anotação;

Quando tiro a injeção, e dou new funciona normal.

Que estranho o código que você usa quando da o erro?

list box que usa o converter

<!-- listbox (para seleção de cargos) -->
                <p:selectOneListbox id="cargos" value="#{promocaoBean.cargo}" converter="cargoConverter" onchange="submit()" >
                    <f:selectItem itemLabel="Selecione um cargo" itemDisabled="true" />
                    <f:selectItems value="#{promocaoBean.cargos}" var="cargo" itemLabel="#{cargo.descricao}" itemValue="#{cargo}"/>
                </p:selectOneListbox>

bean controler

@Named
@ViewScoped
public class PromocaoBean implements Serializable{

    private static final long serialVersionUID = 1L;

    @Inject
    private CargoRepository cargoRepository;

    @Inject
    private FuncionarioRepository funcionarioRepository;

    @Inject
    private AplicarPromocao aplicarPromocao;

    private Cargo cargo;

    private BigDecimal percentualDeAumento;

    private List<Funcionario> funcionarios;


    public PromocaoBean() {
      novo();
      zerarPercentual();
    }


    public void novo() {
        this.cargo = new Cargo();
    }


    public void zerarPercentual() {
        percentualDeAumento = BigDecimal.ZERO;
    }


    public void aumentarSalarios(){
        calcularSalarios();
        atualizarSalarios();
        atualizarCargo();
        zerarPercentual();
    }


    private void calcularSalarios() {
        funcionarios = aplicarPromocao.calcular(getFuncionarios(), getPercentualDeAumento());
    }


    private void atualizarSalarios(){
        funcionarioRepository.autualizarSalario(funcionarios);
    }


    private void atualizarCargo() {
        cargo = cargoRepository.buscarPor(cargo.getId());
    }


    public void setCargo(Cargo cargo) {
        this.cargo = cargo;
    }


    public Cargo getCargo() {
        return cargo;
    }


    public List<Cargo> getCargos(){
        return cargoRepository.listarTodos();
    }


    public List<Funcionario> getFuncionarios(){
         return cargo.getFuncionarios();
    }


    public BigDecimal getPercentualDeAumento() {
        return percentualDeAumento;
    }

    public void setPercentualDeAumento(BigDecimal percentualDeAumento) {
        this.percentualDeAumento = percentualDeAumento;
    }

}

Gilmar o seu cargo pode estar vindo null, tenta.

@Inject
 private Cargo cargo;

Gilmar, faz o seguinte:

no seu EntityFactory:

public class EntityFactory {


private static EntityManagerFactory emf = Persistence.createEntityManagerFactory("projeto");

    @Produces @RequestScoped
    public EntityManager getEntityManager() {
        return emf.createEntityManager();
    }

    public void close(@Disposes EntityManager manager){
        manager.close();
    }
}

e no seu converter:

@FacesConverter("cargoConverter")
public class CargoConverter implements Converter {

    @Inject
    private EntityManager manager;

    @Override
    public Object getAsObject(FacesContext context, UIComponent component, String valor) {
        Long id = Long.valueOf(valor);

    Cargo cargo =  em.find(Cargo.class, id);
    return cargo;     
}

    @Override
    public String getAsString(FacesContext context, UIComponent component, Object object) {

        if (object != null) {
            return  ((Cargo) object).getId().toString();
        }
        return "";
    }

}

veja se isso funciona, como o Alisson, falou pode ser que o objeto esteja vindo com o id null, porém acho difícil pois quando vc não injeta o EntityManager funciona.

Fiz suas alterações mesmo assim não funcionou.

A instância de EntityManager é sempre null ao ser injetada, é como se seu produtor não fosse encontrado, ou não fosse usado nesse contexto.

Posso está falando uma besteira, mas parece que o contexto que utiliza o converter é diferente do contexto que administra as injeções.

Gilmar, isso faz bastante sentido! O Faces Converter é gerenciado pelo JSF enquanto o factory com método produces é gerenciado pelo CDI. Tenta anotar o FacesConverter com @Named.

solução!

Oi Gilmar,

O problema não é na configuração do producer do entityManager, mas sim na integração entre JSF e CDI.

Como o converter é uma classe gerenciada pelo JSF, o CDI não consegue fazer a injeção e o atributo acaba ficando null.

Para funcionar, você precisa fazer com que o CDI gerencie o converter:

@Named
public class CargoConverter implements Converter {

    @Inject
    private EntityManager em;

        @Override
    public Object getAsObject(FacesContext context, UIComponent component, String valor) {
        Long id = Long.valueOf(valor);
        return em.find(Cargo.class, id);
    }

    @Override
    public String getAsString(FacesContext context, UIComponent component, Object object) {

        if (object != null) {
            return  ((Cargo) object).getId().toString();
        }
        return "";
    }

}

E no XHTML tem que utilizar Expression Language para indicar o converter:

<h:selectOneMenu converter="#{cargoConverter}">

Desse jeito deve funcionar.

Bons estudos!