Solucionado (ver solução)
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!