When and why JPA entities should implement the Serializable interface?
The question is in the title. Below I j开发者_运维百科ust described some of my thoughts and findings.
When I had a very simple domain model (3 tables without any relations), all my entities did NOT implement the Serializable
interface.
But when the domain model became more complex, I got a RuntimeException
, saying that one of my entities didn't implement Serializable
.
I use Hibernate as a JPA implementation, and I wonder:
- Is it a vendor-specific requirement/behavior?
- What happens with my serializable entities? Should they be serializable for storing or for transferring?
- At which moment it becomes necessary to make my entity serializable?
According to JPA Spec:
If an entity instance is to be passed by value as a detached object (e.g., through a remote interface), the entity class must implement the Serializable interface.
"JSR 220: Enterprise JavaBeansTM,Version 3.0 Java Persistence API Version 3.0, Final Release May 2, 2006"
You need your entities to be Serializable
if you need to transfer them over-the-wire (serialize them to some other representation), store them in http session (which is in turn serialized to hard disk by the servlet container), etc.
Just for the sake of persistence, Serializable
is not needed, at least with Hibernate.
But it is a best practice to make them Serializable
.
This usually happens if you mix HQL and native SQL queries. In HQL, Hibernate maps the types you pass in to whatever the DB understands. When you run native SQL, then you must do the mapping yourself. If you don't, then the default mapping is to serialize the parameter and send it to the database (in the hope that it does understand it).
According to the hibernate docs, while using @JoinColumn annotation:
It has one more parameters named
referencedColumnName
. This parameter declares the column in the targeted entity that will be used to the join. Note that when usingreferencedColumnName
to a non primary key column, the associated class has to beSerializable
.
JPA specification
According to the JPA specification, an entity should implement Serializable
only if it needs to be passed from one JVM to another or if the entity is used by a Stateful Session Bean which needs to be passivated by the EJB container.
If an entity instance is to be passed by value as a detached object (e.g., through a remote interface), the entity class must implement the
Serializable
interface.
Hibernate
Hibernate only requires that entity attributes are Serializable
, but not the entity itself.
However, implementing the JPA specification, all the JPA requirements regarding Serializable
entities apply to Hibernate as well.
Tomcat
According to Tomcat documentation, the HttpSession
attributes also need to be Serializable
:
Whenever Apache Tomcat is shut down normally and restarted, or when an application reload is triggered, the standard Manager implementation will attempt to serialize all currently active sessions to a disk file located via the pathname attribute. All such saved sessions will then be deserialized and activated (assuming they have not expired in the mean time) when the application reload is completed.
In order to successfully restore the state of session attributes, all such attributes MUST implement the java.io.Serializable interface.
So, if the entity is stored in the HttpSession
, it should implement Serializable
.
If we just talk about persistence, Serializable
is not needed But it is best practice to make the entities Serializable
.
If we are exposing domain
/entities
objects directly exposed to the presentation layer, instead of using DTO
, In that case we need to implement Serializable
. These domain objects can be stored in HTTPSession
for caching/optimization purposes. A http-session can be serialized or clustered. And it is also required for transferring data between JVM
-instances.
When we use DTO
to decouple persistence layer and service layer, marking the domain objects as Serializable
would be counter productive and would violate the “encapsulation
”. Then it becomes an anti-pattern.
Composite identifiers
The primary key class must be serializable.
POJO Models
If an entity instance is to be used remotely as a detached object, the entity class must implement the Serializable
interface.
Cache
In addition, if you are implementing a clustered
second level cache
then your entities must be serializable
. The identifier has to be Serializable
because that’s a JPA requirement since the identifier
might be use as the key for a second-level cache entry.
And when we serialize entities make sure to provide explicit serialVersionUID
with private access modifier. Because if a serializable
class does not explicitly declare a serialVersionUID
, then the serialization runtime will calculate a default serialVersionUID
value for that class based on various aspects of the class, as described in Java(TM) Object Serialization Specification . Default serialVersionUID
computation is highly sensitive to class details that may vary depending on compiler implementations, and can thus result in unexpected InvalidClassExceptions
during deserialization.
To complement the nice answer of Conor who referred to the JSR-317 specifications. Typically, EAR projects consist of an EJB module with the EJBs exposed via a remote interface. In this one case you need to make your entity beans serializable as they are aggregated in the remote EJB and are built to be wired through the network.
A JEE6 war project without CDI: can contain EJB lite backed by non-serializable JPA entities.
A JEE6 war project with CDI: Beans that use session, application, or conversation scope must be serializable, but beans that use request scope do not have to be serializable. Thus the underlying JPA entity beans -if any- would follow the same semantics.
I believe your problem is related to having a field of a complex type (class) which isn't annotated. In such cases the default handling will be storing the object in its serialized form in the database (which probably isn't what you meant to do) Example:
Class CustomerData {
int getAge();
void setAge(int age);
}
@Entity
Class Customer {
CustomerData getCustomerData();
void setCustomerData(CustomerData data)
}
In the above case the CustomerData will be saved in a byte array field in the database in its serialized form.
Classes must implement Serializable if you want to serialize them. This is not directly related to JPA and the JPA specification does not require that entities are serializable. If Hibernate really complains about this, I suppose it is a Hibernate bug, but I suppose that you directly or indirectly are doing something else with the entities, which require them to be serializable.
Please refer http://www.adam-bien.com/roller/abien/entry/do_jpa_entities_have_to it says, The implementation of java.io.Serializable is simply required for transfering data via IIOP or JRMP (RMI) between JVM-instances. In case of a pure web application the domain objects are sometimes stored in HTTPSession for caching / optimization purposes. A http-session can be serialized (passivation) or clustered. In both cases all the content have to be Serializable.
- At which moment it becomes necessary to make my entity serializable?
Implementing ehcache with diskstore as second level cache (i.e. using @Cacheable
annotation on entity or repository/service method) requires Serializable, otherwise the cache will fail (NotSerializableException
) to write the entity to the disk cache.
remote hit using postman or ajax or angular js etc....., may cause the repeat cycle with StackOverflow exception with Jackson fasterxml.So, it is better to use serializer.
when JPA entities are used as parameters or return values by the remote EJB operations
This is also the error that's thrown when you pass an incorrectly-typed ID as the second param to something like em.find() (i.e. passing the entity itself rather than its ID). I haven't found it yet necessary to actually declare JPA entities serializable--it's not really necessary unless you're using referencedColumnName as described by aman.
精彩评论