Search code examples
spring-data-jpamultiple-inheritancemappedsuperclass

How to implement database inheritance in Spring Data JPA with MapperSuperClass?


I'm trying out database inheritance of type JOINED in Spring Data JPA, referring to this article. This worked fine. But I've to implement MappedSuperClass in my project. I've implemented in the following way:

Base.java

@MappedSuperclass
public abstract class Base {
    public abstract Long getId();
    public abstract void setId(Long id);
    public abstract String getFirstName();
    public abstract void setFirstName(String firstName);
}

BaseImpl.java

@Entity
@Inheritance(strategy = InheritanceType.JOINED)
public class BaseImpl extends Base {
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Long id;
    private String firstName;

    ...
}

Super1.java

@MappedSuperclass
public abstract class Super1 extends BaseImpl {
    public abstract String getSuperName();
    public abstract void setSuperName(String guideName);
}

Super1Impl.java

@Entity
public class Super1Impl extends Super1 {
    private String superName;

    ...
}

BaseBaseRepository.java

@NoRepositoryBean
public interface BaseBaseRepository<T extends Base> extends JpaRepository<T, Long> { }

BaseRepository.java

@NoRepositoryBean
public interface BaseRepository<T extends Base> extends BaseBaseRepository<Base> { }

BaseRepositoryImpl.java

@Transactional
public interface BaseRepositoryImpl extends BaseRepository<BaseImpl> { }

Super1Repository.java

@NoRepositoryBean
public interface Super1Repository<T extends Super1> extends BaseBaseRepository<Super1> { }

Super1RepositoryImpl.java

@Transactional
public interface Super1RepositoryImpl extends Super1Repository<Super1Impl> {  }

I'm trying to save a Super1 object in a test case:

@Test
public void contextLoads() {
    Super1 super1 = new Super1Impl();
    super1.setSuperName("guide1");
    super1.setFirstName("Mamatha");
    super1.setEmail("jhhj");
    super1.setLastName("kkjkjhjk");
    super1.setPassword("jhjjh");
    super1.setPhoneNumber("76876876");

    System.out.println(super1Repository.save(super1));
}

But I'm getting the following error:

Caused by: org.springframework.beans.factory.BeanCreationException:
  Error creating bean with name 'baseRepositoryImpl':
    Invocation of init method failed; nested exception is java.lang.IllegalArgumentException:
      This class [class com.example.entity.Base] does not define an IdClass
.....
Caused by: java.lang.IllegalArgumentException: This class [class com.example.entity.Base] does not define an IdClass
.......

Tried out @PrimaryKeyJoinColumn(name = "id", referencedColumnName = "id") in Super1Impl, but still getting the same error.


Solution

  • The error is caused by incorrect repository interface declarations.

    BaseRepository<T extends Base> extends BaseBaseRepository<Base>
    

    should be

    BaseRepository<T extends Base> extends BaseBaseRepository<T>
    

    and

    Super1Repository<T extends Super1> extends BaseBaseRepository<Super1>
    

    should be

    Super1Repository<T extends Super1> extends BaseBaseRepository<T>
    

    As currently declared, BaseBaseRepository<Base> means a repository of Base objects and Base does not have an @Id field, hence the error.