Spring Boot实体类NullPointerException问题排查与解决求助
问题:JPA多主键实体查询时抛出NullPointerException
实体类代码
Evolution 实体
@Getter @Setter @NoArgsConstructor @AllArgsConstructor @Entity @Table(name = "evolutions") @IdClass(value = EvolutionPkey.class) public class Evolution { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) @Column(name = "pokemon_id") private int pokemonId; @Id @GeneratedValue(strategy = GenerationType.IDENTITY) @Column(name = "form_id") private int formId; @Id @GeneratedValue(strategy = GenerationType.IDENTITY) @Column(name = "next_pokemon_id") private int nextPokemonId; @Id @GeneratedValue(strategy = GenerationType.IDENTITY) @Column(name = "next_form_id") private int nextFormId; @Column(nullable = false) private int stage; @ManyToOne @JoinColumn(name = "pokemon_id", referencedColumnName = "pokemon_id") private Pokemon pokemon; }
EvolutionPkey 主键类
@Data @Getter @Setter @NoArgsConstructor @AllArgsConstructor public class EvolutionPkey implements Serializable{ public int pokemonId; public int formId; public int nextPokemonId; public int nextFormId; }
Pokemon 实体
public class Pokemon { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) @Column(name = "pokemon_id") private int pokemonId; @Id @GeneratedValue(strategy = GenerationType.IDENTITY) @Column(name = "form_id") private int formId; // 其他字段省略 @OneToMany(mappedBy = "pokemon", cascade=CascadeType.ALL) private List<Evolution> evolutions; }
Repository与查询代码
PokemonRepository 接口
public interface PokemonRepository extends JpaRepository<Pokemon, PokemonPkey>, JpaSpecificationExecutor<Pokemon> { public Optional<List<Pokemon>> findByPokemonId(int pokemonId); }
服务类查询代码
@Autowired private PokemonRepository pokemonRepository; pokemonRepository.findByPokemonId(pokemonId)
报错信息
Resolved [java.lang.NullPointerException: Cannot invoke "org.hibernate.metamodel.mapping.AttributeMapping.getStateArrayPosition()" because the return value of "org.hibernate.persister.entity.AbstractEntityPersister.findAttributeMapping(String)" is null]
修复思路
- 修正复合主键的自增配置:Evolution的四个@Id字段全部标注
@GeneratedValue(strategy = GenerationType.IDENTITY)完全不合理,数据库无法同时让四个主键字段自增,这会导致Hibernate无法正确映射主键生成逻辑。需要根据业务逻辑调整:仅保留实际由数据库自增的字段(通常复合主键中不会多个自增),或者去掉不需要自增的主键字段的@GeneratedValue注解。 - 调整主键类的字段访问权限:EvolutionPkey中的字段使用public修饰,不符合JPA规范,应该改为private,并通过@Data注解提供getter/setter(@Data已经包含这些,所以只需把public改成private),确保Hibernate能通过反射正确访问主键字段。
- 补全Pokemon实体的必要注解:Pokemon类缺少
@Entity、@Table注解,同时作为复合主键实体,需要添加@IdClass(PokemonPkey.class)(需创建对应的PokemonPkey主键类),以及@Getter/@Setter或@Data注解,否则JPA无法识别该类为实体类,导致映射错误。 - 修复关联映射的重复列问题:Evolution中
pokemonId既是主键字段,又是@ManyToOne关联的外键列,重复映射会导致Hibernate混淆。应该在@ManyToOne注解上添加@MapsId("pokemonId"),让JPA将关联的Pokemon的主键值映射到Evolution的pokemonId主键字段,避免重复映射同一列:@ManyToOne @MapsId("pokemonId") @JoinColumn(name = "pokemon_id", referencedColumnName = "pokemon_id") private Pokemon pokemon; - 修正Repository方法的返回值:
findByPokemonId方法返回Optional<List<Pokemon>>是错误的,Optional用于包装单个对象,集合类型应该直接返回List<Pokemon>(空集合时返回空列表而非null),正确写法:List<Pokemon> findByPokemonId(int pokemonId);
内容的提问来源于stack exchange,提问作者Hiroto Nakashima
相关产品推荐
相关产品推荐

