Utilizzando CDI invece di @ManagedBean: UnproxyableResolutionException perché super classe non ci sono no-args costruttore
-
27-09-2019 - |
Domanda
Sto cercando di usare CDI per la mia JSF / applicazione Java EE. Ho la seguente gerarchia di 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 si tenta di distribuire l'applicazione su GF 3.1, ottengo la seguente eccezione CDI / Salda:
GRAVI: eccezione durante il caricamento del app: WELD-001.435 normale ambito di fagioli classe com.web.AbstractCrudController Non è proxyable perché non ha no-args costruttore. org.jboss.weld.exceptions.UnproxyableResolutionException: WELD-001.435 Normale ambito classe bean com.web.AbstractCrudController Non è proxyable perché non ha no-args costruttore. a org.jboss.weld.util.Proxies.getUnproxyableClassException (Proxies.java:215) a org.jboss.weld.util.Proxies.getUnproxyableTypeException (Proxies.java:166) a org.jboss.weld.util.Proxies.getUnproxyableTypesException (Proxies.java:191) a org.jboss.weld.bootstrap.Validator.validateBean (Validator.java:134) a org.jboss.weld.bootstrap.Validator.validateRIBean (Validator.java:148) a org.jboss.weld.bootstrap.Validator.validateBeans (Validator.java:363) a org.jboss.weld.bootstrap.Validator.validateDeployment (Validator.java:349) a org.jboss.weld.bootstrap.WeldBootstrap.validateBeans (WeldBootstrap.java:416) a org.glassfish.weld.WeldDeployer.event (WeldDeployer.java:178) a org.glassfish.kernel.event.EventsImpl.send (EventsImpl.java:128) a org.glassfish.internal.data.ApplicationInfo.start (ApplicationInfo.java:265) a com.sun.enterprise.v3.server.ApplicationLifecycle.deploy (ApplicationLifecycle.java:402) a com.sun.enterprise.v3.server.ApplicationLifecycle.deploy (ApplicationLifecycle.java:221) a org.glassfish.deployment.admin.DeployCommand.execute (DeployCommand.java:351) a com.sun.enterprise.v3.admin.CommandRunnerImpl $ 1.execute (CommandRunnerImpl.java:360) a com.sun.enterprise.v3.admin.CommandRunnerImpl.doCommand (CommandRunnerImpl.java:375) a com.sun.enterprise.v3.admin.CommandRunnerImpl.doCommand (CommandRunnerImpl.java:1072) a com.sun.enterprise.v3.admin.CommandRunnerImpl.access $ 1200 (CommandRunnerImpl.java:101) a com.sun.enterprise.v3.admin.CommandRunnerImpl $ ExecutionContext.execute (CommandRunnerImpl.java:1221) a com.sun.enterprise.v3.admin.CommandRunnerImpl $ ExecutionContext.execute (CommandRunnerImpl.java:1210) a com.sun.enterprise.v3.admin.AdminAdapter.doCommand (AdminAdapter.java:375) a com.sun.enterprise.v3.admin.AdminAdapter.service (AdminAdapter.java:209) a com.sun.grizzly.tcp.http11.GrizzlyAdapter.service (GrizzlyAdapter.java:166) a com.sun.enterprise.v3.server.HK2Dispatcher.dispath (HK2Dispatcher.java:117) a com.sun.enterprise.v3.services.impl.ContainerMapper.service (ContainerMapper.java:234) a com.sun.grizzly.http.ProcessorTask.invokeAdapter (ProcessorTask.java:824) a com.sun.grizzly.http.ProcessorTask.doProcess (ProcessorTask.java:721) a com.sun.grizzly.http.ProcessorTask.process (ProcessorTask.java:1014) a com.sun.grizzly.http.DefaultProtocolFilter.execute (DefaultProtocolFilter.java:220) a com.sun.grizzly.DefaultProtocolChain.executeProtocolFilter (DefaultProtocolChain.java:135) a com.sun.grizzly.DefaultProtocolChain.execute (DefaultProtocolChain.java:102) a com.sun.grizzly.DefaultProtocolChain.execute (DefaultProtocolChain.java:88) a com.sun.grizzly.http.HttpProtocolChain.execute (HttpProtocolChain.java:76) a com.sun.grizzly.ProtocolChainContextTask.doCall (ProtocolChainContextTask.java:53) a com.sun.grizzly.SelectionKeyContextTask.call (SelectionKeyContextTask.java:57) a com.sun.grizzly.ContextTask.run (ContextTask.java:69) a com.sun.grizzly.util.AbstractThreadPool $ Worker.doWork (AbstractThreadPool.java:530) a com.sun.grizzly.util.AbstractThreadPool $ Worker.run (AbstractThreadPool.java:511) a java.lang.Thread.run (Thread.java:637)
Anche se posso aggiungere un costruttore no-args alla classe di base, Weld lamenta ancora con la stessa eccezione che la classe non è proxyable perché ha metodi finali. Perché WELD mi costringono a cambiare il mio design di classe? Tutto ha funzionato bene usando l'annotazione JSF @ManagedBean.
Gradirei qualsiasi aiuto. Grazie, Theo
Soluzione
Perché WELD mi costringono a cambiare il mio design di classe? Tutto ha funzionato bene usando l'annotazione JSF @ManagedBean.
Bene, Weld / CDI non funziona allo stesso modo. La mia comprensione è che quando si utilizza l'iniezione per ottenere un riferimento a un fagiolo, quello che si ottiene è in maggior parte dei casi un oggetto proxy. Questo oggetto proxy sottoclassi il bean e sovrascrive i metodi per implementare la delega. E questo introduce alcune restrizioni sulla lattina delega classi CDI.
Il CDI spec si esprime così:
5.4.1. tipi di fagioli Unproxyable
Alcuni tipi di fagioli di legge non può essere proxy dal contenitore:
- classi che non hanno un costruttore non privata senza parametri,
- classi che sono dichiarati finale o hanno metodi finali,
- tipi primitivi,
- e array di tipi.
Se un punto di iniezione la cui dichiarata tipo non può essere approssimata dalla risolve Contenitore per un bean con portata normale, il contenitore rileva automaticamente il problema e considera come un problema di distribuzione.
Il mio suggerimento sarebbe quello di rendere i metodi non finale.
Bibliografia
- CDI Specification
- Sezione 5.4. "Proxy client"
- Sezione 5.4.1 "tipi di fagioli Unproxyable"
- Sezione 6.3. "Ambiti normali e pseudo-scope"
Altri suggerimenti
Sono in fase di migrazione da JSF Managed fagioli per CDI gestito fagioli, e ho appena confermato che sono in grado di utilizzare Super con successo in un fagiolo discendente CDI (con 'su misura' qualificatore @Descendant), che 'estende' un bean antenato CDI (con qualificatore @Default).
antenato di fagioli CDI con qualificatore @Default:
@Default
@Named("pf_pointOfContactController")
@SessionScoped
public class pf_PointOfContactController implements Serializable {
Antenato fagiolo ha la seguente:
@PostConstruct
protected void init() {
discendente di fagioli CDI con qualificatore @Descendant:
@Descendant
@Named("pf_orderCustomerPointOfContactController")
@SessionScoped
public class pf_OrderCustomerPointOfContactController extends pf_PointOfContactController {
fagioli Discendente ha il seguente:
@PostConstruct
public void init(){
super.init();
ho dovuto aggiungere / uso super.init (), perché i metodi nel bean antenato CDI sono state alzando NullPointerException, dal momento che @PostConstruct antenato del bean non viene eseguito in CDI @Descendant fagiolo.
Ho visto / sentito / letto che si raccomanda di usare @PostConstruct al posto di metodo di costruzione quando si utilizza CDI, in modo costruttore antenato di fagiolo ha avuto la logica 'di inizializzazione', e il costruttore antenato di fagiolo è stato invocato automaticamente / eseguiti quando si usa JSF gestito fagioli.
A causa risposta accettato è corretta ma incompleta penso di poter aggiungere i miei due centesimi solo per i futuri lettori.
Il problema che OP riscontrato può essere risolto in due modi:
- Rimuovendo
final
parola chiave da metodi e classe stessa - Marcatura tale "classe unproxyable" con
@Singleton
o@Dependent
pseudo-scope (ovviamente se ha senso). Esso funziona perché CDI non crea un oggetto proxy per i fagioli pseudo-ambito.
Nel caso dell'uso OP è stato raccomandato secondo IMHO approccio, come controller sicuramente possono essere contrassegnati come singletons.
La speranza aiuta qualcuno