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 @DiscriminatorValue
can 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.
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.