eclipselink
eclipselink copied to clipboard
IndexOutOfBoundsException when JPQL has embeddable or relational attributes without the optional entity identification variable
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
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)