You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

执行关联角色权限的JPQL查询时触发Hibernate空指针异常

问题:JPQL查询关联权限时抛出NullPointerException

执行JPQL查询获取特定RoleEntity关联的PermissionEntity时,抛出如下空指针异常:

java.lang.NullPointerException: Cannot invoke "org.hibernate.persister.entity.DiscriminatorType.getJdbcJavaType()" because "this.discriminatorType" is null

问题代码

查询语句:

@Query("SELECT PermissionEntity " +
        "FROM RolePermissionEntity rolePermission " +
        "JOIN PermissionEntity permission " +
        "WHERE rolePermission.role = :role")
List<PermissionEntity> findPermissionsByRoleId(@Param("role") RoleEntity role);

实体模型

RoleEntity

@Entity
@Table(
        name = "roles",
        indexes = {
                @Index(name = "role_name_unique", columnList = "name", unique = true)
        }
)
/* Lombok注解省略 */
public class RoleEntity {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Integer id;

    @Column
    private String name;

    @Transient
    private List<PermissionEntity> permissions;

}

PermissionEntity

@Entity
@Table(
        name = "permissions",
        indexes = {
                @Index(name = "permission_name_unique", columnList = "name", unique = true)
        }
)
/* Lombok注解省略 */
public class PermissionEntity {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Integer id;

    @Column
    private String name;

}

RolePermissionEntity

@Entity
@Table(
        name = "role_permissions"
)
/* Lombok注解省略 */
public class RolePermissionEntity {

    @EmbeddedId
    private RolePermissionId id;

    @MapsId("roleId")
    @ManyToOne
    private RoleEntity role;

    @MapsId("permissionId")
    @ManyToOne
    private PermissionEntity permission;

}

RolePermissionId

@Embeddable
/* Lombok注解省略 */
public class RolePermissionId implements Serializable {

    private Integer roleId;

    private Integer permissionId;

}

环境

Spring Boot 3.0.1 + Spring Data JPA + Hibernate


解决方案

1. 修正JPQL查询语句

原查询存在两个关键错误:

  • SELECT子句误用实体类名PermissionEntity,应改为关联的别名permission
  • JOIN子句直接关联实体类,未通过中间表RolePermissionEntity的关联属性,需改为通过rolePermission.permission建立关联

修正后的查询:

@Query("SELECT permission " +
        "FROM RolePermissionEntity rolePermission " +
        "JOIN rolePermission.permission permission " +
        "WHERE rolePermission.role = :role")
List<PermissionEntity> findPermissionsByRoleId(@Param("role") RoleEntity role);

2. 异常原因说明

该空指针异常源于错误的JPQL关联写法:直接关联PermissionEntity而非通过中间表的permission属性,会导致Hibernate解析实体元数据时误判继承结构(尽管当前实体无继承关系),进而触发鉴别器类型的空指针问题。修正关联方式后,Hibernate可正确识别实体间的关联逻辑,异常即可解决。

可选优化:简化实体关联

若业务允许,可在RoleEntity中直接建立@ManyToMany关联,省略手动维护中间表实体的操作:

@Entity
@Table(name = "roles")
public class RoleEntity {
    // 其他属性不变
    @ManyToMany
    @JoinTable(
        name = "role_permissions",
        joinColumns = @JoinColumn(name = "roleId"),
        inverseJoinColumns = @JoinColumn(name = "permissionId")
    )
    private List<PermissionEntity> permissions;
}

此时可直接使用Spring Data JPA的默认查询方法,或编写更简洁的JPQL语句,无需手动操作中间表实体。


内容的提问来源于stack exchange,提问作者Maxime Esnol

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.02 03:48:29