Search code examples
javaspringhibernateclasscastexception

Why do I get a ClassCastException if I run my Hibernate Request in Spring?


While running the spring-application I got the following exception:

java.lang.ClassCastException: project.db.dbmodels.Permission cannot be cast to project.db.dbmodels.Permission
    at project.db.DataOperator.setUpDefaultPermission(DataOperator.java:573)
    at project.web.WebController.start(WebController.java:18)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)
    at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:190)
    at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:138)
    at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:106)
    at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:879)
    ...

I can't recreate this Exception, while running Unit Tests.

Those are my classes: Permission:

package project.db.dbmodels;

import java.util.*;
import javax.persistence.*;

@Entity
@Table(name = "permission")
public class Permission {

    @Id
    @GeneratedValue
    @Column(name = "id")
    private int id;

    @Column(name = "name")
    private String name;

    @OneToMany(mappedBy = "permission", cascade = CascadeType.ALL)
    private Set<Permission_PermissionRole> permissionPermissionRole = new HashSet<Permission_PermissionRole>();

    public Permission() {
    }

    public Permission(int id, String name, Set<Permission_PermissionRole> permissionPermissionRole) {
        this.id = id;
        this.name = name;
        this.permissionPermissionRole = permissionPermissionRole;
    }

    public int getId() {
        return this.id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getName() {
        return this.name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Set<Permission_PermissionRole> getPermissionPermissionRole() {
        return this.permissionPermissionRole;
    }

    public void setPermissionPermissionRole(Set<Permission_PermissionRole> permissionPermissionRole) {
        this.permissionPermissionRole = permissionPermissionRole;
    }

    public void addPermissionPermissionRole(Permission_PermissionRole permissionPermissionRole) {
        this.permissionPermissionRole.add(permissionPermissionRole);
    }

    public Permission id(int id) {
        this.id = id;
        return this;
    }

    public Permission name(String name) {
        this.name = name;
        return this;
    }

    public Permission permissionPermissionRole(Set<Permission_PermissionRole> permissionPermissionRole) {
        this.permissionPermissionRole = permissionPermissionRole;
        return this;
    }

    @Override
    public boolean equals(Object o) {
        if (o == this)
            return true;
        if (!(o instanceof Permission)) {
            return false;
        }
        Permission permission = (Permission) o;
        return id == permission.id && Objects.equals(name, permission.name)
                && Objects.equals(permissionPermissionRole, permission.permissionPermissionRole);
    }

    @Override
    public int hashCode() {
        return Objects.hash(id, name);
    }

    @Override
    public String toString() {
        return "{" + " id='" + getId() + "'" + ", name='" + getName() + "'" + "}";
    }

}

DataOperator:

package project.db;


import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.persistence.PersistenceException;
import javax.persistence.RollbackException;

import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.query.Query;

import project.db.dbmodels.*;
import org.apache.log4j.Logger;

public class DataOperator {
    final static Logger log = Logger.getLogger(DataOperator.class);


    private static boolean setUpDefaultPermission(boolean change) {
        SessionFactory sf = HibernateUtil.getSessionFactory();
        if (sf == null) {
            return false;
        }
        Session session = sf.openSession();
        session.beginTransaction();
        boolean arePermissionsReady = true;
        // Setup permission "AcessAdminarea"
        String request = "FROM Permission WHERE name = 'Acess Adminarea'";
        Query<Permission> query = session.createQuery(request, Permission.class);
        query.setMaxResults(1);
        Permission permAdminArea = null;
        try {
            permAdminArea = query.uniqueResult();//The Exception occures here
        } catch (PersistenceException e) {
            return false;
        }
        if (permAdminArea == null) {
            arePermissionsReady = false;
            if (change) {
                permAdminArea = new Permission();
                permAdminArea.setName("Acess Adminarea");
                session.save(permAdminArea);
            }
        }
        // Setup permissionrole "Admin"
        request = "FROM PermissionRole WHERE name = 'Admin'";
        Query<PermissionRole> query2 = session.createQuery(request, PermissionRole.class);
        PermissionRole roleAdmin = null;
        try {
            roleAdmin = query2.uniqueResult();
        } catch (PersistenceException e) {
            return false;
        }
        if (roleAdmin == null) {
            arePermissionsReady = false;
            if (change) {
                roleAdmin = new PermissionRole();
                roleAdmin.setName("Admin");
                session.save(roleAdmin);
                Permission_PermissionRole permPermrole = new Permission_PermissionRole();
                permPermrole.setPermission(permAdminArea);
                permPermrole.setRole(roleAdmin);
                session.save(permPermrole);
            }
        }
        // Setup permissionrole "Employee"
        request = "FROM PermissionRole WHERE name = 'Employee'";
        query2 = session.createQuery(request, PermissionRole.class);
        PermissionRole roleEmployee = null;
        try {
            roleEmployee = query2.uniqueResult();
        } catch (PersistenceException e) {
            return false;
        }
        if (roleEmployee == null) {
            arePermissionsReady = false;
            if (change) {
                roleEmployee = new PermissionRole();
                roleEmployee.setName("Employee");
                session.save(roleEmployee);
            }
        }

        if (change && !arePermissionsReady) {
            try {
                session.getTransaction().commit();
                arePermissionsReady = true;
            } catch (IllegalStateException e) {
                log.error(String.format("Unable to commit the transaction : %s", e.getMessage()));
            } catch (RollbackException e) {
                log.error(String.format("Unable to commit the transaction : %s", e.getMessage()));
            }
            session.close();
        }
        return arePermissionsReady;
    }


}

While looking for the error I tried to get me some more Debug content, so I replaced the line, where the Exception ocurred and I inserted the following code into DataOperator:

Object result = query.uniqueResult();
String resultType = result.getClass().toString();
boolean test = result instanceof Permission;
boolean test2 = Permission.class.toString().equals(resultType);

I set a stop after this segment and when debugging while running it with Spring I got:

result: Permission@47 "{ id='15', name='Acess AdminArea'}"
resultType: "class project.db.dbmodels.Permission"
test: false
test2: true

While running a unit test i got:

result: Permission@47 "{ id='15', name='Acess AdminArea'}"
resultType: "class project.db.dbmodels.Permission"
test: true
test2: true

Edit: They have different class loaders. sun.misc.Launcher$AppCLassLoader and org.springframework.boot.devtools.restart.classloader.RestartClassLoader.

What can I do about that?


Solution

  • As mentioned by Ed Schaller in another response the problem came from the fact that the classes were loaded from two different entities.

    Although, instead of changing the classpath, I found a way to fix this by using a BootstrapServiceRegistry and adding the class loaders of both the application and hibernate.

    public class HibernateUtil {
        private static SessionFactory sessionFactory;
        static {
            final StandardServiceRegistry registry = new StandardServiceRegistryBuilder(
                    createHibernateBootstrapServiceRegistry()).configure().build();
            try {
                sessionFactory = new MetadataSources(registry).buildMetadata().buildSessionFactory();
            } catch (Exception e) {
                StandardServiceRegistryBuilder.destroy(registry);
            }
        }
    
        private static BootstrapServiceRegistry createHibernateBootstrapServiceRegistry() {
            ClassLoader tccl = Thread.currentThread().getContextClassLoader();
            ClassLoader hibernateCl = BootstrapServiceRegistry.class.getClassLoader();
            return new BootstrapServiceRegistryBuilder().applyClassLoader(tccl).applyClassLoader(hibernateCl).build();
        }
    
        public static Session openSession() {
            return sessionFactory.openSession();
        }
    }