Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why CDI beans don't support final methods

I just incurred in the infamous JavaEE CDI error under GlassFish server:

org.glassfish.deployment.common.DeploymentException: CDI deployment failure:Exception List with 2 exceptions:
Exception 0 :
org.jboss.weld.exceptions.DeploymentException: WELD-001437 Normal scoped bean class ASController is not proxyable because the type is final or it contains a final method public final void ASController.selectPath(org.primefaces.event.NodeSelectEvent) - Managed Bean [class ASController] with qualifiers [@Default @Any @Named].

the error is quite explicative in the fact that he doesn't like final methods inside a CDI bean, however I can't grasp why.

At this link

http://docs.jboss.org/weld/reference/1.1.0.Final/en-US/html_single/#d0e1429

they explain it is something to do with serialization but I can't see why serializing a class with a final method should be any harder than one with non final methods.

like image 806
dendini Avatar asked Dec 19 '13 12:12

dendini


People also ask

What are CDI beans?

But what is a CDI bean? A CDI bean is a POJO, plain old java object, that has been automatically instantiated by the CDI container, and is injected into all, and any qualifying injection points in the application. The CDI container initiates the bean discovery process during deployment.

Why use CDI Java?

CDI is preferred because it allows apps of large (arbitrary?) horizontal and vertical scales to share contexts, dependencies, and therefore data.

What is CDI Java?

CDI (Contexts and Dependency Injection) is a standard dependency injection framework included in Java EE 6 and higher. It allows us to manage the lifecycle of stateful components via domain-specific lifecycle contexts and inject components (services) into client objects in a type-safe way.


1 Answers

Well, there is several ways in which you can implement a proxy object. But since you expect the proxy to have the "same" type as the proxied bean, you'll have to use inheritance (or demand interfaces which you then could implement, but this would not be an approach where every POJO could be a bean for CDI).

That is, they internally extend from the class you want to inject, generate some proxy code around that and give you that sub class.

This proxy then is handling all the magic to make sure you always have a bean fitting your context (and this bean has all the members variable beans pointing to the just right beans).

So you are not really receiving the type of the bean you want to inject, but a proxy subclass of that bean. This does not work very well with final methods and classes and private constructors.

If the class is not final, the proxy can extend this class, it however cannot easily overwrite the final method of yours. This however may be needed (if e.g your bean is serialized, the proxy needs to deserialize it).

There is, more complicated ways, around that. One could inject this functionality by manipulating the byte code of your class via an agent (e.g removing the final modifiers, inject a default constructor, ...) and maybe even mix this with inheritance, but this is just not implemented, yet (and also non trivial to support over several JVM implementations).

From the linked resource a note indicating that this is planned for a future release:

Note

A future release of Weld will likely support a non-standard workaround for this limitation, using non-portable JVM APIs: Sun, IcedTea, Mac: Unsafe.allocateInstance() (The most efficient) IBM, JRockit: ReflectionFactory.newConstructorForSerialization()

But we didn't get around to implementing this yet.

like image 71
Matthias Avatar answered Sep 21 '22 01:09

Matthias