Skip to content

FilterExpressionCheck returns Internal Server Error not-null property references a null or transient value on Post operations #3374

@ilCame

Description

@ilCame

Hello, we are having some trouble with the FilterExpressionCheck. When we are doing a Post operation to create a new entity that holds 2 non-null ManyToOne relationships that were previously created, and the call is intercepted by a ReadPermission with a FilterExpressionCheck we got a 500 error with this error:

not-null property references a null or transient value: org.example.permission.permissions.domain.Books.store
	at org.hibernate.engine.internal.Nullability.checkNullability(Nullability.java:112) ~[hibernate-core-6.6.18.Final.jar:6.6.18.Final]
	at org.hibernate.engine.internal.Nullability.checkNullability(Nullability.java:57) ~[hibernate-core-6.6.18.Final.jar:6.6.18.Final]
	at org.hibernate.action.internal.AbstractEntityInsertAction.nullifyTransientReferencesIfNotAlready(AbstractEntityInsertAction.java:126) ~[hibernate-core-6.6.18.Final.jar:6.6.18.Final]
	at org.hibernate.action.internal.EntityIdentityInsertAction.execute(EntityIdentityInsertAction.java:73) ~[hibernate-core-6.6.18.Final.jar:6.6.18.Final]
	at org.hibernate.engine.spi.ActionQueue.execute(ActionQueue.java:682) ~[hibernate-core-6.6.18.Final.jar:6.6.18.Final]
	at org.hibernate.engine.spi.ActionQueue.addResolvedEntityInsertAction(ActionQueue.java:293) ~[hibernate-core-6.6.18.Final.jar:6.6.18.Final]
	at org.hibernate.engine.spi.ActionQueue.addInsertAction(ActionQueue.java:274) ~[hibernate-core-6.6.18.Final.jar:6.6.18.Final]
	at org.hibernate.engine.spi.ActionQueue.addAction(ActionQueue.java:324) ~[hibernate-core-6.6.18.Final.jar:6.6.18.Final]
	at org.hibernate.event.internal.AbstractSaveEventListener.addInsertAction(AbstractSaveEventListener.java:394) ~[hibernate-core-6.6.18.Final.jar:6.6.18.Final]
	at org.hibernate.event.internal.AbstractSaveEventListener.performSaveOrReplicate(AbstractSaveEventListener.java:308) ~[hibernate-core-6.6.18.Final.jar:6.6.18.Final]
	at org.hibernate.event.internal.AbstractSaveEventListener.performSave(AbstractSaveEventListener.java:224) ~[hibernate-core-6.6.18.Final.jar:6.6.18.Final]
	at org.hibernate.event.internal.AbstractSaveEventListener.saveWithGeneratedId(AbstractSaveEventListener.java:136) ~[hibernate-core-6.6.18.Final.jar:6.6.18.Final]
	at org.hibernate.event.internal.DefaultPersistEventListener.entityIsTransient(DefaultPersistEventListener.java:177) ~[hibernate-core-6.6.18.Final.jar:6.6.18.Final]
	at org.hibernate.event.internal.DefaultPersistEventListener.persist(DefaultPersistEventListener.java:95) ~[hibernate-core-6.6.18.Final.jar:6.6.18.Final]
	at org.hibernate.event.internal.DefaultPersistEventListener.onPersist(DefaultPersistEventListener.java:79) ~[hibernate-core-6.6.18.Final.jar:6.6.18.Final]
	at org.hibernate.event.service.internal.EventListenerGroupImpl.fireEventOnEachListener(EventListenerGroupImpl.java:138) ~[hibernate-core-6.6.18.Final.jar:6.6.18.Final]
	at org.hibernate.internal.SessionImpl.persistOnFlush(SessionImpl.java:825) ~[hibernate-core-6.6.18.Final.jar:6.6.18.Final]
	at org.hibernate.engine.spi.CascadingActions$8.cascade(CascadingActions.java:338) ~[hibernate-core-6.6.18.Final.jar:6.6.18.Final]
	at org.hibernate.engine.spi.CascadingActions$8.cascade(CascadingActions.java:328) ~[hibernate-core-6.6.18.Final.jar:6.6.18.Final]
	at org.hibernate.engine.internal.Cascade.cascadeToOne(Cascade.java:570) ~[hibernate-core-6.6.18.Final.jar:6.6.18.Final]
	at org.hibernate.engine.internal.Cascade.cascadeAssociation(Cascade.java:492) ~[hibernate-core-6.6.18.Final.jar:6.6.18.Final]
	at org.hibernate.engine.internal.Cascade.cascadeProperty(Cascade.java:253) ~[hibernate-core-6.6.18.Final.jar:6.6.18.Final]
	at org.hibernate.engine.internal.Cascade.cascadeCollectionElements(Cascade.java:604) ~[hibernate-core-6.6.18.Final.jar:6.6.18.Final]
	at org.hibernate.engine.internal.Cascade.cascadeCollection(Cascade.java:534) ~[hibernate-core-6.6.18.Final.jar:6.6.18.Final]
	at org.hibernate.engine.internal.Cascade.cascadeAssociation(Cascade.java:495) ~[hibernate-core-6.6.18.Final.jar:6.6.18.Final]
	at org.hibernate.engine.internal.Cascade.cascadeProperty(Cascade.java:253) ~[hibernate-core-6.6.18.Final.jar:6.6.18.Final]
	at org.hibernate.engine.internal.Cascade.cascade(Cascade.java:192) ~[hibernate-core-6.6.18.Final.jar:6.6.18.Final]
	at org.hibernate.event.internal.AbstractFlushingEventListener.cascadeOnFlush(AbstractFlushingEventListener.java:193) ~[hibernate-core-6.6.18.Final.jar:6.6.18.Final]
	at org.hibernate.event.internal.AbstractFlushingEventListener.prepareEntityFlushes(AbstractFlushingEventListener.java:158) ~[hibernate-core-6.6.18.Final.jar:6.6.18.Final]
	at org.hibernate.event.internal.AbstractFlushingEventListener.preFlush(AbstractFlushingEventListener.java:107) ~[hibernate-core-6.6.18.Final.jar:6.6.18.Final]
	at org.hibernate.event.internal.DefaultAutoFlushEventListener.onAutoPreFlush(DefaultAutoFlushEventListener.java:104) ~[hibernate-core-6.6.18.Final.jar:6.6.18.Final]
	at org.hibernate.event.service.internal.EventListenerGroupImpl.fireEventOnEachListener(EventListenerGroupImpl.java:127) ~[hibernate-core-6.6.18.Final.jar:6.6.18.Final]
	at org.hibernate.internal.SessionImpl.autoPreFlush(SessionImpl.java:1391) ~[hibernate-core-6.6.18.Final.jar:6.6.18.Final]
	at org.hibernate.query.sqm.internal.ConcreteSqmSelectQueryPlan.withCacheableSqmInterpretation(ConcreteSqmSelectQueryPlan.java:382) ~[hibernate-core-6.6.18.Final.jar:6.6.18.Final]
	at org.hibernate.query.sqm.internal.ConcreteSqmSelectQueryPlan.performScroll(ConcreteSqmSelectQueryPlan.java:370) ~[hibernate-core-6.6.18.Final.jar:6.6.18.Final]
	at org.hibernate.query.sqm.internal.QuerySqmImpl.doScroll(QuerySqmImpl.java:456) ~[hibernate-core-6.6.18.Final.jar:6.6.18.Final]
	at org.hibernate.query.spi.AbstractSelectionQuery.scroll(AbstractSelectionQuery.java:242) ~[hibernate-core-6.6.18.Final.jar:6.6.18.Final]
	at org.hibernate.query.spi.AbstractSelectionQuery.stream(AbstractSelectionQuery.java:259) ~[hibernate-core-6.6.18.Final.jar:6.6.18.Final]
	at org.hibernate.query.spi.AbstractSelectionQuery.getResultStream(AbstractSelectionQuery.java:253) ~[hibernate-core-6.6.18.Final.jar:6.6.18.Final]
	at com.yahoo.elide.datastores.jpa.porting.QueryWrapper.scroll(QueryWrapper.java:61) ~[elide-datastore-jpa-7.1.11.jar:na]
	at com.yahoo.elide.datastores.jpql.JPQLTransaction.lambda$loadObjects$1(JPQLTransaction.java:156) ~[elide-datastore-hibernate-7.1.11.jar:na]
	at com.yahoo.elide.core.utils.TimedFunction.get(TimedFunction.java:33) ~[elide-core-7.1.11.jar:na]
	at com.yahoo.elide.datastores.jpql.JPQLTransaction.loadObjects(JPQLTransaction.java:157) ~[elide-datastore-hibernate-7.1.11.jar:na]
	at com.yahoo.elide.core.datastore.inmemory.InMemoryStoreTransaction.lambda$loadObjects$2(InMemoryStoreTransaction.java:120) ~[elide-core-7.1.11.jar:na]
	at com.yahoo.elide.core.datastore.inmemory.InMemoryStoreTransaction.fetchData(InMemoryStoreTransaction.java:265) ~[elide-core-7.1.11.jar:na]
	at com.yahoo.elide.core.datastore.inmemory.InMemoryStoreTransaction.loadObjects(InMemoryStoreTransaction.java:126) ~[elide-core-7.1.11.jar:na]
	at com.yahoo.elide.core.datastore.DataStoreTransaction.loadObject(DataStoreTransaction.java:148) ~[elide-core-7.1.11.jar:na]
	at com.yahoo.elide.core.datastore.inmemory.InMemoryStoreTransaction.loadObject(InMemoryStoreTransaction.java:112) ~[elide-core-7.1.11.jar:na]
	at com.yahoo.elide.core.PersistentResource.loadRecord(PersistentResource.java:281) ~[elide-core-7.1.11.jar:na]
	at com.yahoo.elide.jsonapi.models.Resource.toPersistentResource(Resource.java:187) ~[elide-core-7.1.11.jar:na]
	at com.yahoo.elide.jsonapi.models.Relationship.toPersistentResources(Relationship.java:81) ~[elide-core-7.1.11.jar:na]
	at com.yahoo.elide.jsonapi.parser.state.CollectionTerminalState.createObject(CollectionTerminalState.java:243) ~[elide-core-7.1.11.jar:na]
	at com.yahoo.elide.jsonapi.parser.state.CollectionTerminalState.handlePost(CollectionTerminalState.java:141) ~[elide-core-7.1.11.jar:na]
	at com.yahoo.elide.jsonapi.parser.state.StateContext.handlePost(StateContext.java:116) ~[elide-core-7.1.11.jar:na]
	at com.yahoo.elide.jsonapi.parser.PostVisitor.visitQuery(PostVisitor.java:31) ~[elide-core-7.1.11.jar:na]
	at com.yahoo.elide.jsonapi.parser.PostVisitor.visitQuery(PostVisitor.java:18) ~[elide-core-7.1.11.jar:na]
	at com.yahoo.elide.generated.parsers.CoreParser$QueryContext.accept(CoreParser.java:582) ~[elide-core-7.1.11.jar:na]
	at org.antlr.v4.runtime.tree.AbstractParseTreeVisitor.visitChildren(AbstractParseTreeVisitor.java:46) ~[antlr4-runtime-4.13.1.jar:4.13.1]
	at com.yahoo.elide.generated.parsers.CoreBaseVisitor.visitStart(CoreBaseVisitor.java:21) ~[elide-core-7.1.11.jar:na]
	at com.yahoo.elide.jsonapi.parser.BaseVisitor.visitStart(BaseVisitor.java:47) ~[elide-core-7.1.11.jar:na]
	at com.yahoo.elide.jsonapi.parser.BaseVisitor.visitStart(BaseVisitor.java:33) ~[elide-core-7.1.11.jar:na]
	at com.yahoo.elide.generated.parsers.CoreParser$StartContext.accept(CoreParser.java:118) ~[elide-core-7.1.11.jar:na]
	at org.antlr.v4.runtime.tree.AbstractParseTreeVisitor.visit(AbstractParseTreeVisitor.java:18) ~[antlr4-runtime-4.13.1.jar:4.13.1]
	at com.yahoo.elide.jsonapi.JsonApi.visit(JsonApi.java:251) ~[elide-core-7.1.11.jar:na]
	at com.yahoo.elide.jsonapi.JsonApi.lambda$post$1(JsonApi.java:137) ~[elide-core-7.1.11.jar:na]
	at com.yahoo.elide.jsonapi.JsonApi.handleRequest(JsonApi.java:276) ~[elide-core-7.1.11.jar:na]
	at com.yahoo.elide.jsonapi.JsonApi.post(JsonApi.java:129) ~[elide-core-7.1.11.jar:na]

Steps to reproduce

  • Create an Author Entity that has a @ReadPermission implemented with FilterExpressionCheck ✅
  • Create a Store Entity that has a @ReadPermission implemented with FilterExpressionCheck ✅
  • Create a Book Entity that has a relationship with the previously created Author and Store ❌

We are using a FilterExpressionCheck to filter out values from Read responses that do not conform to an header passed in the request;
Moreover, we cannot use the OperationCheck because we need the Read response to be paginated.

To reproduce this error, I've created a small repo with the bare minimum implementation:
PermissionTest

Below here the API calls to reproduce the issue

1.Author:

 curl --location 'http://localhost:8087/permission/author' \
--header 'X-Code-Permission: code-1' \
--header 'Content-Type: application/vnd.api+json' \
--data '{
    "data": {
        "type": "author",
        "attributes": {
            "code": "code-1"
        }
    }
}'
  1. Store:
curl --location 'http://localhost:8087/permission/store' \
--header 'X-Code-Permission: code-1' \
--header 'Content-Type: application/vnd.api+json' \
--data '{
    "data": {
        "type": "store",
        "attributes": {
            "code": "code-1",
            "name": "name"
        }
    }
}'
  1. Books:
curl --location 'http://localhost:8087/permission/books' \
--header 'X-Code-Permission: code-1' \
--header 'Content-Type: application/vnd.api+json' \
--data '{
    "data": {
        "type": "books",
        "attributes": {
            "code": "code-1"
        },
        "relationships": {
            "author": {
                "data": {
                    "type": "author",
                    "id": "1"
                }
            },
            "store": {
                "data": {
                    "type": "store",
                    "id": "1"
                }
            }
        }
    }
}'

Let me know if more information are needed.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions