I was able to do something with your question. I defined another class hierarchy: UserWithRole, which extends a user that is similar to yours.
Define the User class as an object with the inheritance strategy SINGLE_TABLE :
@Entity @Inheritance(strategy = InheritanceType.SINGLE_TABLE) @Table(name = "USERS") public class User { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) protected Long id; @Column(nullable = false) protected String name; // toString(), default constructor, setters/getters, more constructors. ... }
This inheritance strategy has one major drawback:
- Subclasses cannot contain nullable columns.
There is another JOINED strategy that allows you to create JOINED columns in subclasses. It creates an additional table for each subclass; these tables have FK in the superclass table.
Define the UserWithRole class:
@Entity public class UserWithRole extends User { private String role; // toString(), default constructor, setters/getters, more constructors. ... }
Add a Helper class to create users in the database and use your query:
@Component public class Helper { @Autowired EntityManager entityManager; @Transactional public void createUsers() { for (long i = 0; i < 10; i++) { User user; if (i % 2 == 0) { user = new UserWithRole("User-" + i, "Role-" + i); } else { user = new User("User-" + i); } entityManager.persist(user); } entityManager.flush(); } @Transactional(readOnly = true) @SuppressWarnings("unchecked") public < T > List < T > get(Class < T > aClass) { SessionFactory sessionFactory = entityManager.getEntityManagerFactory().unwrap(SessionFactory.class); ClassMetadata hibernateMetadata = sessionFactory.getClassMetadata(aClass); if (hibernateMetadata == null) { return null; } if (hibernateMetadata instanceof AbstractEntityPersister) { AbstractEntityPersister persister = (AbstractEntityPersister) hibernateMetadata; String entityName = persister.getEntityName(); if (entityName != null) { return sessionFactory.getCurrentSession(). createQuery("from " + entityName).list(); } } return null; } }
As you can see, I changed my method a bit:
- A generic type has been added to avoid unsafe types;
- The entity name used instead of the table name because HQL expects the entity name.
Let the testing begin
Get all instances of User :
@Test public void testQueryUsers() { helper.createUsers(); for (User user: helper.get(User.class)) { System.out.println(user); } }
Output (users with the role still have UserWithProfile instances at runtime):
UserWithRole{id=1, name='User-0', role='Role-0'} User{id=2, name='User-1'} UserWithRole{id=3, name='User-2', role='Role-2'} User{id=4, name='User-3'} UserWithRole{id=5, name='User-4', role='Role-4'} User{id=6, name='User-5'} UserWithRole{id=7, name='User-6', role='Role-6'} User{id=8, name='User-7'} UserWithRole{id=9, name='User-8', role='Role-8'} User{id=10, name='User-9'}
Hibernate SQL query:
select user0_.id as id2_0_, user0_.name as name3_0_, user0_.role as role4_0_, user0_.dtype as dtype1_0_ from users user0_
Get all instances of UserWithProfile :
@Test public void testQueryUsersWithProfile() { helper.createUsers(); for (User user: helper.get(UserWithRole.class)) { System.out.println(user); } }
Output:
UserWithRole{id=1, name='User-0', role='Role-0'} UserWithRole{id=3, name='User-2', role='Role-2'} UserWithRole{id=5, name='User-4', role='Role-4'} UserWithRole{id=7, name='User-6', role='Role-6'} UserWithRole{id=9, name='User-8', role='Role-8'}
Hibernate SQL query:
select userwithro0_.id as id2_0_, userwithro0_.name as name3_0_, userwithro0_.role as role4_0_ from users userwithro0_ where userwithro0_.dtype = 'UserWithRole'
Please let me know if this is what you were looking for.