Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

"Not known whether passed class name ... is safe" using JPA EmbeddedId with Hibernate

In an very distilled version of the sample code available from a tutorial, Embedded Compound Primary Key : Primary Key « JPA « Java Tutorial, I'm getting:

javax.persistence.PersistenceException: [PersistenceUnit: unit] Unable to build Hibernate SessionFactory
    at org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl.persistenceException(EntityManagerFactoryBuilderImpl.java:877)
    at org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl.build(EntityManagerFactoryBuilderImpl.java:805)
    at org.hibernate.jpa.HibernatePersistenceProvider.createEntityManagerFactory(HibernatePersistenceProvider.java:58)
    at javax.persistence.Persistence.createEntityManagerFactory(Persistence.java:55)
    at javax.persistence.Persistence.createEntityManagerFactory(Persistence.java:39)
    at [my code that calls e.persist on a Student]

The exception is fairly generic, but Hibernate provides some good log debug info (I've replaced the actual package name with <package>):

[DEBUG] org.hibernate.boot.internal.ClassLoaderAccessImpl: Not known whether passed class name [<package>.Student] is safe
[DEBUG] org.hibernate.boot.internal.ClassLoaderAccessImpl: No temp ClassLoader provided; using live ClassLoader for loading potentially unsafe class : <package>.Student

Here's the distilled code. (The backstory is that I'd been trying, to no avail, to create an entity with an embedded id. After a while of trying to debug that, I re-started with this tutorial code, removing things until I got the same error.)

@Embeddable
class StudentId {
    private int id; 

    public StudentId() {}

    public StudentId(int id) { this.id = id; }

    @Override
    public boolean equals(Object o) { 
        return ((o instanceof StudentId) && id == ((StudentId) o).id);
    }

    @Override
    public int hashCode() { return id; }
}

@Entity
public class Student {
    @EmbeddedId
    private StudentId id;

    public Student() {}

    public Student(int id) { this.id = new StudentId(id); }
}
like image 496
Joshua Taylor Avatar asked Sep 29 '15 19:09

Joshua Taylor


Video Answer


1 Answers

The embeddable class needs to be serializable. Updating the definition of StudentId to implement Serializable (and adding a serialVersionUID), the issue seems to disappear:

@Embeddable
class StudentId implements Serializable {

    private static final long serialVersionUID = -7415410969017941320L;

    // ...
}

Once I discovered this, I was able to do a bit more research, but it was of varying degrees of helpfulness. For instance, Do Hibernate table classes need to be Serializable?, discusses whether entity classes need to be Serializable. In general, they don't. Another question, Why composite-id class must implement Serializable?, is more relevant, but making the id class non-serializable there produces a different error message than what I was getting.

User OndrejM, in a comment, pointed out an answer to How to map a composite key with Hibernate? that locates the part of the JPA 1.0 specification that dictates that composite key classes must be serializable. For completeness, the relevant portion from the later spec, JSR-000338 JavaTM Persistence 2.1 Final Release for Evaluation, is:

2.4 Primary Keys and Entity Identity

… The following rules apply for composite primary keys: …

  • The primary key class must be serializable.
like image 154
Joshua Taylor Avatar answered Oct 17 '22 05:10

Joshua Taylor