Search code examples
javahibernate

Found org.hibernate.InstantiationException: Cannot instantiate abstract class or interface, but still occurs after revert all changes


I have an abstract class:

@Entity
@Table(name = "cas_base_accounts", schema = "connectors_account_service")
@Inheritance(strategy = InheritanceType.JOINED)
@Data
@SuperBuilder
@NoArgsConstructor
public abstract class BaseAccount {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(unique = true)
    private Integer id;
//some fields here

And two subclasses:

@Entity
@Table(name = "cas_simple_auth_accounts", schema = "connectors_account_service")
@Inheritance(strategy = InheritanceType.JOINED)
@Data
@ToString(callSuper = true)
@EqualsAndHashCode(callSuper = true)
@NoArgsConstructor
@SuperBuilder
public class SimpleAuthAccount extends BaseAccount {


    @Id
    @GeneratedValue
    private Integer id;

    @NotNull
    @JsonIgnore
    private String clientId;

    @NotNull
    @JsonIgnore
    private String clientSecret;
//some other fields

And:

@Entity
@Table(name = "cas_oauth_accounts", schema = "connectors_account_service")
@Inheritance(strategy = InheritanceType.JOINED)
@Data
@ToString(callSuper = true)
@EqualsAndHashCode(callSuper = true)
@NoArgsConstructor
@SuperBuilder
public class OAuthAccount extends BaseAccount {

    @Id
    @GeneratedValue
    private Integer id;

    @JsonIgnore
    private String state;

    @JsonIgnore
    private LocalDateTime stateExpirationTime;

    @Transient
    private String tokenLink;
//some fields

When I ran simple GET request http://localhost:8889/accountservice/accountIds?cabinetId=12 I got an error:

threw exception [Request processing failed; nested exception is org.springframework.orm.jpa.JpaSystemException: Cannot instantiate abstract class or interface:  : 
test.connectorsaccountservice.accountservice.model.BaseAccount; nested exception is org.hibernate.InstantiationException: Cannot instantiate abstract class or interface:  : test.connectorsaccountservice.accountservice.model.BaseAccount] 

Entities with cabinetId = 12 is always a SimpleAuthAccount. When I ran for example cabinetId = 10, it returns correct result. In this case entities with id != 12 (and 21) are OauthAccount.

It shows that error occurs in this method:

    public Mono<List<Integer>> getAccountIds(Integer cabinetId) {
        return findServiceByCabinetId(cabinetId)
                .then(Mono.fromCallable(() -> baseAccountRepository.findByCabinetId(cabinetId)))
                .flatMapIterable(e -> e)
                .filter(oAuthAccount -> !oAuthAccount.getIsDeleted()
                        && UserStatus.ENABLED.equals(oAuthAccount.getUserStatus()))
                .map(BaseAccount::getId)
                .collectList();
    }

At this line:

.then(Mono.fromCallable(() -> baseAccountRepository.findByCabinetId(cabinetId)))

Repository:

public interface BaseAccountRepository extends JpaRepository<BaseAccount, Integer> {

    Optional<BaseAccount> findByIdAndCabinetId(Integer accountId, Integer cabinetId);

    Optional<BaseAccount> findByCabinetIdAndAccountLogin(Integer cabinetId, String accountLogin);

    List<BaseAccount> findByCabinetId(Integer cabinetId);

SimpleAuthAccountRepository:

@Repository
public interface SimpleAuthAccountRepository extends
        JpaRepository<SimpleAuthAccount, Integer>,
        CustomAccountRepository<SimpleAuthAccount, Integer> {

    @Query("SELECT a FROM SimpleAuthAccount a " +
           "JOIN BaseCabinet c ON a.cabinetId = c.id " +
           "WHERE " +
           "(:realmId IS NULL OR a.realmId = :realmId) AND " +
           "(:accountLogin IS NULL OR a.accountLogin = :accountLogin) AND " +
           "(:accountId IS NULL OR a.id = :accountId) AND " +
           "(:cabinetId IS NULL OR a.cabinetId = :cabinetId) AND " +
           "(:isDeleted IS NULL OR a.isDeleted = :isDeleted) AND " +
           "((:advertiserIds) IS NULL OR a.advertiserId IN (:advertiserIds)) " +
           "ORDER BY c.description, a.accountLogin")
    List<SimpleAuthAccount> findAccounts(
            @Param("realmId") Integer realmId,
            @Param("accountLogin") String accountLogin,
            @Param("accountId") Integer accountId,
            @Param("cabinetId") Integer cabinetId,
            @Param("isDeleted") Boolean isDeleted,
            @Param("advertiserIds") Set<Integer> advertiserIds
    );

}

Btw, seems like It works before, but I made some changes. After this error happened I revert all changes but error still occurs. And in these changes I didnt touch any classes from this post, only others.

How to fix it? And why this happened and why this still happens after reverted changes? I guess adding @DiscriminatorColumn and @DiscriminatorValuecan help? For me existing column cabinetId will be good as @DiscriminatorColumn, but how can I set value for this if I have an array of ids for SimpleAuthAccount and arrays of ids for OAuthAccount? I really don't want to add another column to this table. But of course if there are no more solutions here I could add column like auth_type and set SIMPLE_AUTH and OAUTH for these classes.


Solution

  • In your db you have records in cas_base_accounts without corresponding records in cas_simple_auth_accounts or cas_oauth_accounts.

    Hibernate think it means such records have type BaseAccount and tries to instantiate that class.