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

IndexOutOfBoundsException when JPQL has embeddable or relational attributes without the optional entity identification variable #2188

Open
anija-anil opened this issue Jul 2, 2024 · 1 comment

Comments

@anija-anil
Copy link
Contributor

JPQL queries with embeddable (or relation) attributes that omit the optional entity identification variable (for consistency with JDQL) get IndexOutOfBoundsException on EclipseLink.

Example query:

FROM Business WHERE location.address.city=?1 ORDER BY name

Here is the exception stack with IndexOutOfBoundsException:

Caused by: java.lang.IllegalArgumentException: An exception occurred while creating a query in EntityManager: 
Exception Description: Internal problem encountered while compiling [ FROM Business WHERE location.address.city=?1 ORDER BY name].
Internal Exception: java.lang.IndexOutOfBoundsException: Index 1 out of bounds for length 1
	at org.eclipse.persistence.internal.jpa.EntityManagerImpl.createQuery(EntityManagerImpl.java:1848)
	at org.eclipse.persistence.internal.jpa.EntityManagerImpl.createQuery(EntityManagerImpl.java:1869)
	at io.openliberty.data.internal.persistence.PageImpl.<init>(PageImpl.java:58)
	... 39 more
Caused by: Exception [EclipseLink-0] (Eclipse Persistence Services - 5.0.0-B02.v202404111748): org.eclipse.persistence.exceptions.JPQLException
Exception Description: Internal problem encountered while compiling [ FROM Business WHERE location.address.city=?1 ORDER BY name].
Internal Exception: java.lang.IndexOutOfBoundsException: Index 1 out of bounds for length 1
	at org.eclipse.persistence.internal.jpa.jpql.HermesParser.buildUnexpectedException(HermesParser.java:215)
	at org.eclipse.persistence.internal.jpa.jpql.HermesParser.populateQueryImp(HermesParser.java:310)
	at org.eclipse.persistence.internal.jpa.jpql.HermesParser.buildQuery(HermesParser.java:174)
	at org.eclipse.persistence.internal.jpa.EJBQueryImpl.buildEJBQLDatabaseQuery(EJBQueryImpl.java:144)
	at org.eclipse.persistence.internal.jpa.EJBQueryImpl.buildEJBQLDatabaseQuery(EJBQueryImpl.java:120)
	at org.eclipse.persistence.internal.jpa.EJBQueryImpl.<init>(EJBQueryImpl.java:107)
	at org.eclipse.persistence.internal.jpa.EJBQueryImpl.<init>(EJBQueryImpl.java:91)
	at org.eclipse.persistence.internal.jpa.EntityManagerImpl.createQuery(EntityManagerImpl.java:1846)
	... 41 more
Caused by: java.lang.IndexOutOfBoundsException: Index 1 out of bounds for length 1
	at java.base/jdk.internal.util.Preconditions.outOfBounds(Preconditions.java:100)
	at java.base/jdk.internal.util.Preconditions.outOfBoundsCheckIndex(Preconditions.java:106)
	at java.base/jdk.internal.util.Preconditions.checkIndex(Preconditions.java:302)
	at java.base/java.util.Objects.checkIndex(Objects.java:385)
	at java.base/java.util.ArrayList.get(ArrayList.java:427)
	at org.eclipse.persistence.jpa.jpql.parser.AbstractPathExpression.getPath(AbstractPathExpression.java:258)
	at org.eclipse.persistence.internal.jpa.jpql.ExpressionBuilderVisitor$PathResolver.resolvePath(ExpressionBuilderVisitor.java:2476)
	at org.eclipse.persistence.internal.jpa.jpql.ExpressionBuilderVisitor$PathResolver.visitPathExpression(ExpressionBuilderVisitor.java:2675)
	at org.eclipse.persistence.internal.jpa.jpql.ExpressionBuilderVisitor$PathResolver.visit(ExpressionBuilderVisitor.java:2620)
	at org.eclipse.persistence.jpa.jpql.parser.IdentificationVariable.accept(IdentificationVariable.java:120)
	at org.eclipse.persistence.internal.jpa.jpql.ExpressionBuilderVisitor$PathResolver.visitPathExpression(ExpressionBuilderVisitor.java:2650)
	at org.eclipse.persistence.internal.jpa.jpql.ExpressionBuilderVisitor$PathResolver.visit(ExpressionBuilderVisitor.java:2620)
	at org.eclipse.persistence.jpa.jpql.parser.StateFieldPathExpression.accept(StateFieldPathExpression.java:77)
	at org.eclipse.persistence.internal.jpa.jpql.ExpressionBuilderVisitor.visitPathExpression(ExpressionBuilderVisitor.java:2127)
	at org.eclipse.persistence.internal.jpa.jpql.ExpressionBuilderVisitor.visit(ExpressionBuilderVisitor.java:1893)
	at org.eclipse.persistence.jpa.jpql.parser.StateFieldPathExpression.accept(StateFieldPathExpression.java:77)
	at org.eclipse.persistence.internal.jpa.jpql.ExpressionBuilderVisitor$ComparisonExpressionVisitor.visit(ExpressionBuilderVisitor.java:2208)
	at org.eclipse.persistence.jpa.jpql.parser.AnonymousExpressionVisitor.visit(AnonymousExpressionVisitor.java:466)
	at org.eclipse.persistence.jpa.jpql.parser.StateFieldPathExpression.accept(StateFieldPathExpression.java:77)
	at org.eclipse.persistence.internal.jpa.jpql.ExpressionBuilderVisitor.visit(ExpressionBuilderVisitor.java:732)
	at org.eclipse.persistence.jpa.jpql.parser.ComparisonExpression.accept(ComparisonExpression.java:71)
	at org.eclipse.persistence.internal.jpa.jpql.ExpressionBuilderVisitor.visit(ExpressionBuilderVisitor.java:2111)
	at org.eclipse.persistence.jpa.jpql.parser.WhereClause.accept(WhereClause.java:56)
	at org.eclipse.persistence.internal.jpa.jpql.ExpressionBuilderVisitor.buildExpression(ExpressionBuilderVisitor.java:280)
	at org.eclipse.persistence.internal.jpa.jpql.JPQLQueryContext.buildExpression(JPQLQueryContext.java:326)
	at org.eclipse.persistence.internal.jpa.jpql.AbstractObjectLevelReadQueryVisitor.visit(AbstractObjectLevelReadQueryVisitor.java:226)
	at org.eclipse.persistence.jpa.jpql.parser.WhereClause.accept(WhereClause.java:56)
	at org.eclipse.persistence.internal.jpa.jpql.AbstractObjectLevelReadQueryVisitor.visitAbstractSelectStatement(AbstractObjectLevelReadQueryVisitor.java:292)
	at org.eclipse.persistence.internal.jpa.jpql.AbstractObjectLevelReadQueryVisitor.visit(AbstractObjectLevelReadQueryVisitor.java:160)
	at org.eclipse.persistence.jpa.jpql.parser.SelectStatement.accept(SelectStatement.java:100)
	at org.eclipse.persistence.internal.jpa.jpql.HermesParser$DatabaseQueryVisitor.visit(HermesParser.java:440)
	at org.eclipse.persistence.jpa.jpql.parser.SelectStatement.accept(SelectStatement.java:100)
	at org.eclipse.persistence.internal.jpa.jpql.HermesParser$DatabaseQueryVisitor.visit(HermesParser.java:423)
	at org.eclipse.persistence.jpa.jpql.parser.JPQLExpression.accept(JPQLExpression.java:186)
	at org.eclipse.persistence.internal.jpa.jpql.HermesParser.populateQueryImp(HermesParser.java:296)
	... 47 more
@Riva-Tholoor-Philip
Copy link
Contributor

I could recreate the issue.

Below is the Business entity we have by referencing the entity present in Jakarta Data.

@Entity
public class Business {

    public String name;

    @GeneratedValue
    @Id
    public int id;

    @Embedded
    public Location location;

    public static Business of(float latitude, float longitude, String city, String state, int zip,
                              int houseNum, String streetName, String streetDir, String name) {
        Business inst = new Business();
        Street street = new Street(streetName, streetDir);
        Address address = new Address(city, state, zip, houseNum, street);

        inst.name = name;
        inst.location = new Location(address, latitude, longitude);

        return inst;
    }

    @Embeddable
    public static class Location {

        @Embedded
        public Address address;

        @Column(columnDefinition = "DECIMAL(8,5) NOT NULL")
        public float latitude;

        @Column(columnDefinition = "DECIMAL(8,5) NOT NULL")
        public float longitude;

        public Location() {
        }

        public Location(Address address, float latitude, float longitude) {
            this.address = address;
            this.latitude = latitude;
            this.longitude = longitude;
        }
    }

    @Embeddable
    public static class Address {

        public String city;

        public int houseNum;

        public String state;

        @Embedded
        public Street street;

        public int zip;

        public Address() {
        }

        Address(String city, String state, int zip, int houseNum, Street street) {
            this.city = city;
            this.state = state;
            this.zip = zip;
            this.houseNum = houseNum;
            this.street = street;
        }
    }

    @Embeddable
    public static class Street {

        public String direction;

        @Column(name = "STREETNAME")
        public String name;

        public Street() {
        }

        public Street(String name, String direction) {
            this.name = name;
            this.direction = direction;
        }
    }

Here is the code where we executed the JPQL query:

public void testOLGH28931() throws Exception {
        Business ibmRoc = Business.of(44.05887f, -92.50355f, "Rochester", "Minnesota", 55901, 2800, "37th St", "NW", "IBM Rochester");
        Business ibmRTP = Business.of(35.90481f, -78.85026f, "Durham", "North Carolina", 27703, 4204, "Miami Blvd", "S", "IBM RTP");

        Business result;

        tx.begin();
        em.persist(ibmRoc);
        em.persist(ibmRTP);
        tx.commit();

        tx.begin();
        try {
            result = em.createQuery("FROM Business WHERE location.address.city=?1 ORDER BY name", Business.class)
                            .setParameter(1, "Rochester")
                            .getSingleResult();
            tx.commit();
        } catch (Exception e) {
            tx.rollback();

            throw e;
        }

This resulted in the following exception stack, which is the same as described in the issue:

Caused by: Exception [EclipseLink-0] (Eclipse Persistence Services - 5.0.0-B02.v202404111748): org.eclipse.persistence.exceptions.JPQLException
Exception Description: Internal problem encountered while compiling [FROM Business WHERE location.address.city=?1 ORDER BY name].
Internal Exception: java.lang.IndexOutOfBoundsException: Index 1 out of bounds for length 1
at org.eclipse.persistence.internal.jpa.jpql.HermesParser.buildUnexpectedException(HermesParser.java:215)
at org.eclipse.persistence.internal.jpa.jpql.HermesParser.populateQueryImp(HermesParser.java:310)
at org.eclipse.persistence.internal.jpa.jpql.HermesParser.buildQuery(HermesParser.java:174)
at org.eclipse.persistence.internal.jpa.EJBQueryImpl.buildEJBQLDatabaseQuery(EJBQueryImpl.java:144)
at org.eclipse.persistence.internal.jpa.EJBQueryImpl.buildEJBQLDatabaseQuery(EJBQueryImpl.java:120)
at org.eclipse.persistence.internal.jpa.EJBQueryImpl.<init>(EJBQueryImpl.java:107)
at org.eclipse.persistence.internal.jpa.EJBQueryImpl.<init>(EJBQueryImpl.java:91)
at org.eclipse.persistence.internal.jpa.EntityManagerImpl.createQuery(EntityManagerImpl.java:1846)
Caused by: java.lang.IndexOutOfBoundsException: Index 1 out of bounds for length 1
at java.base/jdk.internal.util.Preconditions.outOfBounds(Preconditions.java:64)
at java.base/jdk.internal.util.Preconditions.outOfBoundsCheckIndex(Preconditions.java:70)
at java.base/jdk.internal.util.Preconditions.checkIndex(Preconditions.java:266)
at java.base/java.util.Objects.checkIndex(Objects.java:361)
at java.base/java.util.ArrayList.get(ArrayList.java:427)
at org.eclipse.persistence.jpa.jpql.parser.AbstractPathExpression.getPath(AbstractPathExpression.java:258)
at org.eclipse.persistence.internal.jpa.jpql.ExpressionBuilderVisitor$PathResolver.resolvePath(ExpressionBuilderVisitor.java:2476)
at org.eclipse.persistence.internal.jpa.jpql.ExpressionBuilderVisitor$PathResolver.visitPathExpression(ExpressionBuilderVisitor.java:2675)
at org.eclipse.persistence.internal.jpa.jpql.ExpressionBuilderVisitor$PathResolver.visit(ExpressionBuilderVisitor.java:2620)
at org.eclipse.persistence.jpa.jpql.parser.IdentificationVariable.accept(IdentificationVariable.java:120)
at org.eclipse.persistence.internal.jpa.jpql.ExpressionBuilderVisitor$PathResolver.visitPathExpression(ExpressionBuilderVisitor.java:2650)
at org.eclipse.persistence.internal.jpa.jpql.ExpressionBuilderVisitor$PathResolver.visit(ExpressionBuilderVisitor.java:2620)
at org.eclipse.persistence.jpa.jpql.parser.StateFieldPathExpression.accept(StateFieldPathExpression.java:77)
at org.eclipse.persistence.internal.jpa.jpql.ExpressionBuilderVisitor.visitPathExpression(ExpressionBuilderVisitor.java:2127)
at org.eclipse.persistence.internal.jpa.jpql.ExpressionBuilderVisitor.visit(ExpressionBuilderVisitor.java:1893)
at org.eclipse.persistence.jpa.jpql.parser.StateFieldPathExpression.accept(StateFieldPathExpression.java:77)
at org.eclipse.persistence.internal.jpa.jpql.ExpressionBuilderVisitor$ComparisonExpressionVisitor.visit(ExpressionBuilderVisitor.java:2208)
at org.eclipse.persistence.jpa.jpql.parser.AnonymousExpressionVisitor.visit(AnonymousExpressionVisitor.java:466)
at org.eclipse.persistence.jpa.jpql.parser.StateFieldPathExpression.accept(StateFieldPathExpression.java:77)
at org.eclipse.persistence.internal.jpa.jpql.ExpressionBuilderVisitor.visit(ExpressionBuilderVisitor.java:732)
at org.eclipse.persistence.jpa.jpql.parser.ComparisonExpression.accept(ComparisonExpression.java:71)
at org.eclipse.persistence.internal.jpa.jpql.ExpressionBuilderVisitor.visit(ExpressionBuilderVisitor.java:2111)
at org.eclipse.persistence.jpa.jpql.parser.WhereClause.accept(WhereClause.java:56)
at org.eclipse.persistence.internal.jpa.jpql.ExpressionBuilderVisitor.buildExpression(ExpressionBuilderVisitor.java:280)
at org.eclipse.persistence.internal.jpa.jpql.JPQLQueryContext.buildExpression(JPQLQueryContext.java:326)
at org.eclipse.persistence.internal.jpa.jpql.AbstractObjectLevelReadQueryVisitor.visit(AbstractObjectLevelReadQueryVisitor.java:226)
at org.eclipse.persistence.jpa.jpql.parser.WhereClause.accept(WhereClause.java:56)
at org.eclipse.persistence.internal.jpa.jpql.AbstractObjectLevelReadQueryVisitor.visitAbstractSelectStatement(AbstractObjectLevelReadQueryVisitor.java:292)
at org.eclipse.persistence.internal.jpa.jpql.AbstractObjectLevelReadQueryVisitor.visit(AbstractObjectLevelReadQueryVisitor.java:160)
at org.eclipse.persistence.jpa.jpql.parser.SelectStatement.accept(SelectStatement.java:100)
at org.eclipse.persistence.internal.jpa.jpql.HermesParser$DatabaseQueryVisitor.visit(HermesParser.java:440)
at org.eclipse.persistence.jpa.jpql.parser.SelectStatement.accept(SelectStatement.java:100)
at org.eclipse.persistence.internal.jpa.jpql.HermesParser$DatabaseQueryVisitor.visit(HermesParser.java:423)
at org.eclipse.persistence.jpa.jpql.parser.JPQLExpression.accept(JPQLExpression.java:186)
at org.eclipse.persistence.internal.jpa.jpql.HermesParser.populateQueryImp(HermesParser.java:296)

at componenttest.topology.utils.FATServletClient.assertTestResponse(FATServletClient.java:106)
at componenttest.topology.utils.FATServletClient.runTest(FATServletClient.java:91)
at componenttest.custom.junit.runner.SyntheticServletTest.invokeExplosively(SyntheticServletTest.java:49)
at componenttest.custom.junit.runner.FATRunner$1.evaluate(FATRunner.java:204)
at componenttest.custom.junit.runner.FATRunner$2.evaluate(FATRunner.java:364)
at componenttest.custom.junit.runner.FATRunner.run(FATRunner.java:178)
at org.testcontainers.containers.FailureDetectingExternalResource$1.evaluate(FailureDetectingExternalResource.java:29)
at componenttest.rules.repeater.RepeatTests$CompositeRepeatTestActionStatement.evaluate(RepeatTests.java:145)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants