Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Hibernate ORM 6.2 - NullPointerException in TupleMappingModelExpressible #36363

Closed
mikethecalamity opened this issue Oct 9, 2023 · 18 comments · Fixed by #36978
Closed

Hibernate ORM 6.2 - NullPointerException in TupleMappingModelExpressible #36363

mikethecalamity opened this issue Oct 9, 2023 · 18 comments · Fixed by #36978
Labels
area/hibernate-orm Hibernate ORM area/persistence OBSOLETE, DO NOT USE kind/bug Something isn't working
Milestone

Comments

@mikethecalamity
Copy link

mikethecalamity commented Oct 9, 2023

Describe the bug

I am attempting to migrate from Quarkus 2.16.8 to 3.3.3 and I receive a NPE when running a query using the new version. Everything worked before and I thought I made all the necessary updates in the migration guide.

I'm assuming something is missing from my migration or configuration, but I can't determine what.

Expected behavior

NullPointerException: Cannot invoke "org.hibernate.metamodel.mapping.MappingModelExpressible.forEachJdbcType(int, org.hibernate.internal.util.IndexedConsumer)
" because "this.components[i]" is null
        at org.hibernate.metamodel.model.domain.internal.TupleMappingModelExpressible.forEachJdbcType(TupleMappingModelExpressible.java:41)
        at org.hibernate.metamodel.model.domain.internal.TupleMappingModelExpressible.<init>(TupleMappingModelExpressible.java:28)
        at org.hibernate.metamodel.model.domain.internal.MappingMetamodelImpl.resolveMappingExpressible(MappingMetamodelImpl.java:810)
        at org.hibernate.query.sqm.sql.BaseSqmToSqlAstConverter.determineValueMapping(BaseSqmToSqlAstConverter.java:5675)
        at org.hibernate.query.sqm.sql.BaseSqmToSqlAstConverter.lambda$visitWithInferredType$98(BaseSqmToSqlAstConverter.java:6784)
        at org.hibernate.query.sqm.sql.BaseSqmToSqlAstConverter.resolveInferredType(BaseSqmToSqlAstConverter.java:5216)
        at org.hibernate.query.sqm.sql.BaseSqmToSqlAstConverter.visitTuple(BaseSqmToSqlAstConverter.java:5971)
        at org.hibernate.query.sqm.tree.expression.SqmTuple.accept(SqmTuple.java:84)
        at org.hibernate.query.sqm.sql.BaseSqmToSqlAstConverter.visitWithInferredType(BaseSqmToSqlAstConverter.java:6786)
        at org.hibernate.query.sqm.sql.BaseSqmToSqlAstConverter.visitInSubQueryPredicate(BaseSqmToSqlAstConverter.java:7716)
        at org.hibernate.query.sqm.sql.BaseSqmToSqlAstConverter.visitInSubQueryPredicate(BaseSqmToSqlAstConverter.java:434)
        at org.hibernate.query.sqm.tree.predicate.SqmInSubQueryPredicate.accept(SqmInSubQueryPredicate.java:87)
        at org.hibernate.query.sqm.sql.BaseSqmToSqlAstConverter.visitWhereClause(BaseSqmToSqlAstConverter.java:2471)
        at org.hibernate.query.sqm.sql.BaseSqmToSqlAstConverter.visitQuerySpec(BaseSqmToSqlAstConverter.java:2048)
        at org.hibernate.query.sqm.sql.BaseSqmToSqlAstConverter.visitQuerySpec(BaseSqmToSqlAstConverter.java:434)
        at org.hibernate.query.sqm.tree.select.SqmQuerySpec.accept(SqmQuerySpec.java:125)
        at org.hibernate.query.sqm.spi.BaseSemanticQueryWalker.visitQueryPart(BaseSemanticQueryWalker.java:221)
        at org.hibernate.query.sqm.sql.BaseSqmToSqlAstConverter.visitQueryPart(BaseSqmToSqlAstConverter.java:1902)
        at org.hibernate.query.sqm.sql.BaseSqmToSqlAstConverter.visitSelectStatement(BaseSqmToSqlAstConverter.java:1587)
        at org.hibernate.query.sqm.sql.BaseSqmToSqlAstConverter.visitSelectStatement(BaseSqmToSqlAstConverter.java:434)
        at org.hibernate.query.sqm.tree.select.SqmSelectStatement.accept(SqmSelectStatement.java:222)
        at org.hibernate.query.sqm.sql.BaseSqmToSqlAstConverter.translate(BaseSqmToSqlAstConverter.java:770)
        at org.hibernate.query.sqm.internal.ConcreteSqmSelectQueryPlan.buildCacheableSqmInterpretation(ConcreteSqmSelectQueryPlan.java:345)
        at org.hibernate.query.sqm.internal.ConcreteSqmSelectQueryPlan.withCacheableSqmInterpretation(ConcreteSqmSelectQueryPlan.java:268)
        at org.hibernate.query.sqm.internal.ConcreteSqmSelectQueryPlan.performList(ConcreteSqmSelectQueryPlan.java:244)
        at org.hibernate.query.sqm.internal.QuerySqmImpl.doList(QuerySqmImpl.java:518)
        at org.hibernate.query.spi.AbstractSelectionQuery.list(AbstractSelectionQuery.java:367)
        at org.hibernate.query.Query.getResultList(Query.java:119)
        at my.project.jpa.DataManager.getAll(DataManager.java:47)

Actual behavior

No failure

How to Reproduce?

Build Gradle:

dependencies {
    implementation 'io.quarkus:quarkus-config-yaml'
    implementation 'io.quarkus:quarkus-hibernate-orm'
    implementation 'io.quarkus:quarkus-jdbc-postgresql'
    implementation 'io.quarkus:quarkus-kubernetes'
    implementation 'io.quarkus:quarkus-kubernetes-config'
    implementation 'io.quarkus:quarkus-logging-json'
    implementation 'io.quarkus:quarkus-rest-client-reactive'
    implementation 'io.quarkus:quarkus-rest-client-reactive-jackson'
    implementation 'io.quarkus:quarkus-resteasy-reactive'
    implementation 'io.quarkus:quarkus-resteasy-reactive-jackson'
    implementation 'io.quarkus:quarkus-smallrye-context-propagation'
    implementation 'io.quarkus:quarkus-smallrye-health'
    implementation 'io.quarkus:quarkus-smallrye-openapi'
    implementation 'io.quarkus:quarkus-undertow'
    implementation 'org.amqphub.quarkus:quarkus-qpid-jms'
}

Code:

@Inject
private EntityManager em;

public List<MyEntity> getAll(final Instant time) {
    final TypedQuery<MyEntity> q = em.createNamedQuery(MyEntity.GET_LATEST_AT_TIME, MyEntity.class);
    q.setParameter("time", time);
    return q.getResultList();
}

@Entity
@Table(schema = "my_schema", name = "my_table")
@NamedQueries({
        @NamedQuery(name = MyEntity.GET_LATEST_AT_TIME,
                query = "SELECT m FROM MyEntity AS m WHERE (m.associatedId, m.value) IN"
                        + " (SELECT innerM.associatedId, max(innerM.value) FROM MyEntity AS innerM"
                        + " WHERE innerM.value <= :time AND innerM.isDeleted = false"
                        + " GROUP BY innerM.associatedId)")
})
public class MyEntity implements Serializable {

    private static final long serialVersionUID = 1L;

    public static final String GET_LATEST_AT_TIME = "my_table.getLatestAtTime";

    @Id
    @Column(name = "id")
    private UUID id;

    @Column(name = "value")
    private long value;

    @Column(name = "associated_id")
    private UUID associatedId;

    @Column(name = "is_deleted")
    private boolean isDeleted;
}

Config:

quarkus:
  datasource:
    db-kind: postgresql
    jdbc:
      background-validation-interval: 20S
      idle-removal-interval: 30S
      max-size: 10
      min-size: 0
      url: jdbc:postgresql://${PGHOST}:${PGPORT}/${PGDATABASE}?user=${PGDATABASE}&ApplicationName=my-project&reWriteBatchedInserts=true
    username: ${PGDATABASE}
    password: ${PGPASSWORD}

Output of uname -a or ver

No response

Output of java -version

Temurin 17.0.8

GraalVM version (if different from Java)

No response

Quarkus version or git rev

3.3.3

Build tool (ie. output of mvnw --version or gradlew --version)

Gradle 8.3

Additional information

No response

@mikethecalamity mikethecalamity added the kind/bug Something isn't working label Oct 9, 2023
@quarkus-bot quarkus-bot bot added area/hibernate-orm Hibernate ORM area/kubernetes area/persistence OBSOLETE, DO NOT USE labels Oct 9, 2023
@quarkus-bot
Copy link

quarkus-bot bot commented Oct 9, 2023

/cc @Sanne (hibernate-orm), @geoand (kubernetes), @gsmet (hibernate-orm), @iocanel (kubernetes), @yrodiere (hibernate-orm)

@yrodiere
Copy link
Member

Thanks for reporting.

This looks more like a bug (potentially in Hibernate ORM itself) than something missing from the migration guide.

That being said, I think the reproducer would be slightly more useful if it included the query that triggers the failure :] What's the code of MyEntity, and particularly what's the value of MyEntity.GET_LATEST_AT_TIME and what's the definition of the corresponding query?

@yrodiere yrodiere added triage/needs-reproducer We are waiting for a reproducer. and removed area/kubernetes labels Oct 10, 2023
@gsmet
Copy link
Member

gsmet commented Oct 10, 2023

It would help immensely if you could put together a self contained reproducer. Thanks!

@Sanne
Copy link
Member

Sanne commented Oct 10, 2023

cc/ @beikov

@mikethecalamity
Copy link
Author

@yrodiere I added my entity class to the example. I don't think it has to do with the query, I think that query is just the first one to be run.

@gsmet I'll try to put together a self-contained reproducer. I'm not sure if I'll be able to because of the postgres database though.

@mikethecalamity
Copy link
Author

@gsmet I was finally able to get together a self-contained reproducer, but I'm not get the error. So it's definitely something with my company's baseline/configuration. But I'm not sure where to go from here to track down the issue, since the error is deep in the guts of Hibernate.

@yrodiere
Copy link
Member

@mikethecalamity In my experience the only way to proceed in these cases is to build the reproducer by basically copy-pasting your whole project to a new one, then stripping it down little by little, regularly checking whether the bug is still there. It's ready when you can't remove anything without eliminating the bug.

In particular, make sure to use Quarkus in your reproducer, at least at first, because Quarkus does customize Hibernate ORM significantly and this can lead ORM to behave differently than with its default settings, including different bugs.

@ingalemart
Copy link

I am experiencing the same bug in Spring Boot 3.1.4.
The problem seems to be related to HQL queries containing clauses such as (value1, value2) IN (subquery). The "TupleMappingModelExpressible" constructor calls the "forEachJdbcType" method which uses the "components" array, but in this case, the array contains null values.

@yrodiere
Copy link
Member

I am experiencing the same bug in Spring Boot 3.1.4. The problem seems to be related to HQL queries containing clauses such as (value1, value2) IN (subquery). The "TupleMappingModelExpressible" constructor calls the "forEachJdbcType" method which uses the "components" array, but in this case, the array contains null values.

Thanks for letting us know @ingalemart! Did you report this to the ORM project already? Do you have a link?

@ingalemart
Copy link

I am experiencing the same bug in Spring Boot 3.1.4. The problem seems to be related to HQL queries containing clauses such as (value1, value2) IN (subquery). The "TupleMappingModelExpressible" constructor calls the "forEachJdbcType" method which uses the "components" array, but in this case, the array contains null values.

Thanks for letting us know @ingalemart! Did you report this to the ORM project already? Do you have a link?

Yes, here is the ticket: https://hibernate.atlassian.net/browse/HHH-17332

@yrodiere yrodiere added triage/upstream and removed triage/needs-reproducer We are waiting for a reproducer. labels Oct 18, 2023
@yrodiere
Copy link
Member

Thanks! I updated the labels.

@yrodiere yrodiere changed the title Error in Quarkus/Hibernate when migrating to 3.0 Hibernate ORM 6.2 - NullPointerException in TupleMappingModelExpressible Oct 18, 2023
@mikethecalamity
Copy link
Author

@ingalemart is there any workaround that you've found?

@ingalemart
Copy link

ingalemart commented Oct 19, 2023

@ingalemart is there any workaround that you've found?

@mikethecalamity Unfortunately I couldn't find a proper workaround, but I guess you could revert to Hibernate ORM 6.2.4 or earlier, or you could try to rewrite your query so that it does not need an anonoymous tuple. Maybe you could split it into two separate queries or use a self join

@mikethecalamity
Copy link
Author

Thanks @ingalemart, that works for now, I added to my build.gradle:

configurations.all {
    resolutionStrategy {
        force 'org.hibernate.orm:hibernate-core:6.2.4.Final'
    }
 }

@mikethecalamity
Copy link
Author

@ingalemart any word on whether the Hibernate folks fixed this issue? And if so what version has the fix

@yrodiere
Copy link
Member

As @ingalemart wrote, this was reported as https://hibernate.atlassian.net/browse/HHH-17332, which is fixed in several versions, as you can see by following the link.
As for Quarkus, this will be fixed when we merge the upgrade to ORM 6.4: #36978

@mikethecalamity
Copy link
Author

Has anyone still seen this in Hibernate 6.4? I've been working on upgrading our services to Quarkus 3.9.3 (which uses the latest Hibernate 6.4.4) and I still see this issue. But the reproducer linked in the hibernate issue does now pass with 6.4.4. So I am at a loss as to why this issue would still be happening and cannot get it to reproduce in a vacuum.

@yrodiere
Copy link
Member

@mikethecalamity can you please try to write a reproducer based on this code, which provides a closer environment to quarkus? https://github.com/hibernate/hibernate-test-case-templates/blob/main/orm/hibernate-orm-6/src/test/java/org/hibernate/bugs/QuarkusLikeORMUnitTestCase.java

If you manage to reproduce, please open a new issue with a link to this one .

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area/hibernate-orm Hibernate ORM area/persistence OBSOLETE, DO NOT USE kind/bug Something isn't working
Projects
None yet
Development

Successfully merging a pull request may close this issue.

5 participants