Hibernate Inheritance Mapping with SpringBoot – cast class Exception

I have this object:

@Entity
@Table(name = "PERSONNE")
@NamedQuery(name = "Personne.findAll", query = "SELECT p FROM Personne p")
@Inheritance(strategy = InheritanceType.JOINED)
@ClassExtractor(PersonneClassExtractor.class)
@NoArgsConstructor
@AllArgsConstructor
@Data
@SuperBuilder
@ToString(of = { "personneId", "perId" })
@EqualsAndHashCode(of = { "personneId", "perId" })
public class Personne  implements  Serializable {

    private static final long serialVersionUID = 1L;

    @Id
    @ReturnInsert    
    @Column(name = "PERSONNE_ID")
    protected Long personneId;

..
}

and this one:

@Entity
@Table(name = "ENFANT")
@NamedQuery(name = "Enfant.findAll", query = "SELECT e FROM Enfant e")
@PrimaryKeyJoinColumn(name = "PERSONNE_ID")
@Inheritance(strategy = InheritanceType.JOINED)
@Data
@SuperBuilder
@NoArgsConstructor
@ToString(callSuper = true)
@EqualsAndHashCode(callSuper = true)
@Audit
public class Enfant extends Personne {

    private static final long serialVersionUID = 1L;
..
}

and this:

@Repository
public interface EnfantRepository extends PersonneBaseRepository<Enfant>,
        JpaSpecificationExecutor<Enfant> {

    @Query("SELECT e FROM Enfant e WHERE e.personneId = ?1")
    Enfant findOne(Long enfantId);
..
}

and

@NoRepositoryBean
public interface PersonneBaseRepository<T extends Personne> 
        extends JpaRepository<T, Long> {

}

but when I do

Enfant enfant = enfantRepo.findOne(7L);

I have this error:

 class com.mundos.model.persons.Personne cannot be cast to class com.mundos.model.persons.Enfant (com.mundos.model.persons.Personne and com.mundos.model.persons.Enfant are in unnamed module of loader org.apache.catalina.loader.ParallelWebappClassLoader @67cae0fe)

I also tried enfantRepo.findById with the same result

Answer

The findOne method provided by JpaSpecificationExecutor contract and the implementation underneath (`SimpleJpaRepository) has seen some changes in different spring-data-jpa project versions.

While this is not clear given the reported error, but the runtime may be generating a new query on-fly that does not match your polymorphic structure (you can activate hibernate SQL logging to inspect these).

That being said, you are better off using the findById and getById ready alternatives instead of creating your own query-based method. You should remove your custom findOne method out of your JpaRepository declaration:

@Repository
public interface EnfantRepository extends PersonneBaseRepository<Enfant>, JpaSpecificationExecutor<Enfant> {

    // ...
}

You are then able to query the Enfant entity based on its identifier:

Enfant enfant = enfantRepo.findById(7L).orElseThrow(() -> new EntityNotFoundException(id));

Or simply bypassing the Optional return value using the getById alternative:

Enfant enfant = enfantRepo.getById(7L);