Nuñito Calzada
Nuñito Calzada

Reputation: 2166

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

Upvotes: 5

Views: 877

Answers (2)

Ravi Parekh
Ravi Parekh

Reputation: 5622

Your error might be misleading, according to this stackoverflow unless you are explicitly casting in your code.

And not sure both are in same jar|library in your code (depends on your structure)!! ERROR: in unnamed module of loader

Try, This may help if devtools is in your classpath.

public static void main(final String[] args) {
    System.setProperty("spring.devtools.restart.enabled", "false");
    SpringApplication.run(Application.class, args);
}

OR

Exclude | Remove

<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-devtools</artifactId>
  <optional>true</optional>
</dependency>

Upvotes: 1

tmarwen
tmarwen

Reputation: 16374

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);

Upvotes: 1

Related Questions