Usando CDI en lugar de @ManagedBean: UnproxyableResolutionException porque superclase no tiene ningún constructor-args
-
27-09-2019 - |
Pregunta
Estoy tratando de utilizar CDI para aplicaciones Java EE mi JSF /. Tengo la siguiente jerarquía de clases:
/**
* 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);
}
//...
}
Cuando intento de implementar la aplicación en GF 3.1, se produce la siguiente excepción CDI / Weld:
GRAVES: Excepción durante la carga de la aplicación: Weld-001435 normal con ámbito de frijol clase com.web.AbstractCrudController No es proxyable porque no tiene sin argumentos constructor. org.jboss.weld.exceptions.UnproxyableResolutionException: Weld-001435 normal de ámbito clase de bean com.web.AbstractCrudController No es proxyable porque no tiene sin argumentos constructor. en org.jboss.weld.util.Proxies.getUnproxyableClassException (Proxies.java:215) en org.jboss.weld.util.Proxies.getUnproxyableTypeException (Proxies.java:166) en org.jboss.weld.util.Proxies.getUnproxyableTypesException (Proxies.java:191) en org.jboss.weld.bootstrap.Validator.validateBean (Validator.java:134) en org.jboss.weld.bootstrap.Validator.validateRIBean (Validator.java:148) en org.jboss.weld.bootstrap.Validator.validateBeans (Validator.java:363) en org.jboss.weld.bootstrap.Validator.validateDeployment (Validator.java:349) en org.jboss.weld.bootstrap.WeldBootstrap.validateBeans (WeldBootstrap.java:416) en org.glassfish.weld.WeldDeployer.event (WeldDeployer.java:178) en org.glassfish.kernel.event.EventsImpl.send (EventsImpl.java:128) en org.glassfish.internal.data.ApplicationInfo.start (ApplicationInfo.java:265) en com.sun.enterprise.v3.server.ApplicationLifecycle.deploy (ApplicationLifecycle.java:402) en com.sun.enterprise.v3.server.ApplicationLifecycle.deploy (ApplicationLifecycle.java:221) en org.glassfish.deployment.admin.DeployCommand.execute (DeployCommand.java:351) en com.sun.enterprise.v3.admin.CommandRunnerImpl $ 1.Ejecute (CommandRunnerImpl.java:360) en com.sun.enterprise.v3.admin.CommandRunnerImpl.doCommand (CommandRunnerImpl.java:375) en com.sun.enterprise.v3.admin.CommandRunnerImpl.doCommand (CommandRunnerImpl.java:1072) en com.sun.enterprise.v3.admin.CommandRunnerImpl.access $ 1200 (CommandRunnerImpl.java:101) en com.sun.enterprise.v3.admin.CommandRunnerImpl $ ExecutionContext.execute (CommandRunnerImpl.java:1221) en com.sun.enterprise.v3.admin.CommandRunnerImpl $ ExecutionContext.execute (CommandRunnerImpl.java:1210) en com.sun.enterprise.v3.admin.AdminAdapter.doCommand (AdminAdapter.java:375) en com.sun.enterprise.v3.admin.AdminAdapter.service (AdminAdapter.java:209) en com.sun.grizzly.tcp.http11.GrizzlyAdapter.service (GrizzlyAdapter.java:166) en com.sun.enterprise.v3.server.HK2Dispatcher.dispath (HK2Dispatcher.java:117) en com.sun.enterprise.v3.services.impl.ContainerMapper.service (ContainerMapper.java:234) en com.sun.grizzly.http.ProcessorTask.invokeAdapter (ProcessorTask.java:824) en com.sun.grizzly.http.ProcessorTask.doProcess (ProcessorTask.java:721) en com.sun.grizzly.http.ProcessorTask.process (ProcessorTask.java:1014) en com.sun.grizzly.http.DefaultProtocolFilter.execute (DefaultProtocolFilter.java:220) en com.sun.grizzly.DefaultProtocolChain.executeProtocolFilter (DefaultProtocolChain.java:135) en com.sun.grizzly.DefaultProtocolChain.execute (DefaultProtocolChain.java:102) en com.sun.grizzly.DefaultProtocolChain.execute (DefaultProtocolChain.java:88) en com.sun.grizzly.http.HttpProtocolChain.execute (HttpProtocolChain.java:76) en com.sun.grizzly.ProtocolChainContextTask.doCall (ProtocolChainContextTask.java:53) en com.sun.grizzly.SelectionKeyContextTask.call (SelectionKeyContextTask.java:57) en com.sun.grizzly.ContextTask.run (ContextTask.java:69) en com.sun.grizzly.util.AbstractThreadPool $ Worker.doWork (AbstractThreadPool.java:530) en com.sun.grizzly.util.AbstractThreadPool $ Worker.run (AbstractThreadPool.java:511) en java.lang.Thread.run (Thread.java:637)
Incluso si añado un constructor sin argumentos a la clase base, Weld todavía se queja con la misma salvedad que la clase no es proxyable porque tiene métodos finales. ¿Por qué me obligan soldadura para cambiar mi diseño de la clase? Todo funcionaba bien utilizando la anotación JSF @ManagedBean.
Le agradecería cualquier ayuda. Gracias, Theo
Solución
¿Por qué me obliga soldadura para cambiar mi diseño de la clase? Todo funcionaba bien utilizando la anotación JSF @ManagedBean.
Bueno, Weld / CDI no funciona de la misma manera. Mi opinión es que cuando se utiliza la inyección para obtener una referencia a un bean, lo que se obtiene es en mayoría de los casos un objeto proxy. Este objeto proxy subclases bean y omite los métodos para implementar la delegación. Y esto introduce algunas restricciones en la lata de proxy clases CDI.
El CDI especificación expresa así:
5.4.1. tipos de frijol Unproxyable
Algunos tipos de frijol legales no puede ser aproximada por el contenedor:
- clases que no tienen un constructor no privada sin parámetros,
- clases que son declaradas final o tienen métodos finales,
- tipos primitivos,
- y matrices de tipos.
Si un punto de inyección cuya declaró tipo no puede ser aproximado por la resuelve recipiente a un bean con una alcance normal, el recipiente detecta automáticamente el problema y lo trata como un problema de implementación.
Mi sugerencia sería que los métodos no final.
Referencias
- CDI Especificación
- Sección 5.4. "Proxies de cliente"
- Sección 5.4.1 "tipos de frijol Unproxyable"
- Sección 6.3. "Ámbitos normales y pseudo-ámbitos"
Otros consejos
Estoy en el proceso de migración de los granos de JSF Managed al CDI logró granos, y me acaba de confirmar que estoy en condiciones de uso super con éxito en un grano descendiente CDI (con 'costumbre' calificador @Descendant) que 'se extiende' un bean antepasado CDI (con @Default calificador).
CDI ancestro de frijoles con @Default calificador:
@Default
@Named("pf_pointOfContactController")
@SessionScoped
public class pf_PointOfContactController implements Serializable {
frijol antepasado tiene la siguiente:
@PostConstruct
protected void init() {
CDI descendiente de frijoles con @Descendant calificador:
@Descendant
@Named("pf_orderCustomerPointOfContactController")
@SessionScoped
public class pf_OrderCustomerPointOfContactController extends pf_PointOfContactController {
frijol Descendiente tiene la siguiente:
@PostConstruct
public void init(){
super.init();
he tenido que añadir / uso super.init (), ya que los métodos del bean ancestro CDI estaban criando NullPointerException, ya @PostConstruct del ancestro frijol no se ejecuta en el frijol CDI @Descendant.
He visto / oído / leído que es recomendable utilizar @PostConstruct en lugar de Método constructor cuando se utiliza CDI, por lo que el constructor del antecesor de frijol tenía la lógica 'inicialización', y el constructor del antecesor de frijol se invoca automáticamente / ejecutada cuando se utiliza JSF habas administrado.
Debido respuesta aceptada es correcta pero incompleta creo que puedo añadir mi granito de arena sólo para los futuros lectores.
El problema que se encontró con OP se pueden resolver de dos maneras:
- Al eliminar la palabra clave
final
de métodos y clase en sí - Marcado tales "clase unproxyable" con
@Singleton
o@Dependent
pseudo-alcance (por supuesto si tiene sentido). Se va a funcionar porque CDI no crea un objeto proxy para los granos de seudo con ámbito.
En el caso de uso OP se recomienda el segundo enfoque en mi humilde opinión, como controladores sin duda se pueden marcar como simple.
Esperamos que ayude a alguien