I have not yet experienced any serialization-related issues. But PMD and Findbugs detect a bunch of potential problems regarding seriazation. A typical case is an injected logger that is being detected as non-serializable. but there are many more - EntityManager and several CDI beans.
I have not found any best practices on how to deal with serialization correctly.
will the fields, injected by #Inject and #PersistenceContext be reinjected on deserialization?
should they be marked as transient?
or should I just ignore/switch off the code checks?
should I really provide accessors to all those fields as PMD advises?
I realize this is an old question, but I believe the only answer provided is incorrect.
will the fields, injected by #Inject and #PersistenceContext be
reinjected on deserialization?
No, they will not. I personally experienced this with JBoss in a clustered environment. If the bean is passivation capable, then the container must inject a serializable proxy. That proxy gets serialized and deserialized. Once deserialized, it will locate the proper injection and rewire it. However, if you mark the field transient, the proxy is not serialized and you will see NPEs when the injected resource is accessed.
It should be noted that the injected resource or bean does not have to be Serializable, because the proxy will be. The only exception is for #Dependent scoped beans which have to be serializable or the injection transient. This is because a proxy is not used in this case.
should they be marked as transient?
No, see above.
or should I just ignore/switch off the code checks?
This is up to you, but it is what I would do.
should I really provide accessors to all those fields as PMD advises?
No, I would not.
In our projects, we disable this check when we know we are using CDI.
This answer will detail the serialization/passivation semantics for EJB 3.2 (JSR 345), JPA 2.1 (JSR 338) and CDI 1.2 (JSR 346). Noteworthy is that the Java EE 7 umbrella specification (JSR 342), the Managed Beans 1.0 specification (JSR 316) and the Commons Annotations specification 1.2 (JSR 250) does not have anything to say that is of interest to us in regards to serialization/passivation.
I will also touch on the topic of static code analyzers.
EJB
Relevant sections are "4.2 Conversational State of a Stateful Session Bean" and "4.2.1 Instance Passivation and Conversational State".
#Stateless and #Singleton instances are never passivated.
#Stateful instances may be passivated. Since EJB 3.2, the class developer can opt-out from passivation using #Stateful(passivationCapable=false).
The EJB specification explicitly notes that references to things such as UserTransaction, EntityManagerFactory and container-managed EntityManager are taken care of by the container. A #Stateful instance which uses an extended persistence context will not be passivated unless all entities in the persistence context and the EntityManager implementation is serializable.
Please note that an application-managed EntityManager always uses an extended persistence context. Also, a #Stateful instance is the only type of EJB session instance which may use a container-managed EntityManager with an extended persistence context. This persistence context would be bound to the life cycle of the #Stateful instance instead of one single JTA transaction.
The EJB specification does not explicitly address what happens to a container-managed EntityManager with an extended persistence context. My understanding is this: If there is an extended persistence context, then this guy must be deemed serializable or not according to the rules defined previously and if it is, then passivation proceeds. If passivation proceeds, then the #Stateful class developer need only concern himself with references to application-managed entity managers.
The EJB specification does not specify what happens to transient fields other than describing an assumption we as developers should make.
Section 4.2.1 says:
The Bean Provider must assume that the content of transient fields may be lost between the PrePassivate and PostActivate notifications.
[...]
While the container is not required to use the Serialization protocol for the Java programming language to store the state of a passivated session instance, it must achieve the equivalent result. The one exception is that containers are not required to reset the value of transient fields during activation. Declaring the session bean's fields as transient is, in general, discouraged.
Requiring the container to "achieve the equivalent result" as Javas serialization protocol at the same time leaving it totally unspecified as to what happens with transient fields is quite sad, to be honest. The take-home lesson is that nothing should be marked transient. For fields that the container can not handle, use #PrePassivate to write a null and #PostActivate to restore.
JPA
The word "passivation" does not occur in the JPA specification. Nor does JPA define serialization semantics for types such as EntityManagerFactory, EntityManager, Query and Parameter. The only sentence in the specification relevant to us is this (section "6.9 Query Execution"):
CriteriaQuery, CriteriaUpdate, and CriteriaDelete objects must be serializable.
CDI
Section "6.6.4. Passivating scopes" define a passivating scope as a scope explicitly annotated #NormalScope(passivating=true). This property defaults to false.
One implication is that #Dependent - which is a pseudo scope - is not a passivation capable scope. Also noteworthy is that javax.faces.view.ViewScoped is not a passivation capable scope which for whatever reason the majority of Internet seems to believe. For example, section "17-2. Developing a JSF Application" in the book "Java 9 Recipes: A Problem-Solution Approach".
A passivation capable scope requires that instances of classes declared "with the scope are passivation capable" (section "6.6.4. Passivating scopes"). Section "6.6.1. Passivation capable beans" define such an object instance simply as one being transferable to secondary storage. Special class- annotations or interfaces are not an explicit requirement.
Instances of EJB:s #Stateless and #Singleton are not "passivation capable beans". #Stateful may be (stateful is the only EJB session type which it makes sense to let CDI manage the life cycle of - i.e., never put a CDI scope on a #Stateless or #Singleton). Other "managed beans" are only "passivation capable beans" if they and their interceptors and decorators are all serializable.
Not being defined as a "passivation capable bean" does not mean that things such as stateless, singleton, EntityManagerFactory, EntityManager, Event and BeanManager can not be used as dependencies inside a passivation capable instance that you author. These things are instead defined as "passivation capable dependencies" (see section "6.6.3. Passivation capable dependencies" and "3.8. Additional built-in beans").
CDI make these depedencies passivation capable through the use of passivation capable proxies (see last bulleted item in section "5.4. Client proxies" and section "7.3.6. Lifecycle of resources"). Please note that for Java EE resources such as the EntityManagerFactory and EntityManager to be passivation capable, they must be declared as a CDI producer field (section "3.7.1. Declaring a resource"), they do not support any other scope than #Dependent (see section "3.7. Resources") and they must be looked up on the client-side using #Inject.
Other #Dependent instances - albeit not declared with a normal scope and not required to be fronted by a CDI "client proxy" - can also be used as a passivation capable dependency if the instance is transferable to secondary storage, i.e., serializable. This guy will be serialized together with the client (see last bulleted item in section "5.4. Client proxies").
To be perfectly clear and to provide a few examples; a #Stateless instance, a reference to an EntityManager produced by CDI and a serializable #Dependent instance can all be used as instance fields inside your class annotated with a passivation capable scope.
Static code analyzers
Static code analyzers are stupid. I think that for senior developers, they are more a cause of concern than being an aide. False flags raised by these analyzers for suspected serialization/passivation problems is certainly of very limited value because CDI requires the container to validate that the instance "truly is passivation capable and that, in addition, its dependencies are passivation capable" or otherwise "throw a subclass of javax.enterprise.inject.spi.DeploymentException" (section "6.6.5. Validation of passivation capable beans and dependencies" and "2.9. Problems detected automatically by the container").
Finally, as others have pointed out, it is worth repeating: we should probably never mark a field as transient.
PMD and FindBugs are only checking the interfaces and also have no information about the environment in which your code will be running. To quiet the tools, you could mark them as transient, but they'll all be properly re-injected upon deserialization and first use regardless of the transient keyword.
Related
I have three questions
Generally, a bean is just a Pojo that is managed by a container (like Ejb container or CDI container), right? As for when a bean is considered an EJB is quite clear. You will have something like #Stateless or #Stateful. But I don't understand fully when a bean is considered CDI bean. Defining the scope (e.g. #RequestScope) is an indication but what about other classes? In short, when I create and write my own classes, how can I make them CDI bean instead of make them plain Java classes? The only thing I have found about this is https://docs.oracle.com/javaee/6/tutorial/doc/gjfzi.html
Related to above, in this tutorial
https://dzone.com/articles/cdi-and-the-produces-annotation-for-factory
in step 4 says that "CDI does not know how to inject the SpecialLogger object", because of LogConfiguration, so why LogConfiguration is not considered a CDI bean and cannot be injected, and needed to create a producer method ?
I don't understand when we use a producer method, in this example we use it to create a SpecialLogger object but why, we shouldn't just inject SpecialLogger?
Firstly, EJB and CDI are two different specifications with different limitations and goals. Later on in Java/Jakarta EE evolution, CDI created a bridge between the two where it considers all EJB beans to also be CDI beans (the internals of which are more complex and I won't go into now) but otherwise they are still different specs so don't conflate them.
In CDI, beans can be either managed beans or producer methods/fields. Managed beans are typically a java class which can (or in some cases must) have certain annotations to be picked up as a bean. There are some limitations as to how a managed bean looks. See this section of specification (CDI 4, Jakarta EE 10) for further information. Producer methods/fields are a way to declare a bean while also providing an instance of the bean yourself instead of letting CDI create it. In both cases, CDI then manages the bean for its lifecycle, which is typically controlled by the scope of the bean (i.e. #RequestScoped).
However, that's not all there is to it. You mentioned discovery and that's part of the process. There are three discovery modes - none, all, annotated - which can be declared in beans.xml. These control which beans will be found and if they need any kind of annotation to be recognized as beans. none simply means no beans, all means that all classes will be picked up as potential beans, even without annotations. And lastly, annotated will only pick up beans that have a so called bean defining annotation. These include scope annotations, stereotypes, and interceptor annotation. See this part of spec (CDI 4).
Note that prior to CDI 4, default discovery mode was all. With CDI 4 and onwards, it is annotated!
To your second question - SpecialLogger has no no-args constructor and has one constructor with parameters (LogConfiguration) and this constructor isn't annotated with #Inject. Therefore, CDI doesn't know how to create an instance of this object. Note that annotating the constructor with #Inject effectively tells CDI that all of its parameters are also CDI beans that it should know how to instantiate which is not going to be the case in this example.
This brings me to your last question. A producer is typically useful for when it isn't easy or even possible to have an instance of the class created automatically by CDI, but there is still value in handling the instance as a CDI bean. Once you define a producer for SpecialLogger, you can then normally #Inject SpecialLogger in your code. In the end, user won't know if their bean is a product of CDI class instantiation or a producer method. Since bean types of producer method are governed by transitive closure on method's return type, you can also choose to return one of several subclasses based on some config options etc. Overall, it gives you more control over how to create and initialize an object before you hand it over to CDI but at the cost of not having this object injected (since it is you who creates it and not CDI).
In essence, what is the difference between these two classes:
#ApplicationScoped
#Singleton
class A {}
#Dependent
#Singleton
class B {}
Contextual EJB instances
I prefer not to use #Inject when looking for EJB:s, unless the EJB is a #Stateful and I want the CDI container to manage the stateful's life-cycle which could be very convenient. Otherwise, using #Inject to retrieve a contextual EJB instance is a bit dangerous. For example, a #Remote client-view cannot be retrieved using CDI unless we also write a producer. Furthermore, class A and class B can not declare any other scope than what they currently do. CDI 1.1, section "3.2 Session beans" says:
A singleton bean must belong to either the #ApplicationScoped scope or
to the #Dependent pseudo-scope. If a session bean specifies an illegal
scope, the container automatically detects the problem and treats it
as a definition error.
Hence, apart from stateful beans, I see no point in using CDI when I go look for EJB:s.
A more mature version of the question
From the client code's perspective which uses #Inject to declare a dependency on either A or B, I cannot imagine there is a difference. In both cases, the call will be routed to a singleton EJB. Had I been the implementation author of a CDI provider, then I might even inject the real EJB proxy in both cases and ignore future calls asking for destruction of the dependent CDI proxy? The bottom line is that we may declare two different scopes on the EJB singleton class. So what's the difference?
I wonder what happens with the injected EJB-Proxy, when the SessionScoped CDI bean was passivated and then activated. Is there a null ref? Or is the EJB "reinjected"? Thanks for clarification.
Section 6.6.3. (Passivation capable dependencies) of CDI spec states that the container guarantees Stateless beans are Passivation capable whether you declare your stateless bean serializable or not.
Section 6.6.5 of the specs states that an error occurs at deployment if a passivating scope ('#SessionScoped' for example) declares a dependency to a non-passivation capable dependency.
How the container handles the reactivation is implementation dependent. It can make the stateless bean serializable, or the proxy serializable and the reference to the bean, when the proxy is deserialized is updated.
Adding to the answer of maress; since a Stateless bean is for the client in fact stateless, the container does not necessarily have to serialize anything for it.
Every other call to a stateless bean can go to a different bean instance anyway, or every other call can cause a new bean instance to be created (which is the default behavior in WildFly 8 if I'm not mistaken).
As maress mentioned, technically the proxy can be made serializable, but the proxy typically does little more than fetch the actual bean* from a systemwide pool (which can be of zero size) and delegate all method calls to that.
*) As a technical detail; the proxy may not call the actual bean directly, but call into an interceptor chain before the actual-actual bean is called
Spring creates the class objects by Java dynamic proxies (java.lang.reflect.Proxy). i.e
#Component
public class NewsService implements Service{
}
But how the member variables are injected by Spring? ie
#Autowired
private EntityManager em;
Java dynamic proxies uses interface (i.e Service) to create the objects. But how member variables are injected? The instance variables are not known by interface.
Also when member instances are injected? Load time?(When containing class object is created?) or Lazy loading? (when object is used first?)
Few facts for you:
Spring instantiates specific classes, not interfaces. Dependency injection is done on the original bean instance.
When a proxy is created, Spring registers both the original bean and its proxy in the application context. JDK proxy is created for all interfaces implemented by the original bean.
Proxies are not created if they are not necessary (i.e. no aspect is applied on the target bean).
All beans are eagerly initialized by default. If you want some bean to be instantiated in a lazy fashion, you need to specify it explicitly.
Dependency injection happens right after the bean is instantiated. Some dependencies are injected based on the bean definition, other dependencies might be injected by various bean post processors (but they are executed right away as well).
How is dependency injection realized:
When using XML configuration or autowiring , dependency injection is done via Reflection API. Spring is able to either call property setter (setFoo(...)) or set field value directly (reflection allows setting private members).
When using #Bean methods in Java configuration, dependency injection is done by your method.
A bit on proxies:
JDK proxies and CGLIB proxies are two different proxying mechanisms. JDK creates artificial class based on provided interfaces, whereas CGLIB creates artificial subclass of the target class.
Which proxying mechanism is used depends on your Spring configuration (JDK is the default one). For obvious reasons JDK proxy can be used only in cases when your dependencies are referenced only by interface. From the other side you can not use CGLIB proxying for final classes.
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.
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.
Container create proxy object for injected classes. So, container doesn't use your classes, but those classes extends. Java prohibit extends final classes, so you cannot use final classes in CDI.