175
votes

The question is in the title. Below I just 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:

  1. Is it a vendor-specific requirement/behavior?
  2. What happens with my serializable entities? Should they be serializable for storing or for transferring?
  3. At which moment it becomes necessary to make my entity serializable?
14

14 Answers

63
votes

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).

117
votes

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"

71
votes

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.

26
votes

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.

21
votes

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 using referencedColumnName to a non primary key column, the associated class has to be Serializable.

19
votes

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.

8
votes

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.

6
votes

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.

6
votes

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.

5
votes

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.

2
votes
  1. 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.

1
votes

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.

1
votes

when JPA entities are used as parameters or return values by the remote EJB operations

0
votes

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.