2

I have a datamodel with multiple layers of inheritance. As long as every layer contains only one class, I have no problem generating my database schema. When I add another class to the last layer, I get an exception when trying to generate the schema:

Exception Description: Predeployment of 
  PersistenceUnit [JPA] failed.
Internal Exception: java.lang.NullPointerException

My datamodel is implemented as follows:

PersistentEntiy.java

@Data
@AllArgsConstructor
@NoArgsConstructor
@Getter(value = AccessLevel.PROTECTED)
@Setter(value = AccessLevel.NONE)
@MappedSuperclass
@IdClass(DatabaseId.class)
public abstract class PersistentEntity {

  @Id
  @Column(name = "ID", nullable = false)
  @NonNull
  @Setter(value = AccessLevel.NONE)
  private UUID id;

  @Id
  @Column(name = "LAST_MODIFIED", nullable = false)
  @NonNull
  @Setter(value = AccessLevel.NONE)
  private LocalDateTime lastModified;

}

Booking.java

@EqualsAndHashCode(callSuper = true)
@Data
@NoArgsConstructor
@Setter(AccessLevel.NONE)
@Entity
@Inheritance(strategy = InheritanceType.JOINED)
@Table(name = "BOOKINGS", uniqueConstraints = {
    @UniqueConstraint(columnNames = {"TARGETCASHREGISTER", "BOOKINGNUMBER"})
})
public class Booking extends PersistentEntity {

  @Column(nullable = false, precision = 36, scale = 2)
  @DecimalMin("0.01")
  @NonNull
  private BigDecimal amount;
  @Column(nullable = false)
  @NonNull
  private String text;
  @Column(nullable = false)
  private boolean isInPayment;
  @Column(nullable = false)
  @NonNull
  private UUID targetCashRegister;
  @Column(nullable = false)
  private long bookingNumber;
  @Column(nullable = false)
  @NonNull
  private String affiliate;
  @Transient
  private boolean isAnnulated = false;

  ...
}

CashContribution.java

@EqualsAndHashCode(callSuper = true)
@NoArgsConstructor
@Entity
@Table(name = "CASHCONTRIBUTIONS")
public class CashContribution extends Booking {
  ...
}

Until this point everything works fine. But when adding the following class, the schema generation fails.

CashRetrieval.java

@EqualsAndHashCode(callSuper = true)
@NoArgsConstructor
@Entity
@Table(name = "CASHRETRIEVALS")
public class CashRetrieval extends Booking {
  ...
}

Note: This project makes heavy use of lombok annotations to generate code at compile time.

Can anyone help me fix this issue?


Edit 1: Full stacktrace

Exception in thread "main" Local Exception Stack: 
Exception [EclipseLink-30005] (Eclipse Persistence Services - 2.7.0.v20170811-d680af5): org.eclipse.persistence.exceptions.PersistenceUnitLoadingException
Exception Description: An exception was thrown while searching for persistence archives with 
ClassLoader: sun.misc.Launcher$AppClassLoader@18b4aac2
Internal Exception: javax.persistence.PersistenceException: Exception [EclipseLink-28018] (Eclipse Persistence Services - 2.7.0.v20170811-d680af5): org.eclipse.persistence.exceptions.EntityManagerSetupException
Exception Description: Predeployment of PersistenceUnit [JPA] failed.
Internal Exception: java.lang.NullPointerException
  at org.eclipse.persistence.exceptions.PersistenceUnitLoadingException.exceptionSearchingForPersistenceResources(PersistenceUnitLoadingException.java:127)
  at org.eclipse.persistence.jpa.PersistenceProvider.createEntityManagerFactoryImpl(PersistenceProvider.java:115)
  at org.eclipse.persistence.jpa.PersistenceProvider.createEntityManagerFactory(PersistenceProvider.java:188)
  at javax.persistence.Persistence.createEntityManagerFactory(Persistence.java:79)
  at javax.persistence.Persistence.createEntityManagerFactory(Persistence.java:54)
  at com.gipa.kassenbuch.Main.<init>(Main.java:16)
  at com.gipa.kassenbuch.Main.main(Main.java:26)
Caused by: javax.persistence.PersistenceException: Exception [EclipseLink-28018] (Eclipse Persistence Services - 2.7.0.v20170811-d680af5): org.eclipse.persistence.exceptions.EntityManagerSetupException
Exception Description: Predeployment of PersistenceUnit [JPA] failed.
Internal Exception: java.lang.NullPointerException
  at org.eclipse.persistence.internal.jpa.EntityManagerSetupImpl.createPredeployFailedPersistenceException(EntityManagerSetupImpl.java:2080)
  at org.eclipse.persistence.internal.jpa.EntityManagerSetupImpl.predeploy(EntityManagerSetupImpl.java:2071)
  at org.eclipse.persistence.internal.jpa.deployment.JPAInitializer.callPredeploy(JPAInitializer.java:101)
  at org.eclipse.persistence.jpa.PersistenceProvider.createEntityManagerFactoryImpl(PersistenceProvider.java:104)
  ... 5 more
Caused by: Exception [EclipseLink-28018] (Eclipse Persistence Services - 2.7.0.v20170811-d680af5): org.eclipse.persistence.exceptions.EntityManagerSetupException
Exception Description: Predeployment of PersistenceUnit [JPA] failed.
Internal Exception: java.lang.NullPointerException
  at org.eclipse.persistence.exceptions.EntityManagerSetupException.predeployFailed(EntityManagerSetupException.java:231)
  ... 9 more
Caused by: java.lang.NullPointerException
  at org.eclipse.persistence.internal.jpa.metadata.MetadataDescriptor.setPKClass(MetadataDescriptor.java:1846)
  at org.eclipse.persistence.internal.jpa.metadata.inheritance.InheritanceMetadata.process(InheritanceMetadata.java:244)
  at org.eclipse.persistence.internal.jpa.metadata.accessors.classes.EntityAccessor.processTableAndInheritance(EntityAccessor.java:1390)
  at org.eclipse.persistence.internal.jpa.metadata.accessors.classes.EntityAccessor.process(EntityAccessor.java:683)
  at org.eclipse.persistence.internal.jpa.metadata.MetadataProject.processStage2(MetadataProject.java:1876)
  at org.eclipse.persistence.internal.jpa.metadata.MetadataProcessor.processORMMetadata(MetadataProcessor.java:575)
  at org.eclipse.persistence.internal.jpa.deployment.PersistenceUnitProcessor.processORMetadata(PersistenceUnitProcessor.java:610)
  at org.eclipse.persistence.internal.jpa.EntityManagerSetupImpl.predeploy(EntityManagerSetupImpl.java:1992)
  ... 7 more

Main.java

public class Main {

  private final EntityManager manager;

  public Main () {
    EntityManagerFactory factory = Persistence.createEntityManagerFactory("JPA");
    manager = factory.createEntityManager();
  }

  public void run() {
    final DatabaseProvider provider = DatabaseProvider.getInstance();
  }

  public static void main(String[] args) {
    new Main().run();
  }

}
tgr
  • 3,557
  • 4
  • 33
  • 63
  • do you understand why this is not enough information for us to pinpoint the exact issue? – Stultuske Jun 18 '18 at 08:34
  • What do you need in addition? – tgr Jun 18 '18 at 08:35
  • check what field triggers the NPE, check where it (should be) is instantiated, check whether the value is exactly what you believe it (ought to be) is – Stultuske Jun 18 '18 at 08:36
  • When you get a NullPointerException the stack trace gives the location. Please post the stack trace. – ewramner Jun 18 '18 at 08:41
  • There is no additional field in neither `CashContribution` nor `CashRetrieval`. The exception message does not state anything else, the only classes mentioned are classes from JPA itself and the class with the `main` method, where the EntityManagerFactory is created. – tgr Jun 18 '18 at 08:41
  • If you turn logging on to fine or finest, the logging should show what class it is processing when it gets that error. I'm not sure why a lastModified field should be used as an ID field - have you tried making it a simple pk and see if that helps? – Chris Jun 18 '18 at 14:17
  • 1
    You might try adding the IdClass annotation to the root entity, booking class. Looks like a bug in the inheritance parsing that subclasses can't find it if it is in an abstract mappedsuperclass – Chris Jun 18 '18 at 14:44
  • The last modified field is used for keeping a journal like history. It was a (financial) business requirement, that an entry may never change. Therefore we decided to incorporate the timestamp as part of the primary key. Maybe the field name is a little irritating. – tgr Jun 19 '18 at 05:23
  • @Chris: Please make your suggestion with the `@IdClass` annotation an answer, so I can accept it. This really solved my problem. – tgr Jun 19 '18 at 05:29

1 Answers1

1

The stack trace shows it is unable to find the IdClass in the inheritance root entity. This seems a bug in the mappedsupperclass parsing which can be worked around by putting the @IdClass(DatabaseId.class) annotation on the Booking class.

Chris
  • 20,138
  • 2
  • 29
  • 43