Usando o CDI em vez de @ManagedBean: UnproxyableResolutionException porque a Super Class não tem construtor de não-Args

StackOverflow https://stackoverflow.com/questions/3840240

  •  27-09-2019
  •  | 
  •  

Pergunta

Estou tentando usar o CDI para o meu aplicativo JSF/Java EE. Eu tenho a seguinte hierarquia de classe:

/**
 * base controller class
 * also contains some final methods and an inner enum class declaration
 */
public abstract class AbstractCrudController<K, E> implements Serializable {
  private Class<E> entityClass;

  public AbstractCrudController(Class<E> entityClass) {
    this.entityClass = entityClass;
  }

  // ...
}


import javax.enterprise.context.SessionScoped;
import javax.inject.Named;

@Named
@SessionScoped
public class CategoryController extends AbstractCrudController<Long, Category> implements Serializable {
  public CategoryController() {
    super(Category.class);
  }
  //...
}

Quando tento implantar o aplicativo no GF 3.1, recebo a seguinte exceção CDI/solda:

Severo: exceção ao carregar o aplicativo: Weld-001435 Classe de feijão com escopo normal com.web.abstractcrudcontroller não é procurável porque não possui construtor de não-Args. org.jboss.weld.exceptions.unproxyableResolutionException: Weld-001435 Classe de feijão com escopo normal com.web.abstractcrudcontroller não é procurável porque não possui o construtor não-Args. Org.jboss.weld.util.proxies.getUnProxyableClassexception (proxies.java:215) em org.jboss.weld.util.proxies.getUnProxyableTypeexception (proxies.java:166) em org.jboss. (Proxies.java:191) em org.jboss.weld.bootstrap.validator.validateBean (validator.java:134) em org.jboss.weld.bootstrap.validator.validateribean (validator.java:148) em org.jboss. weld.bootstrap.Validator.validateBeans(Validator.java:363) at org.jboss.weld.bootstrap.Validator.validateDeployment(Validator.java:349) at org.jboss.weld.bootstrap.WeldBootstrap.validateBeans(WeldBootstrap.java: 416) em org.glassfish.weld.welddeployer.event (WeldDeployer.java:178) em org.glassfish.kernel.event.eventsimpl.send (eventsimplic.java:128) em org.glassfish.innstall.datafina.AppLination (ApplicationInfo.java:265) em com.sun.enterprise.v3.server.applicationlifecycle.deploy (ApplicationlifeCycle.java:402) em com.sun.enterprise.v3.server.ApplicationLifecycle.deplo org.glassfish.deployment.admin.deployCommand.execute (implantCommand.java:351) em com.sun.enterprise.v3.admin.commandrunnerimpl $ 1.execute (commandrunnerimpl.java:360) em com.sun.erMerPrise (com comandrunnerimpl.java:360) em com.sun.erMerPrise ( .CommandRunnerImpl.doCommand(CommandRunnerImpl.java:375) at com.sun.enterprise.v3.admin.CommandRunnerImpl.doCommand(CommandRunnerImpl.java:1072) at com.sun.enterprise.v3.admin.CommandRunnerImpl.access$1200(CommandRunnerImpl. java: 101) em com.sun.enterprise.v3.admin.Commandrunnerimpl $ ExecutionContext.execute (commandRunnerimpl.java:1221) em com.sun.enterprise.v3.admin.commandrunnerImpl $ ExecutionConxt.extenxt.exection.v3.admin.ComMRunnerImpl $ em com.sun.enterprise.v3.admin.adminadapter.docommand (adminadapter.java:375) em com.sun.enterprise.v3.admin.adminadapter.service (adminadapter.java:209) em com.sun.gra. .http11.grizzlyadapter.service (grizzlyadapter.java:166) em com.sun.enterprise.v3.server.hk2dispatcher.dispath (hk2dispatcher.java:117) AT.SUNEN.ENTERSERSERPRISE.VERVIDES.IMPLES.IMPERTIDES.IMPRICES.IMPRICES.JAVA: rvice (contingermapper.java:234) em com.sun.grizzly.http.processortsork.invokeadapter (processortosk.java:824) em com.sun.grizzly.http.processortosk.doprocess (processortosk.java:721) .Grizzly.http.processorTask.process (processortosk.java:1014) em com.sun.grizzly.http.defaultprotocolfilter.execute (defaultProtocolfilter.java:220) em com.sun.grizzly.defaultocolterColter.java:220) em com.sun.grizzly.defaultColcolter. ) at com.sun.grizzly.DefaultProtocolChain.execute(DefaultProtocolChain.java:102) at com.sun.grizzly.DefaultProtocolChain.execute(DefaultProtocolChain.java:88) at com.sun.grizzly.http.HttpProtocolChain.execute(HttpProtocolChain. java:76) at com.sun.grizzly.ProtocolChainContextTask.doCall(ProtocolChainContextTask.java:53) at com.sun.grizzly.SelectionKeyContextTask.call(SelectionKeyContextTask.java:57) at com.sun.grizzly.ContextTask.run(ContextTask .Java: 69) em com.sun.grizzly.util.abstractThreadpool $ worker.dowork (abstracthreadpool.java:530) em com.sun.grizzly.util.abst ractThreadpool $ worker.run (abstracthreadpool.java:511) em java.lang.thread.run (thread.java:637)

Mesmo se eu adicionar um construtor sem args à classe base, a Weld ainda reclama com a mesma exceção de que a classe não é procurável porque possui métodos finais. Por que a solda me força a mudar meu design de classe? Tudo funcionou bem usando a anotação JSF @ManagedBean.

Eu apreciaria qualquer ajuda. Obrigado, Theo

Foi útil?

Solução

Por que a solda me força a mudar meu design de classe? Tudo funcionou bem usando a anotação JSF @ManagedBean.

Bem, Weld/CDI não funciona da mesma maneira. Meu entendimento é que, quando você usa injeção para obter uma referência a um feijão, o que você recebe é a maioria dos casos um objeto de proxy. Esse objeto de proxy submasca seu feijão e substitui os métodos para implementar a delegação. E isso introduz algumas restrições nas classes que o CDI pode proxy.

A especificação CDI coloca assim:

5.4.1. Tipos de feijão desprezíveis

Certos tipos de feijão legal não podem ser procurados pelo contêiner:

  • classes que não têm um construtor não privado sem parâmetros,
  • classes que são declaradas finais ou têm métodos finais,
  • tipos primitivos,
  • e tipos de matriz.

Se um ponto de injeção cujo tipo declarado não puder ser proxado pelo contêiner resolver um feijão com um escopo normal, o contêiner detecta automaticamente o problema e o trata como um problema de implantação.

Minha sugestão seria tornar os métodos não finais.

Referências

  • Especificação CDI
    • Seção 5.4. "Proxies de clientes"
    • Seção 5.4.1 "Tipos de feijão insuficientes"
    • Seção 6.3. "Escopos e pseudo-escopos normais"

Outras dicas

Estou em processo de migração do JSF gerenciado com feijões gerenciados pelo CDI, e acabei de confirmar que sou capaz de usar super Com sucesso em um CDI Bean descendente (com qualificador 'personalizado' @Descender) que 'estende' um feijão CDI ancestral (com o qualificador @default).

CDI Bean Ancestor com @Default Qualifier:

@Default
@Named("pf_pointOfContactController")
@SessionScoped
public class pf_PointOfContactController implements Serializable {

Ancestral Bean tem o seguinte:

@PostConstruct
protected void init() {

CDI Bean Descendente com @Descender Qualifier:

@Descendant
@Named("pf_orderCustomerPointOfContactController")
@SessionScoped
public class pf_OrderCustomerPointOfContactController extends pf_PointOfContactController {

Descendente Bean tem o seguinte:

@PostConstruct
public void init(){
    super.init();

Eu tive que adicionar/usar super.init (), porque os métodos no Ancestor CDI Bean estavam levantando o NullPointerException, uma vez que o @PostConstruct do Ancestor Bean não é executado no CDI @Descender Bean.

Eu vi/ouvi/li que é recomendável usar @postconstruct em vez do método construtor ao usar o CDI, para que o construtor do ancestral Bean tenha a lógica de 'inicialização', e o construtor do Ancestor Bean foi automaticamente chamado/executado ao usar feijões gerenciados por JSF.

Como a resposta aceita é correta, mas incompleta, acho que posso adicionar meus dois centavos apenas para futuros leitores.

O problema que o OP encontrou pode ser resolvido de duas maneiras:

  1. Removendo final palavra -chave dos métodos e a classe em si
  2. Marcando essa "classe não -fornecida" com @Singleton ou @Dependent pseudo-escopo (é claro se faz sentido). Ele funcionará porque o CDI não cria um objeto proxy para feijões pseudo-escassos.

No caso de uso do OP, a segunda abordagem IMHO foi recomendada, pois os controladores definitivamente podem ser marcados como singletons.

Espero que ajude alguém

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top