Failed to load entities regarding objectid-class
Environment
Running `/Users/onacit/gitcl/github.com/jinahya/mysql-emploees-persistence/mvnw`...
Apache Maven 3.9.6 (bc0240f3c744dd6b6ec2920b3cd08dcc295161ae)
Maven home: /Users/onacit/.m2/wrapper/dists/apache-maven-3.9.6-bin/3311e1d4/apache-maven-3.9.6
Java version: 21.0.2, vendor: IBM Corporation, runtime: /Library/Java/JavaVirtualMachines/ibm-semeru-open-21.jdk/Contents/Home
Default locale: en_US, platform encoding: UTF-8
OS name: "mac os x", version: "14.3.1", arch: "aarch64", family: "mac"
Dependencies
<dependency>
<groupId>org.datanucleus</groupId>
<artifactId>datanucleus-accessplatform-jakarta-rdbms</artifactId>
<version>6.0.7</version>
<type>pom</type>
</dependency>
Description
With following classs,
@MappedSuperclass
abstract class BaseEntity<ID extends Serializable> implements Serializable {
@Serial
private static final long serialVersionUID = -3812806986886347446L;
}
@Setter
@Getter
@ToString(callSuper = true)
@NoArgsConstructor//(access = AccessLevel.PROTECTED)
public class SalaryId implements BaseId {
@Serial
private static final long serialVersionUID = -378954798191441067L;
@Override
public final boolean equals(final Object obj) {
if (this == obj) {
return true;
}
if (!(obj instanceof SalaryId that)) {
return false;
}
return Objects.equals(empNo, that.empNo) &&
Objects.equals(fromDate, that.fromDate);
}
@Override
public final int hashCode() {
return Objects.hash(empNo, fromDate);
}
@NotNull
private Integer empNo;
@NotNull
private LocalDate fromDate;
}
@IdClass(SalaryId.class)
@Entity
@Table(name = Salary.TABLE_NAME)
@Setter
@Getter
@ToString(callSuper = true)
@NoArgsConstructor
@SuppressWarnings({
"java:S1700" // ... salary;
})
public class Salary extends BaseEntity<Integer> {
@Serial
private static final long serialVersionUID = 604718367871825963L;
// -----------------------------------------------------------------------------------------------------------------
public static final String TABLE_NAME = "salaries";
// -----------------------------------------------------------------------------------------------------------------
public static final String COLUMN_NAME_EMP_NO = Employee.COLUMN_NAME_EMP_NO;
// ---------------------------------------------------------------------------------------------------------- salary
public static final String COLUMN_NAME_SALARY = "salary";
// ------------------------------------------------------------------------------------------------------- from_date
public static final String COLUMN_NAME_FROM_DATE = "from_date";
// --------------------------------------------------------------------------------------------------------- to_date
public static final String COLUMN_NAME_TO_DATE = "to_date";
// ------------------------------------------------------------------------------------------------ java.lang.Object
@Override
public boolean equals(final Object obj) {
if (this == obj) {
return true;
}
if (!(obj instanceof Salary that)) {
return false;
}
return Objects.equals(empNo, that.empNo) &&
Objects.equals(fromDate, that.fromDate);
}
@Override
public int hashCode() {
return Objects.hash(empNo, fromDate);
}
// ------------------------------------------------------------------------------------------------- Bean-Validation
//@AssertTrue
private boolean isFromDateLessThanOrEqualToToDate() {
if (fromDate == null || toDate == null) {
return true;
}
return !fromDate.isAfter(toDate);
}
// -------------------------------------------------------------------------------------------------- empNo/employee
public Employee getEmployee() {
return employee;
}
public void setEmployee(final Employee employee) {
this.employee = employee;
setEmpNo(
Optional.ofNullable(this.employee)
.map(Employee::getEmpNo)
.orElse(null)
);
}
// ---------------------------------------------------------------------------------------------------------- salary
// -------------------------------------------------------------------------------------------------------- fromDate
// ---------------------------------------------------------------------------------------------------------- toDate
// -----------------------------------------------------------------------------------------------------------------
@NotNull
@Id
@Column(name = COLUMN_NAME_EMP_NO, nullable = false, insertable = true, updatable = false)
private Integer empNo;
@Valid
@ManyToOne(optional = false, fetch = FetchType.LAZY)
@JoinColumn(name = COLUMN_NAME_EMP_NO, nullable = false, insertable = false, updatable = false)
@EqualsAndHashCode.Exclude
@ToString.Exclude
private Employee employee;
// -----------------------------------------------------------------------------------------------------------------
//@Positive
@NotNull
@Basic(optional = false)
@Column(name = COLUMN_NAME_SALARY, nullable = false, insertable = true, updatable = true)
private Integer salary;
// -----------------------------------------------------------------------------------------------------------------
@NotNull
@Id
@Basic(optional = false)
@Column(name = COLUMN_NAME_FROM_DATE, nullable = false, insertable = true, updatable = true)
private LocalDate fromDate;
@NotNull
@Basic(optional = false)
@Column(name = COLUMN_NAME_TO_DATE, nullable = false, insertable = true, updatable = true)
private LocalDate toDate;
}
Failed to load the persistence unit.
Caused by: org.datanucleus.metadata.InvalidClassMetaDataException: Class "....Salary" has the persistence-capable-superclass ....BaseEntity, but defines a different objectid-class than its superclass. No objectid-class should be specified because the superclasses id is always used.
at org.datanucleus.metadata.AbstractClassMetaData.inheritIdentity(AbstractClassMetaData.java:782)
at org.datanucleus.metadata.ClassMetaData.populate(ClassMetaData.java:180)
at org.datanucleus.metadata.MetaDataManagerImpl$1.run(MetaDataManagerImpl.java:2822)
at java.base/java.security.AccessController.doPrivileged(AccessController.java:319)
at org.datanucleus.metadata.MetaDataManagerImpl.populateAbstractClassMetaData(MetaDataManagerImpl.java:2816)
at org.datanucleus.metadata.MetaDataManagerImpl.populateFileMetaData(MetaDataManagerImpl.java:2617)
at org.datanucleus.metadata.MetaDataManagerImpl.initialiseFileMetaDataForUse(MetaDataManagerImpl.java:1345)
at org.datanucleus.metadata.MetaDataManagerImpl.loadPersistenceUnit(MetaDataManagerImpl.java:1124)
at org.datanucleus.api.jakarta.JakartaEntityManagerFactory.initialiseNucleusContext(JakartaEntityManagerFactory.java:919)
at org.datanucleus.api.jakarta.JakartaEntityManagerFactory.initialise(JakartaEntityManagerFactory.java:513)
at org.datanucleus.api.jakarta.JakartaEntityManagerFactory.<init>(JakartaEntityManagerFactory.java:417)
at org.datanucleus.api.jakarta.PersistenceProviderImpl.createEntityManagerFactory(PersistenceProviderImpl.java:103)
at jakarta.persistence.Persistence.createEntityManagerFactory(Persistence.java:90)
at jakarta.persistence.Persistence.createEntityManagerFactory(Persistence.java:66)
As a guess, by not specifying an IdClass for the base class it probably defaults to using a simple 'long' for the OID and it expects that to be used for all subclasses but in your subclass Salary you have specified:
@IdClass(SalaryId.class)
which clashes with the default set for the base class - just a theory ;)
I've always used a separate meta data file (.jdo) to avoid spraying persistence annotations throughout the model classes' source code so I'm not familiar with some of those annotation but just guessing from their names.
@chrisco484 Thank you for you comment, sir. Yes the fault is mine. I should've specify the right id type.
class Salary extends BaseEntity<SalaryId>
I still seeing
Class "....Salary" has the persistence-capable-superclass ...._BaseEntity,
but defines a different objectid-class than its superclass.
No objectid-class should be specified because the superclasses id is always used.
@MappedSuperclass
public abstract class _BaseEntity<ID extends Serializable> implements Serializable {
}
interface _BaseId extends Serializable {
}
@Setter
@Getter
@ToString(callSuper = true)
@NoArgsConstructor//(access = AccessLevel.PROTECTED)
public class SalaryId implements _BaseId {
@NotNull
private Integer empNo;
@NotNull
private LocalDate fromDate;
}
@IdClass(SalaryId.class)
@Entity
@Table(name = Salary.TABLE_NAME)
@Setter
@Getter
@ToString(callSuper = true)
@NoArgsConstructor
@SuppressWarnings({
"java:S1700" // ... salary;
})
public class Salary extends _BaseEntity<SalaryId> {
@NotNull
@Id
@Column(name = COLUMN_NAME_EMP_NO, nullable = false, insertable = true, updatable = false)
private Integer empNo;
@NotNull
@Id
@Basic(optional = false)
@Column(name = COLUMN_NAME_FROM_DATE, nullable = false, insertable = true, updatable = true)
private LocalDate fromDate;
}
I may be not sure what I'm talking about... but,
// AbstractClassMetaData.java
...
if (superObjectIdClass == null || !objectidClass.equals(superObjectIdClass))
{
throw new InvalidClassMetaDataException("044085", fullName, persistableSuperclass);
}
...
Shouldn't it be...
if (superObjectIdClass != null && !objectidClass.equals(superObjectIdClass))
{
throw new InvalidClassMetaDataException("044085", fullName, persistableSuperclass);
}
Impossible to comment on something that can't be easily seen. Kindly follow https://www.datanucleus.org/documentation/problem_reporting.html#jpa
I may be not sure what I'm talking about... but,
// AbstractClassMetaData.java ... if (superObjectIdClass == null || !objectidClass.equals(superObjectIdClass)) { throw new InvalidClassMetaDataException("044085", fullName, persistableSuperclass); } ...Shouldn't it be...
if (superObjectIdClass != null && !objectidClass.equals(superObjectIdClass)) { throw new InvalidClassMetaDataException("044085", fullName, persistableSuperclass); }
That looks ok, the intent is to throw the exception if superObjectIdClass is not equal to objectidClass which it won't be if null (hence the first == null is correct).