1

I use EclipseLink 2.6.3 as JPA provider. I have two entities:

@Entity
public class ClassA{

    @Id
    private String uuid;

    private String comment;

    @OneToMany(fetch = FetchType.EAGER,cascade = CascadeType.ALL,mappedBy = "classA",orphanRemoval = false)
    @MapKey(name="code")
    private Map<String,ClassB> texts;
    //+ getters and setters
}

@Entity
public class ClassB {

    @Id
    private String uuid;

    private String code;

    private String name;

     @ManyToOne
    @JoinColumn(name = "comeColname")
    private ClassA classA;

   //+getters and setters
}

When I load ClassA entity without EntityGraph everything works well. However, if I do the following code:

String queryString="SELECT a FROM ClassA a WHERE a.uuid='dj000000001111111111a1'";
EntityGraph<ClassA> eg = em.createEntityGraph(ClassA.class);
eg.addAttributeNodes(new String[]{"uuid","comment"});
eg.addSubgraph("texts").addAttributeNodes(new String[]{"uuid","code","name"});
Query query = em.createQuery(queryString);
query.setHint("javax.persistence.fetchgraph", eg);
List<ClassA> items=query.getResultList();
em.close();

I get the following exception:

[EL Warning]: 2016-06-10 13:40:20.093--ServerSession(1266534280)--java.lang.ClassCastException: 
    java.util.Hashtable cannot be cast to org.eclipse.persistence.queries.FetchGroupTracker
    at org.eclipse.persistence.descriptors.FetchGroupManager.getObjectFetchGroup(FetchGroupManager.java:695)
    at org.eclipse.persistence.internal.descriptors.ObjectBuilder.load(ObjectBuilder.java:778)
    at org.eclipse.persistence.internal.sessions.AbstractSession.load(AbstractSession.java:5189)
    at org.eclipse.persistence.queries.ObjectLevelReadQuery.executeDatabaseQuery(ObjectLevelReadQuery.java:1192)
    at org.eclipse.persistence.queries.DatabaseQuery.execute(DatabaseQuery.java:904)
    at org.eclipse.persistence.queries.ObjectLevelReadQuery.execute(ObjectLevelReadQuery.java:1134)
    at org.eclipse.persistence.queries.ReadAllQuery.execute(ReadAllQuery.java:460)
    at org.eclipse.persistence.internal.sessions.AbstractSession.internalExecuteQuery(AbstractSession.java:3271)
    at org.eclipse.persistence.internal.sessions.AbstractSession.executeQuery(AbstractSession.java:1857)
    at org.eclipse.persistence.internal.sessions.AbstractSession.executeQuery(AbstractSession.java:1839)
    at org.eclipse.persistence.internal.indirection.NoIndirectionPolicy.valueFromQuery(NoIndirectionPolicy.java:326)
    at org.eclipse.persistence.mappings.ForeignReferenceMapping.valueFromRowInternal(ForeignReferenceMapping.java:2334)
    at org.eclipse.persistence.mappings.ForeignReferenceMapping.valueFromRow(ForeignReferenceMapping.java:2178)
    at org.eclipse.persistence.mappings.ForeignReferenceMapping.readFromRowIntoObject(ForeignReferenceMapping.java:1505)
    at org.eclipse.persistence.internal.descriptors.ObjectBuilder.buildAttributesIntoObject(ObjectBuilder.java:462)
    at org.eclipse.persistence.internal.descriptors.ObjectBuilder.buildObject(ObjectBuilder.java:1005)
    at org.eclipse.persistence.internal.descriptors.ObjectBuilder.buildWorkingCopyCloneNormally(ObjectBuilder.java:899)
    at org.eclipse.persistence.internal.descriptors.ObjectBuilder.buildObjectInUnitOfWork(ObjectBuilder.java:852)
    at org.eclipse.persistence.internal.descriptors.ObjectBuilder.buildObject(ObjectBuilder.java:735)
    at org.eclipse.persistence.internal.descriptors.ObjectBuilder.buildObject(ObjectBuilder.java:689)
    at org.eclipse.persistence.queries.ObjectLevelReadQuery.buildObject(ObjectLevelReadQuery.java:805)
    at org.eclipse.persistence.queries.ReadObjectQuery.registerResultInUnitOfWork(ReadObjectQuery.java:895)
    at org.eclipse.persistence.queries.ReadObjectQuery.executeObjectLevelReadQuery(ReadObjectQuery.java:562)
    at org.eclipse.persistence.queries.ObjectLevelReadQuery.executeDatabaseQuery(ObjectLevelReadQuery.java:1175)
    at org.eclipse.persistence.queries.DatabaseQuery.execute(DatabaseQuery.java:904)
    at org.eclipse.persistence.queries.ObjectLevelReadQuery.execute(ObjectLevelReadQuery.java:1134)
    at org.eclipse.persistence.queries.ReadObjectQuery.execute(ReadObjectQuery.java:441)
    at org.eclipse.persistence.queries.ObjectLevelReadQuery.executeInUnitOfWork(ObjectLevelReadQuery.java:1222)
    at org.eclipse.persistence.internal.sessions.UnitOfWorkImpl.internalExecuteQuery(UnitOfWorkImpl.java:2896)
    at org.eclipse.persistence.internal.sessions.AbstractSession.executeQuery(AbstractSession.java:1857)
    at org.eclipse.persistence.internal.sessions.AbstractSession.executeQuery(AbstractSession.java:1839)
    at org.eclipse.persistence.internal.sessions.AbstractSession.executeQuery(AbstractSession.java:1804)
    at org.eclipse.persistence.internal.jpa.QueryImpl.executeReadQuery(QueryImpl.java:258)
    at org.eclipse.persistence.internal.jpa.QueryImpl.getResultList(QueryImpl.java:465)

How to fix it? Is this a bug or I do something wrong?

Pavel_K
  • 10,748
  • 13
  • 73
  • 186
  • 1
    The JPA contract says that _javax.persistence.Query.getResultList()_ is not allowed to throw ClassCastException so you can conclude that this is a bug and it should be reported to your JPA provider – Neil Stockton Jun 10 '16 at 15:03
  • Seems to work fine in Hibernate 5.0.9.Final. – K.Nicholas Jun 12 '16 at 17:50
  • @Nicholas as far as I know Hibernate ignores fetch graph at all. See my question - http://stackoverflow.com/questions/37054082/hibernate-ignores-fetchgraph – Pavel_K Jun 12 '16 at 17:56
  • In my test, I got two entirely different queries out of hibernate for just the query string above versus the entire code segment above. The entity Graph seemed to be much more optimized than just the query string. – K.Nicholas Jun 12 '16 at 18:05
  • Same problem here: https://stackoverflow.com/questions/62305036/org-eclipse-persistence-indirection-indirectmap-cannot-be-cast-to-org-eclipse-pe Bug already present since 2016, unresolved yet -> https://bugs.eclipse.org/bugs/show_bug.cgi?id=495892 – Kawu Dec 06 '20 at 15:23
  • Please vote for your own bug at https://bugs.eclipse.org/bugs/show_bug.cgi?id=495892 – Kawu Dec 06 '20 at 16:00

1 Answers1

3

Disclaimer - I am not EclipseLink developer and I may be wrong.

As I found out the problem is that Map is not considered as collection in EntityGraph. So I added some code to org.eclipse.persistence.internal.sessions.AbstractSession as a temp workaround for my problem:

public void load(Object objectOrCollection, AttributeGroup group, ClassDescriptor referenceDescriptor, boolean fromFetchGroup) {
  if (objectOrCollection == null || group == null) {
       return;
   }       
   if (objectOrCollection instanceof Collection) {
       Iterator iterator = ((Collection)objectOrCollection).iterator();
       while (iterator.hasNext()) {
           load(iterator.next(), group, referenceDescriptor, fromFetchGroup);
       }
   }//MY CODE STARTS 
    else if(objectOrCollection instanceof Map){
        Map<Object, Object> map = (Map)objectOrCollection;
        Iterator<Map.Entry<Object, Object>> it = map.entrySet().iterator();
        while (it.hasNext()) {
          Map.Entry<Object, Object> entry = it.next();
          load(entry.getValue(), group, referenceDescriptor, fromFetchGroup);
        }
   }//MY CODE ENDS
   else {
       ClassDescriptor concreteDescriptor = referenceDescriptor;
       if (concreteDescriptor.hasInheritance() && !objectOrCollection.getClass().equals(concreteDescriptor.getJavaClass())){
           concreteDescriptor = concreteDescriptor.getInheritancePolicy().getDescriptor(objectOrCollection.getClass());
       }
       AttributeGroup concreteGroup = group.findGroup(concreteDescriptor);
       concreteDescriptor.getObjectBuilder().load(objectOrCollection, concreteGroup, this, fromFetchGroup);
   }

}

Pavel_K
  • 10,748
  • 13
  • 73
  • 186