Some Eclipse Foundation services are deprecated, or will be soon. Please ensure you've read this important communication.
Bug 364153 - JPA query - NOT MEMBER OF exception (ClassCastException)
Summary: JPA query - NOT MEMBER OF exception (ClassCastException)
Status: CLOSED FIXED
Alias: None
Product: z_Archived
Classification: Eclipse Foundation
Component: Eclipselink (show other bugs)
Version: unspecified   Edit
Hardware: All Linux
: P2 normal (vote)
Target Milestone: ---   Edit
Assignee: Nobody - feel free to take it CLA
QA Contact:
URL:
Whiteboard:
Keywords:
Depends on:
Blocks:
 
Reported: 2011-11-18 09:12 EST by Dennis Fuglsang CLA
Modified: 2022-06-09 10:21 EDT (History)
4 users (show)

See Also:


Attachments
Suggested patch. (9.83 KB, patch)
2013-03-08 14:11 EST, Andrei Ilitchev CLA
no flags Details | Diff

Note You need to log in before you can comment on or make changes to this bug.
Description Dennis Fuglsang CLA 2011-11-18 09:12:22 EST
Build Identifier: 2.3.1

I have a very simple test case involving a single Java class, two database tables, a basic collection mapping and JPA queries.  The SQL for the DB schema is shown below

CREATE TABLE Z_INSTANCES (
  INSTANCE_UUID CHAR(36) NOT NULL
, NAME VARCHAR2(256)
, CONSTRAINT Z_INSTANCES_PK PRIMARY KEY (INSTANCE_UUID) using index tablespace &INDEX_TABLESPACE ENABLE) tablespace &DATA_TABLESPACE;

CREATE TABLE Z_GROUPS(
  INSTANCE_UUID CHAR(36) NOT NULL
, GROUP_UUID CHAR(36) NOT NULL
, CONSTRAINT GROUPS_UK1 UNIQUE (INSTANCE_UUID,GROUP_UUID) using index tablespace &INDEX_TABLESPACE ENABLE
, CONSTRAINT Z_INSTANCES_FK1 FOREIGN KEY (INSTANCE_UUID) 
    REFERENCES Z_INSTANCES(INSTANCE_UUID) ON DELETE CASCADE ENABLE) tablespace &DATA_TABLESPACE;

The Java class is very simple

public class Zinstance {
    private String uuid;
    private String name;
    private Set<String> groupUUIDs;
    public Zinstance() {
        this.uuid = UUID.randomUUID().toString();
        this.groupUUIDs = new HashSet<String>();
    }
}

The OR mapping is shown below:

                <entity class="my.temp.Zinstance">
                                <table name="Z_INSTANCES" />
                                <attributes>
                                                <id name="uuid">
                                                                <column name="INSTANCE_UUID" updatable="false" />
                                                </id>
                                                <basic name="name">
                                                                <column name="NAME" />
                                                </basic>
                                                <basic-collection name="groupUUIDs">
                                                                <value-column name="GROUP_UUID" />
                                                                <collection-table name="Z_GROUPS">
                                                                                <primary-key-join-column>INSTANCE_UUID</primary-key-join-column>
                                                                </collection-table>
                                                                <private-owned />
                                                                <join-fetch>OUTER</join-fetch>
                                                </basic-collection>
                                </attributes>
                </entity>


I attempted the following JPA queries

SELECT a FROM Zinstance a                                     <-Success
SELECT a FROM Zinstance a WHERE a.groupUUIDs = ?1             <-Success
SELECT a FROM Zinstance a WHERE ?1 LIKE a.groupUUIDs          <-Success 
SELECT a FROM Zinstance a WHERE ?1 NOT LIKE a.groupUUIDs      <-Fail incorrect results 
SELECT a FROM Zinstance a WHERE a.groupUUIDs IS EMPTY         <-Success
SELECT a FROM Zinstance a WHERE a.groupUUIDs IS NOT EMPTY     <-Success
SELECT a FROM Zinstance a WHERE ?1 MEMBER OF a.groupUUIDs     <-Success
SELECT a FROM Zinstance a WHERE ?1 NOT MEMBER OF a.groupUUIDs <-Fail CCE

I am using EclipseLink 2.3.1. Is the ClassCastException for the NOT MEMBER OF a bug?  Is there an alternative syntax for this type of query?

Exception [EclipseLink-6168] (Eclipse Persistence Services - 2.3.1.v20111018-r10243): org.eclipse.persistence.exceptions.QueryException
Exception Description: Query failed to prepare, unexpected error occurred: [java.lang.ClassCastException: java.lang.String cannot be cast to org.eclipse.persistence.internal.descriptors.PersistenceObject].
Internal Exception: java.lang.ClassCastException: java.lang.String cannot be cast to org.eclipse.persistence.internal.descriptors.PersistenceObject
Query: ReadAllQuery(referenceClass=Zinstance jpql="SELECT a FROM Zinstance a WHERE 'b54f6d66-07fe-4d04-97f6-acff6722236a' NOT MEMBER OF a.groupUUIDs")
       at org.eclipse.persistence.exceptions.QueryException.prepareFailed(QueryException.java:1555)
       at org.eclipse.persistence.queries.DatabaseQuery.checkPrepare(DatabaseQuery.java:625)
       at org.eclipse.persistence.queries.ObjectLevelReadQuery.checkPrepare(ObjectLevelReadQuery.java:823)
       at org.eclipse.persistence.queries.DatabaseQuery.prepareCall(DatabaseQuery.java:1741)
       at org.eclipse.persistence.internal.jpa.EJBQueryImpl.buildEJBQLDatabaseQuery(EJBQueryImpl.java:268)
       at org.eclipse.persistence.internal.jpa.EJBQueryImpl.buildEJBQLDatabaseQuery(EJBQueryImpl.java:190)
       at org.eclipse.persistence.internal.jpa.EJBQueryImpl.<init>(EJBQueryImpl.java:142)
       at org.eclipse.persistence.internal.jpa.EJBQueryImpl.<init>(EJBQueryImpl.java:126)
       at org.eclipse.persistence.internal.jpa.EntityManagerImpl.createQuery(EntityManagerImpl.java:1475)
       at oracle.oer.orc.persistence.temp.BasicCollectionIntegTest.query(BasicCollectionIntegTest.java:131)


Reproducible: Always

Steps to Reproduce:
1. Create single java class with collection attribute
2. Create two DB tables to hold instance of Java class and values of collection
3. Use basic collection mapping
4. Execute JPA query using NOT MEMBER OF operator
Comment 1 Tom Ware CLA 2011-12-02 10:25:59 EST
Setting target and priority.  See the following page for the meanings of these fields:

http://wiki.eclipse.org/EclipseLink/Development/Bugs/Guidelines

Community: Please vote for this bug if it is important to you.  Votes are one of the main criteria we use to determine which bugs to fix next.
Comment 2 Andrei Ilitchev CLA 2013-03-07 13:05:26 EST
I reproduced
SELECT a FROM Zinstance a WHERE ?1 NOT MEMBER OF a.groupUUIDs <-Fail CCE
that's a bug.
To workaround use:
SELECT e FROM Zinstance a WHERE NOT EXISTS (SELECT g FROM a.groupUUIDs g WHERE g = ?1)


The following jpql is illegal:
SELECT a FROM Zinstance a WHERE a.groupUUIDs = ?1
SELECT a FROM Zinstance a WHERE ?1 LIKE a.groupUUIDs
SELECT a FROM Zinstance a WHERE ?1 NOT LIKE a.groupUUIDs
as per spec.:
4.6.3 Path Expressions
It is illegal to use a collection_valued_path_expression within a WHERE or HAVING clause as part
of a conditional expression except in an empty_collection_comparison_expression, in a
collection_member_expression, or as an argument to the SIZE operator.
Comment 3 Andrei Ilitchev CLA 2013-03-08 14:11:21 EST
Created attachment 228155 [details]
Suggested patch.

The patch idea was suggested by James.
The original code didn't work because the target of DirectCollection has no descriptor.
"SELECT e FROM Employee e WHERE 'a' NOT MEMBER OF e.responsibilities"

Function operator [NOT EXISTS ,  ]
   SubSelect ReportQuery()
      Logical operator [ AND ]
         Relation operator [ = ]
            Base QUERY OBJECT
            Query Key responsibilities
               Base org.eclipse.persistence.testing.models.jpa.advanced.Employee
         Relation operator [ = ]
            Base QUERY OBJECT
            Constant a

To accommodate this the code was altered so that sub query is always against the same type as the parent expression:

Function operator [NOT EXISTS ,  ]
   SubSelect ReportQuery()
      Logical operator [ AND ]
         Relation operator [ = ]
            Base QUERY OBJECT
            Base org.eclipse.persistence.testing.models.jpa.advanced.Employee
         Relation operator [ = ]
            Query Key responsibilities
               Base QUERY OBJECT
            Constant a

Expression.noneOf method could achieve that, but the code is very similar.
Also added support for nested collection path (project.teamLeader.responsibilities).

The following tests were added to JUnitJPQLSimpleTestSuite:
selectSimpleNotMemberOfWithParameterNestedTest;
selectDirectCollectionNotMemberTest;
selectDirectCollectionNonMemberNestedTest
Comment 4 Andrei Ilitchev CLA 2013-03-08 14:15:30 EST
Correction: "Expression.noneOf method could NOT achieve that.."
Comment 5 Andrei Ilitchev CLA 2013-03-08 14:42:29 EST
Checked the patch into 2.4.2, trunk is pending.
Comment 6 Andrei Ilitchev CLA 2013-03-21 18:10:40 EDT
Checked the patch into trunk (2.5).
Comment 7 Eclipse Webmaster CLA 2022-06-09 10:21:27 EDT
The Eclipselink project has moved to Github: https://github.com/eclipse-ee4j/eclipselink