Skip to main content

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [List Home]
Re: [eclipselink-users] ReadAllQuery fails in checkPrepare due to NullPointerException

I hit this and have a fix locally, but haven’t gotten around to checking bugzilla and submitting a patch. There are a few other issues with schema per tenant I’m looking into (sequencing with inheritance) as well.

If you file it, I can upload the changes I have and see it fixes it for you.



On Dec 13, 2019, at 5:32 AM, unimatrix-0 webmaster <webmaster@xxxxxxxxxxxxxx> wrote:

Dear all,

I have a problem with schema based multitenancy:

I am developing a multitenancy enabled application. The multitenancy is schema based. Frameworks used so far are eclipselink 2.7.5, Spring data jpa 2.2.0.RELEASE and PostgreSQL. Creating, finding and deleting single entities works fine so far. A simple "findAll" works as well. However I have a problem with custom repository methods.

One entity is defined like this:

@Entity
@Table(name = "HISTORY")
@Multitenant(MultitenantType.TABLE_PER_TENANT)
@TenantTableDiscriminator(type = TenantTableDiscriminatorType.SCHEMA, contextProperty = PersistenceUnitProperties.MULTITENANT_PROPERTY_DEFAULT)
@IdClass(SimpleLongId.class)
public class History implements Serializable {
    @Id
    @TableGenerator(name = "TABLE_GEN_HIST",
            table = "SEQUENCE_TABLE",
            pkColumnName = "SEQ_NAME",
            valueColumnName = "SEQ_COUNT",
            pkColumnValue = "HIST_SEQ")
    @GeneratedValue(strategy = GenerationType.AUTO)
    Long id;

    @Column(nullable = false)
    Long fkParentId;

    @Temporal(TemporalType.TIMESTAMP)
    @Column(nullable = true)
    private Date lastrun;

    @Temporal(TemporalType.TIMESTAMP)
    @Column(nullable = false)
    private Date startDateTime;

    @Temporal(TemporalType.TIMESTAMP)
    @Column(nullable = true)
    private Date endDateTime;

    @Column
    private String status;

    @Temporal(TemporalType.TIMESTAMP)
    @Column(nullable = false)
    private Date modified;

    @Temporal(TemporalType.TIMESTAMP)
    @Column(nullable = false)
    private Date created;

    @OneToMany(fetch = FetchType.EAGER, mappedBy = "history", cascade = CascadeType.ALL)
    @JoinColumns({
            @JoinColumn(name = "HISTORY_ID", referencedColumnName = "HISTORY_ID", nullable = false)})
    @CascadeOnDelete
    List<HistoryRecord> entries;

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public Date getLastrun() {
        return lastrun;
    }

    public void setLastrun(Date lastrun) {
        this.lastrun = lastrun;
    }

    public Date getStartDateTime() {
        return startDateTime;
    }

    public void setStartDateTime(Date startDateTime) {
        this.startDateTime = startDateTime;
    }

    public Date getEndDateTime() {
        return endDateTime;
    }

    public void setEndDateTime(Date endDateTime) {
        this.endDateTime = endDateTime;
    }

    public String getStatus() {
        return status;
    }

    public void setStatus(String status) {
        this.status = status;
    }

    public Date getModified() {
        return modified;
    }

    public void setModified(Date modified) {
        this.modified = modified;
    }

    public Date getCreated() {
        return created;
    }

    public void setCreated(Date created) {
        this.created = created;
    }

    public List<HistoryRecord> getEntries() {
        return entries;
    }

    public void setEntries(List<HistoryRecord> entries) {
        this.entries = entries;
    }

    public Long getFkParentId() {
        return fkParentId;
    }

    public void setFkParentId(Long fkParentId) {
        this.fkParentId = fkParentId;
    }

    @PrePersist
    public void prePersist() {
        Date now = new Date();
        created = now;
        modified = now;
    }

    @PreUpdate
    public void preUpdate() {
        modified = new Date();
    }

    public String toString() {
        StringBuilder sb = new StringBuilder();
        sb.append("id: ").append(getId());
        sb.append(", parentId: ").append(getFkParentId());
        sb.append(", created: ").append(getCreated());
        sb.append(", modified: ").append(getModified());
        sb.append(", startDateTime: ").append(getStartDateTime());
        sb.append(", endDateTime: ").append(getEndDateTime());
        sb.append(", Status: ").append(getStatus());
        return sb.toString();
    }
}

As I want to be able to find all History entities by the field fkParentId I created an additional method in the repository:

    @Query(value = "SELECT h FROM History h WHERE h.fkParentId = :fkParentId", nativeQuery = true)
    public List<History> findAllByFkParentId(@Param("fkParentId") Long fkParentId);

Regardles if I simply use only the method name or add the Query annotation I end up with the following stacktrace:

[EL Finest]: query: 2019-12-04 16:23:16.73--UnitOfWork(2097614581)--Thread(Thread[main,5,main])--Execute query ReadAllQuery(referenceClass=History sql="SELECT h FROM History h WHERE h.fkParentId = :fkParentId")
[EL Warning]: 2019-12-04 16:23:16.741--UnitOfWork(2097614581)--Thread(Thread[main,5,main])--Local Exception Stack: 
Exception [EclipseLink-6168] (Eclipse Persistence Services - 2.7.5.v20191016-ea124dd158): org.eclipse.persistence.exceptions.QueryException
Exception Description: Query failed to prepare, unexpected error occurred: [java.lang.NullPointerException].
Internal Exception: java.lang.NullPointerException
Query: ReadAllQuery(referenceClass=History sql="SELECT h FROM History h WHERE h.fkParentId = :fkParentId")
    at org.eclipse.persistence.exceptions.QueryException.prepareFailed(QueryException.java:1598)
    at org.eclipse.persistence.queries.DatabaseQuery.checkPrepare(DatabaseQuery.java:692)
    at org.eclipse.persistence.queries.ObjectLevelReadQuery.checkPrepare(ObjectLevelReadQuery.java:968)
...
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:763)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:463)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:209)
Caused by: java.lang.NullPointerException
    at org.eclipse.persistence.internal.helper.NonSynchronizedVector.addAll(NonSynchronizedVector.java:315)
    at org.eclipse.persistence.queries.ObjectLevelReadQuery.getSelectionFields(ObjectLevelReadQuery.java:1808)
...

Debugging to the place where the exception is thrown shows me that in the RelationalDescriptor which appears to be used for the "getAllSelectionFields" the property allSelectionFields is null which causes the NullpointerException.

How can solve this? Is there something missing in the annotated entity class?

Many thanks in advance!

P.S.: I posted this question as well on stackoverflow, I hope it is OK reposting it to this user mailing list.


Back to the top