views:

29

answers:

1

Hi,

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

+1  A: 

Why does WELD force me to change my class design? Everything worked fine using the JSF @ManagedBean annotation.

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:

5.4.1. Unproxyable bean types

Certain legal bean types cannot be proxied by the container:

  • classes which don't have a non-private constructor with no parameters,
  • classes which are declared final or have final methods,
  • primitive types,
  • and array types.

If an injection point whose declared type cannot be proxied by the container resolves to a bean with a normal scope, the container automatically detects the problem and treats it as a deployment problem.

My suggestion would be to make the methods non final.

References

  • CDI Specification
    • Section 5.4. "Client proxies"
    • Section 5.4.1 "Unproxyable bean types"
    • Section 6.3. "Normal scopes and pseudo-scopes"
Pascal Thivent
which are the cases when CDI does not use proxies? I think it should always :) (+1)
Bozho
@Bozho When using pseudo-scopes?
Pascal Thivent
a, yes, the spec says "for all normal scopes"
Bozho
Thanks. @Bozho The spec says CDI does not use client proxies for beans with the @Dependent scope (which is the default scope).
Theo