I'm trying to use CDI for my JSF/Java EE application. I have the following class hierarchy:
/**
* 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);
}
//...
}
When I try to deploy the application on GF 3.1, I get the following CDI/Weld exception:
SEVERE: Exception while loading the
app : WELD-001435 Normal scoped bean
class
com.web.AbstractCrudController
is not proxyable because it has no
no-args constructor.
org.jboss.weld.exceptions.UnproxyableResolutionException:
WELD-001435 Normal scoped bean class
com.web.AbstractCrudController
is not proxyable because it has no
no-args constructor.
at org.jboss.weld.util.Proxies.getUnproxyableClassException(Proxies.java:215)
at org.jboss.weld.util.Proxies.getUnproxyableTypeException(Proxies.java:166)
at org.jboss.weld.util.Proxies.getUnproxyableTypesException(Proxies.java:191)
at org.jboss.weld.bootstrap.Validator.validateBean(Validator.java:134)
at org.jboss.weld.bootstrap.Validator.validateRIBean(Validator.java:148)
at 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)
at org.glassfish.weld.WeldDeployer.event(WeldDeployer.java:178)
at org.glassfish.kernel.event.EventsImpl.send(EventsImpl.java:128)
at org.glassfish.internal.data.ApplicationInfo.start(ApplicationInfo.java:265)
at com.sun.enterprise.v3.server.ApplicationLifecycle.deploy(ApplicationLifecycle.java:402)
at com.sun.enterprise.v3.server.ApplicationLifecycle.deploy(ApplicationLifecycle.java:221)
at org.glassfish.deployment.admin.DeployCommand.execute(DeployCommand.java:351)
at com.sun.enterprise.v3.admin.CommandRunnerImpl$1.execute(CommandRunnerImpl.java:360)
at com.sun.enterprise.v3.admin.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)
at com.sun.enterprise.v3.admin.CommandRunnerImpl$ExecutionContext.execute(CommandRunnerImpl.java:1221)
at com.sun.enterprise.v3.admin.CommandRunnerImpl$ExecutionContext.execute(CommandRunnerImpl.java:1210)
at com.sun.enterprise.v3.admin.AdminAdapter.doCommand(AdminAdapter.java:375)
at com.sun.enterprise.v3.admin.AdminAdapter.service(AdminAdapter.java:209)
at com.sun.grizzly.tcp.http11.GrizzlyAdapter.service(GrizzlyAdapter.java:166)
at com.sun.enterprise.v3.server.HK2Dispatcher.dispath(HK2Dispatcher.java:117)
at com.sun.enterprise.v3.services.impl.ContainerMapper.service(ContainerMapper.java:234)
at com.sun.grizzly.http.ProcessorTask.invokeAdapter(ProcessorTask.java:824)
at com.sun.grizzly.http.ProcessorTask.doProcess(ProcessorTask.java:721)
at com.sun.grizzly.http.ProcessorTask.process(ProcessorTask.java:1014)
at com.sun.grizzly.http.DefaultProtocolFilter.execute(DefaultProtocolFilter.java:220)
at com.sun.grizzly.DefaultProtocolChain.executeProtocolFilter(DefaultProtocolChain.java:135)
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)
at com.sun.grizzly.util.AbstractThreadPool$Worker.doWork(AbstractThreadPool.java:530)
at com.sun.grizzly.util.AbstractThreadPool$Worker.run(AbstractThreadPool.java:511)
at java.lang.Thread.run(Thread.java:637)
Even if I add a no-args constructor to the base class, Weld still complains with the same exception that the class is not proxyable because it has final methods. Why does WELD force me to change my class design? Everything worked fine using the JSF @ManagedBean annotation.
I would appreciate any help.
Thank,
Theo
Best Answer
Well, Weld/CDI doesn't work the same way. My understanding is that when you use injection to obtain a reference to a bean, what you get is in most cases a proxy object. This proxy object sub-classes your bean and overrides the methods to implement delegation. And this introduces some restrictions on the classes CDI can proxy.
The CDI spec puts it like this:
My suggestion would be to make the methods non final.
References