-->
These old forums are deprecated now and set to read-only. We are waiting for you on our new forums!
More modern, Discourse-based and with GitHub/Google/Twitter authentication built-in.

All times are UTC - 5 hours [ DST ]



Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 3 posts ] 
Author Message
 Post subject: EntityManager.find returns a wrong class from 2nd lvl cache
PostPosted: Mon Jan 20, 2014 11:52 am 
Newbie

Joined: Mon Dec 13, 2010 10:10 am
Posts: 5
Hi,

We've encountered a pretty strange error, it seems that the entity manager loads the entity from the second level cache ignoring the entity class
We're using Spring 3.1.3 with Hibernate 4.1.7 (though I tested it with 4.3.0 and the problem still exists). Let's suppose that we have a root entity:
Code:
@Entity
@Inheritance(strategy = InheritanceType.SINGLE_TABLE)
@Table(name = "test_entities")
@Cache(usage = CacheConcurrencyStrategy.READ_WRITE)
public class TestEntityRoot {

    @Id
    @GeneratedValue(generator = "entity_id_generator")
    @GenericGenerator(name = "entity_id_generator", strategy
        = "org.hibernate.id.enhanced.TableGenerator", parameters = {
            @Parameter(name = TableGenerator.CONFIG_PREFER_SEGMENT_PER_ENTITY, value = "true"),
            @Parameter(name = TableGenerator.INCREMENT_PARAM, value = "100"),
            @Parameter(name = TableGenerator.OPT_PARAM, value = "pooled")})
    private Long id;

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }
}

and two child entities, A
Code:
@Entity
public class TestEntityA extends TestEntityRoot{
}

and B
Code:
@Entity
public class TestEntityB extends TestEntityRoot{
}

And we have the following (minimal) test class:
Code:
@Component
@Transactional
public class TestHibernate implements ITestHibernate {

    @PersistenceContext
    private EntityManager entityManager;

    public static void main(String[] args) {
        ITestHibernate test = new ClassPathXmlApplicationContext("classpath:/META-INF/context.xml").getBean(ITestHibernate.class);
        long id = test.createA();
        test.createB();
        test.loadAll();
        test.testLoad(id);
    }

    @Override
    public long createA() {
        TestEntityA entity = new TestEntityA();
        entityManager.persist(entity);
        return entity.getId();
    }

    @Override
    public void createB() {
        TestEntityB entity = new TestEntityB();
        entityManager.persist(entity);
    }

    @Override
    public void loadAll() {
        entityManager.unwrap(Session.class).createQuery("select E from " + TestEntityRoot.class.
            getName() + " E").setCacheable(true).list();
    }

    @Override
    public void testLoad(long id) {
        TestEntityB b = entityManager.find(TestEntityB.class, id);
        System.out.println(b);
    }
}

If we run this class it would fail in the testLoad() method with
Code:
Exception in thread "main" java.lang.ClassCastException: test.TestEntityA cannot be cast to test.TestEntityB
   at test.TestHibernate.testLoad(TestHibernate.java:57)
   at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
   at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
   at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
   at java.lang.reflect.Method.invoke(Method.java:606)
   at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:318)
   at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:183)
   at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:150)
   at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:110)
   at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172)
   at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:202)
   at com.sun.proxy.$Proxy108.testLoad(Unknown Source)
   at test.TestHibernate.main(TestHibernate.java:33)


So, basically, the test creates two entities A and B, then loads them both using and HQL query and then tries to read B with the id of A. All four methods use the separate transactions and thus each has its own session.
If the @Cache annotation is commented then the test works as expected, i.e., the find() method returns null. But if the cache is enabled then it loads A despite the fact that it was told to load an instance of B. I debugged it a little and it seems that this problem is caused by the following lines in the org.hibernate.event.internal.DefaultLoadEventListener's loadFromSecondLevelCache method:
Code:
      final CacheKey ck = source.generateCacheKey(
            event.getEntityId(),
            persister.getIdentifierType(),
            persister.getRootEntityName()
      );

It seems that it ignores the entity name and uses the root entity instead. Is it a bug in Hibernate or am I missing something? And is there a fix or workaround to this issue besides disabling the second level cache?


Top
 Profile  
 
 Post subject: Re: EntityManager.find returns a wrong class from 2nd lvl cache
PostPosted: Wed Jan 29, 2014 5:24 am 
Newbie

Joined: Mon Dec 13, 2010 10:10 am
Posts: 5
So, is it a bug? Should I submit it to JIRA or something?


Top
 Profile  
 
 Post subject: Re: EntityManager.find returns a wrong class from 2nd lvl cache
PostPosted: Mon May 05, 2014 3:18 pm 
Beginner
Beginner

Joined: Sat Apr 07, 2007 4:42 pm
Posts: 24
Same problem here.
Any solution?
Thank you


Top
 Profile  
 
Display posts from previous:  Sort by  
Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 3 posts ] 

All times are UTC - 5 hours [ DST ]


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum

Search for:
© Copyright 2014, Red Hat Inc. All rights reserved. JBoss and Hibernate are registered trademarks and servicemarks of Red Hat, Inc.