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.  [ 18 posts ]  Go to page 1, 2  Next
Author Message
 Post subject: Puzzling this on an Hibernate entity and its collection
PostPosted: Mon Jul 11, 2011 8:36 am 
Pro
Pro

Joined: Mon Apr 16, 2007 8:10 am
Posts: 246
Hello,

I have a very puzzling thing happening around an Hibernate entity and its collection property.

There is an entity LinkCategory which has a collection property of Link(s).

Here is the Hibernate mapping:
Code:
       
<set name="links" inverse="true" order-by="list_order" cascade="all">
   <key column="category_id" />
        <one-to-many class="com.thalasoft.learnintouch.core.domain.Link" />
</set>


In the LinkCategory domain class, there is a removeLink method:
Code:
   public void removeLink(Link link) {
      logger.debug("========================>> About to remove a link");
      logger.debug("========================>> link.getLinkCategory: " + link.getLinkCategory() + " this: " + this);
      if (link.getLinkCategory() == this) {
         logger.debug("========================>> Removing a link");
         link.setLinkCategory(null);
         this.links.remove(link);
         logger.debug("========================>> Removed a link");
      }
   }


When I instantiate a LinkCategory object and its collection of links, as in:
Code:
      link0 = new Link();
      link0.setName("Thalasoft");
      link0.setImage("image0.png");
      link0.setListOrder(3);
      linkCategory0.addLink(link0);
      link2 = new Link();
      link2.setName("Google");
      link2.setImage("image2.gif");
      link2.setListOrder(1);
      linkCategory0.addLink(link2);
      link1 = new Link();
      link1.setName("Libe");
      link1.setImage("image1.jpg");
      link1.setListOrder(2);
      linkCategory0.addLink(link1);

and this without doing any persistence of the object, a call to the removeLink method works fine, and the 4 logger debug statements sitting in the method, are all displayed.

But when I persist the same entity, then retrieving it into another object, and calling the removeLink method on one of the links, only the first 2 logger debug statements are displayed, the if statement resolves to false and its 2 logger debug statements are not displayed.

So I tend to think that only when retrieving a LinkCategory entity into an object, the Link(s) collection property is not correctly set.

And so, to make sure, this is the case, I have the following source code, right after having retrieved the object, and before calling the removeLink method:

Code:
      for (Link thelink : linkCategory.getLinks()) {
         if ((thelink.getLinkCategory() == linkCategory)) {
            logger.debug("=================>> The link has the same link category.");
            linkCategory.removeLink(thelink);
         }
      }


And surprise, the if statement resolves to true ! But inside this if statement, the if statement in the removeLink method resolves to false ! This on the same object ! Or, is it the same object..

Any clue ?


Last edited by stephaneeybert on Mon Jul 11, 2011 8:47 am, edited 1 time in total.

Top
 Profile  
 
 Post subject: Re: Puzzling this on an Hibernate entity and its collection
PostPosted: Mon Jul 11, 2011 8:39 am 
Pro
Pro

Joined: Mon Apr 16, 2007 8:10 am
Posts: 246
Here is the test case:

Code:
   @Test
   public void testCollection() {
      link0 = new Link();
      link0.setName("Thalasoft");
      link0.setImage("image0.png");
      link0.setListOrder(3);
      linkCategory0.addLink(link0);
      link2 = new Link();
      link2.setName("Google");
      link2.setImage("image2.gif");
      link2.setListOrder(1);
      linkCategory0.addLink(link2);
      link1 = new Link();
      link1.setName("Libe");
      link1.setImage("image1.jpg");
      link1.setListOrder(2);
      linkCategory0.addLink(link1);
      linkCategoryDao.flush();
      linkCategoryDao.clear();
      LinkCategory linkCategory = linkCategoryDao.findWithId(linkCategory0.getId(), false);
      assertEquals(3, linkCategory.getLinks().size());
      Iterator<Link> results = linkCategory.getLinks().iterator();
      Link link = (Link) results.next();
      assertEquals(link2.getName(), link.getName());
      link = (Link) results.next();
      assertEquals(link1.getName(), link.getName());
      link = (Link) results.next();
      assertEquals(link0.getName(), link.getName());
      for (Link thelink : linkCategory.getLinks()) {
         if ((thelink.getLinkCategory() == linkCategory)) {
            logger.debug("=================>> The link has the same link category.");
            linkCategory.removeLink(thelink);
         }
      }
   }



Top
 Profile  
 
 Post subject: Re: Puzzling this on an Hibernate entity and its collection
PostPosted: Mon Jul 11, 2011 8:46 am 
Pro
Pro

Joined: Mon Apr 16, 2007 8:10 am
Posts: 246
The console output:
Quote:
Hibernate:
select
linkcatego0_.id as id75_0_,
linkcatego0_.version as version75_0_,
linkcatego0_.name as name75_0_,
linkcatego0_.description as descript4_75_0_
from
link_category linkcatego0_
where
linkcatego0_.id=?
2011-07-11 14:45:06,206 TRACE [BasicBinder] binding parameter [1] as [INTEGER] - 8
2011-07-11 14:45:06,219 TRACE [BasicExtractor] found [1] as column [version75_0_]
2011-07-11 14:45:06,219 TRACE [BasicExtractor] found [Images] as column [name75_0_]
2011-07-11 14:45:06,219 TRACE [BasicExtractor] found [null] as column [descript4_75_0_]
Hibernate:
select
links0_.category_id as category8_75_1_,
links0_.id as id1_,
links0_.id as id27_0_,
links0_.version as version27_0_,
links0_.name as name27_0_,
links0_.description as descript4_27_0_,
links0_.image as image27_0_,
links0_.url as url27_0_,
links0_.list_order as list7_27_0_,
links0_.category_id as category8_27_0_
from
link links0_
where
links0_.category_id=?
order by
links0_.list_order
2011-07-11 14:45:06,227 TRACE [BasicBinder] binding parameter [1] as [INTEGER] - 8
2011-07-11 14:45:06,231 TRACE [BasicExtractor] found [12] as column [id27_0_]
2011-07-11 14:45:06,231 TRACE [BasicExtractor] found [0] as column [version27_0_]
2011-07-11 14:45:06,232 TRACE [BasicExtractor] found [Google] as column [name27_0_]
2011-07-11 14:45:06,232 TRACE [BasicExtractor] found [null] as column [descript4_27_0_]
2011-07-11 14:45:06,232 TRACE [BasicExtractor] found [image2.gif] as column [image27_0_]
2011-07-11 14:45:06,232 TRACE [BasicExtractor] found [null] as column [url27_0_]
2011-07-11 14:45:06,232 TRACE [BasicExtractor] found [1] as column [list7_27_0_]
2011-07-11 14:45:06,232 TRACE [BasicExtractor] found [8] as column [category8_27_0_]
2011-07-11 14:45:06,232 TRACE [BasicExtractor] found [8] as column [category8_75_1_]
2011-07-11 14:45:06,232 TRACE [BasicExtractor] found [12] as column [id1_]
2011-07-11 14:45:06,233 TRACE [BasicExtractor] found [10] as column [id27_0_]
2011-07-11 14:45:06,233 TRACE [BasicExtractor] found [0] as column [version27_0_]
2011-07-11 14:45:06,233 TRACE [BasicExtractor] found [Libe] as column [name27_0_]
2011-07-11 14:45:06,233 TRACE [BasicExtractor] found [null] as column [descript4_27_0_]
2011-07-11 14:45:06,233 TRACE [BasicExtractor] found [image1.jpg] as column [image27_0_]
2011-07-11 14:45:06,233 TRACE [BasicExtractor] found [null] as column [url27_0_]
2011-07-11 14:45:06,233 TRACE [BasicExtractor] found [2] as column [list7_27_0_]
2011-07-11 14:45:06,234 TRACE [BasicExtractor] found [8] as column [category8_27_0_]
2011-07-11 14:45:06,235 TRACE [BasicExtractor] found [8] as column [category8_75_1_]
2011-07-11 14:45:06,235 TRACE [BasicExtractor] found [10] as column [id1_]
2011-07-11 14:45:06,235 TRACE [BasicExtractor] found [11] as column [id27_0_]
2011-07-11 14:45:06,235 TRACE [BasicExtractor] found [0] as column [version27_0_]
2011-07-11 14:45:06,235 TRACE [BasicExtractor] found [Thalasoft] as column [name27_0_]
2011-07-11 14:45:06,235 TRACE [BasicExtractor] found [null] as column [descript4_27_0_]
2011-07-11 14:45:06,235 TRACE [BasicExtractor] found [image0.png] as column [image27_0_]
2011-07-11 14:45:06,235 TRACE [BasicExtractor] found [null] as column [url27_0_]
2011-07-11 14:45:06,235 TRACE [BasicExtractor] found [3] as column [list7_27_0_]
2011-07-11 14:45:06,235 TRACE [BasicExtractor] found [8] as column [category8_27_0_]
2011-07-11 14:45:06,236 TRACE [BasicExtractor] found [8] as column [category8_75_1_]
2011-07-11 14:45:06,236 TRACE [BasicExtractor] found [11] as column [id1_]
2011-07-11 14:45:06,242 DEBUG [LinkCategoryDaoTest] =================>> The link has the same link category.
2011-07-11 14:45:06,244 DEBUG [LinkCategory] ========================>> About to remove a link
2011-07-11 14:45:06,244 DEBUG [LinkCategory] ========================>> link.getLinkCategory: com.thalasoft.learnintouch.core.domain.LinkCategory@11126f6 this: com.thalasoft.learnintouch.core.domain.LinkCategory@11126f6
2011-07-11 14:45:06,244 DEBUG [LinkCategoryDaoTest] =================>> The link has the same link category.
2011-07-11 14:45:06,244 DEBUG [LinkCategory] ========================>> About to remove a link
2011-07-11 14:45:06,244 DEBUG [LinkCategory] ========================>> link.getLinkCategory: com.thalasoft.learnintouch.core.domain.LinkCategory@11126f6 this: com.thalasoft.learnintouch.core.domain.LinkCategory@11126f6
2011-07-11 14:45:06,244 DEBUG [LinkCategoryDaoTest] =================>> The link has the same link category.
2011-07-11 14:45:06,249 DEBUG [LinkCategory] ========================>> About to remove a link
2011-07-11 14:45:06,250 DEBUG [LinkCategory] ========================>> link.getLinkCategory: com.thalasoft.learnintouch.core.domain.LinkCategory@11126f6 this: com.thalasoft.learnintouch.core.domain.LinkCategory@11126f6
20


Top
 Profile  
 
 Post subject: Re: Puzzling this on an Hibernate entity and its collection
PostPosted: Mon Jul 11, 2011 8:55 am 
Pro
Pro

Joined: Mon Apr 16, 2007 8:10 am
Posts: 246
The if statement in the removeLink method, is to make sure the object really is an item of the collection of the parent object. The object must be one and the same. The if statement is not comparing the objects values.


Top
 Profile  
 
 Post subject: Re: Puzzling this on an Hibernate entity and its collection
PostPosted: Mon Jul 11, 2011 8:56 am 
Pro
Pro

Joined: Mon Apr 16, 2007 8:10 am
Posts: 246
I also tried with a hashCode() as in:

Code:
      if (link.getLinkCategory().hashCode() == this.hashCode()) {


But it changed nothing at all in the console output.


Top
 Profile  
 
 Post subject: Re: Puzzling this on an Hibernate entity and its collection
PostPosted: Tue Jul 12, 2011 3:21 pm 
Newbie

Joined: Tue Jul 12, 2011 2:58 pm
Posts: 1
Hi,

I understood your problem to some extent. I think without persisting the things work fine, that means something wrong is happening once you persist the object.

This might be happening because of Hibernate keeping its different object reference in the cache or session.

To resolve this problem did you try to override .equals method in both LinkCategory and Links object to compare objects logically?
Once eqauls method is overriden you can use .eqauls for comparison instead of ==.

If you don't want it to be done that way, please let me know so that we can handle it in some other way.
I hope it helps.



Thanks,
GyanomTech


Top
 Profile  
 
 Post subject: Re: Puzzling this on an Hibernate entity and its collection
PostPosted: Mon Jul 18, 2011 2:20 am 
Pro
Pro

Joined: Mon Apr 16, 2007 8:10 am
Posts: 246
Hi Gyanom,

Thanks for your comment, it is appreciated.

Yes, it is correct that without persisting the thing work fine.

But when the entity is retrieved by Hibernate, the this keyword acts in a funky way.

To be more precise, the linkCategory object retrieved by Hibernate is correctly set up.

The following code bit sitting in the test case method displays fine the line "The first if is true" in the console.

Code:
      for (Link thelink : linkCategory.getLinks()) {
         if (thelink.getLinkCategory() == linkCategory) {
            logger.debug("========================>> The first if is true");
            linkCategory.removeLink(thelink, linkCategory);
         }
      }

Now, note the redundant usage (for demo purposes only) of the linkCategory object in the call to removeLink above, once as the reference and once as a method argument.

Code:
            linkCategory.removeLink(thelink, linkCategory);

I modified the method to accept this redundant parameter, as in:

Code:
   public void removeLink(Link link, LinkCategory linkCategory) {
      logger.debug("========================>> About to remove a link");
      logger.debug("========================>> link.getLinkCategory: " + link.getLinkCategory() + " this: " + this);
      if (link.getLinkCategory() == linkCategory) {
         logger.debug("========================>> The second if is true");
      }
      if (link.getLinkCategory() == this) {
         logger.debug("========================>> Removing a link");
         link.setLinkCategory(null);
         this.links.remove(link);
         logger.debug("========================>> Removed a link");
      }
   }


The method call displays fine the text "The second if is true" in the console.

This means that the linkCategory object passed in the method parameter is correctly set up.

But none of the following texts "Removing a link" nor "Removed a link" are displayed.

This means that the this object is not correctly set up.

But the linkCategory object and the this object are one and the same, or they should be.

How to explain that the same linkCategory object used redundantly in the method call has different behaviors if used as a parameter or used as the this object ?

Here is the test case in full:

Code:
   @Test
   public void testCollection() {
      link0 = new Link();
      link0.setName("Thalasoft");
      link0.setImage("image0.png");
      link0.setListOrder(3);
      linkCategory0.addLink(link0);
      link2 = new Link();
      link2.setName("Google");
      link2.setImage("image2.gif");
      link2.setListOrder(1);
      linkCategory0.addLink(link2);
      link1 = new Link();
      link1.setName("Libe");
      link1.setImage("image1.jpg");
      link1.setListOrder(2);
      linkCategory0.addLink(link1);
      linkCategoryDao.flush();
      linkCategoryDao.clear();
      LinkCategory linkCategory = linkCategoryDao.findWithId(linkCategory0.getId(), false);
      assertEquals(3, linkCategory.getLinks().size());
      Iterator<Link> results = linkCategory.getLinks().iterator();
      Link link = (Link) results.next();
      assertEquals(link2.getName(), link.getName());
      link = (Link) results.next();
      assertEquals(link1.getName(), link.getName());
      link = (Link) results.next();
      assertEquals(link0.getName(), link.getName());
      for (Link thelink : linkCategory.getLinks()) {
         if (thelink.getLinkCategory() == linkCategory) {
            logger.debug("========================>> The first if is true");
            linkCategory.removeLink(thelink, linkCategory);
         }
      }
      linkCategoryDao.flush();
      linkCategoryDao.clear();
      linkCategory = linkCategoryDao.findWithId(linkCategory0.getId(), false);
      assertEquals(2, linkCategory.getLinks().size());
      assertEquals(link2.getName(), linkCategory.getLinks().iterator().next().getName());
      assertEquals(link0.getName(), linkCategory.getLinks().iterator().next().getName());
   }


Last edited by stephaneeybert on Sun Nov 20, 2011 1:43 pm, edited 1 time in total.

Top
 Profile  
 
 Post subject: Re: Puzzling this on an Hibernate entity and its collection
PostPosted: Wed Jul 20, 2011 5:50 am 
Newbie

Joined: Fri Jul 15, 2011 3:46 am
Posts: 3
I'd guess that it's related to the way Hibernate handles proxying of collections. Without actually running the code and inspecting the objects in question I won't swear to this, but I'm reasonably certain that one of your LinkCategory objects is a proxy instead of the real object. When working with Hibernate the use of == isn't always a good idea, using equals(..) is much more likely to behave correctly...assuming of course you have a naturalID or you're persisting the object before comparing that is.

Alex


Top
 Profile  
 
 Post subject: Re: Puzzling this on an Hibernate entity and its collection
PostPosted: Wed Jul 20, 2011 12:35 pm 
Pro
Pro

Joined: Mon Apr 16, 2007 8:10 am
Posts: 246
Hi Alex,

Yes, I'm persisting the object before comparing. In fact the issue only occurs if persisting before.

I understand the collection is proxied, lazy loading as it should, but how to explain that the this reference and the linkCategory reference have different values ?


Top
 Profile  
 
 Post subject: Re: Puzzling this on an Hibernate entity and its collection
PostPosted: Thu Jul 21, 2011 4:50 pm 
Newbie

Joined: Fri Jul 15, 2011 3:46 am
Posts: 3
Again not quite certain about this, but I'd guess that when referencing linkCategory from a different object it's actually Proxy extends LinkCategory, which also contains a linkCategory reference. Once you're in an actual linkCategory object this will reference the object itself, where the passed reference is to the proxy.

Setting a breakpoint in your code and inspecting the objects ought to show you though.

Alex


Top
 Profile  
 
 Post subject: Re: Puzzling this on an Hibernate entity and its collection
PostPosted: Thu Jul 21, 2011 5:05 pm 
Pro
Pro

Joined: Mon Apr 16, 2007 8:10 am
Posts: 246
Hi Zakath,

That's an interesting suggestion. Indeed, using the "this" keyword within the method still makes use of the proxied object. Whereas using a passed in argument probably retrieves the actual object and not its proxy.

Now I'll see about running the debugger.

Cheers,

Stephane


Top
 Profile  
 
 Post subject: Re: Puzzling this on an Hibernate entity and its collection
PostPosted: Thu Jul 21, 2011 6:04 pm 
Pro
Pro

Joined: Mon Apr 16, 2007 8:10 am
Posts: 246
So I tried two things to load the proxied object.

One was to access one of its properties, namely the getName one.

And another one was to initialize it.

Code:
   public void removeLink(Link link, LinkCategory linkCategory) {
      logger.debug("========================>> About to remove a link");
      logger.debug("========================>> link.getLinkCategory: " + link.getLinkCategory() + " this: " + this);
      if (link.getLinkCategory() == linkCategory) {
         logger.debug("========================>> The second if is true");
      }
      String dummy = this.getName();
      Hibernate.initialize(this);
      if (link.getLinkCategory() == this) {
         logger.debug("========================>> Removing a link");
         link.setLinkCategory(null);
         this.links.remove(link);
         logger.debug("========================>> Removed a link");
      }
   }

But none of these two attempts did anything.

The issue remained the same, as did the console output.


Last edited by stephaneeybert on Sun Nov 20, 2011 1:43 pm, edited 1 time in total.

Top
 Profile  
 
 Post subject: Re: Puzzling this on an Hibernate entity and its collection
PostPosted: Sat Oct 08, 2011 4:45 am 
Pro
Pro

Joined: Mon Apr 16, 2007 8:10 am
Posts: 246
When I change the if statement in the model class to compare, not the objects themselves, but their id, I get an exception signifying me that I attempted to modify an object that was already being used in a fast failing loop.

Here is the if statement:
Code:
   public void removeLink(Link link) {
      logger.debug("========================>> About to remove a link");
      logger.debug("========================>> link.getLinkCategory: " + link.getLinkCategory() + " this: " + this);
      if (link.getLinkCategory().getId() == this.getId()) {
         logger.debug("========================>> Removing a link");
         link.setLinkCategory(null);
         this.links.remove(link);
         logger.debug("========================>> Removed a link");
      }
   }


Quote:
java.util.ConcurrentModificationException
at java.util.LinkedHashMap$LinkedHashIterator.nextEntry(LinkedHashMap.java:373)
at java.util.LinkedHashMap$KeyIterator.next(LinkedHashMap.java:384)
at org.hibernate.collection.AbstractPersistentCollection$IteratorProxy.next(AbstractPersistentCollection.java:580)
at com.thalasoft.learnintouch.core.dao.LinkCategoryDaoTest.testCollection(LinkCategoryDaoTest.java:94)


Indeed, the object is lazily loaded and its collection is proxied.

How to go to check that two object references, that happen to be one object still in a proxied state, reference the same object ?


Last edited by stephaneeybert on Sun Nov 20, 2011 3:06 pm, edited 1 time in total.

Top
 Profile  
 
 Post subject: Re: Puzzling this on an Hibernate entity and its collection
PostPosted: Sun Nov 20, 2011 1:47 pm 
Pro
Pro

Joined: Mon Apr 16, 2007 8:10 am
Posts: 246
I tried to unproxy the retrieved object with the following statement:

linkCategoryDao.initializeAndUnproxy(linkCategory);

Here is the implementation of the method:
Code:
   public <T> T initializeAndUnproxy(T entity) {
      if (entity == null) {
         throw new NullPointerException("The entity passed for unproxying is null.");
      }
      Hibernate.initialize(entity);
      if (entity instanceof HibernateProxy) {
         entity = (T) ((HibernateProxy) entity).getHibernateLazyInitializer().getImplementation();
      }
      return entity;
   }


But it didn't change anything in the exception.


Top
 Profile  
 
 Post subject: Re: Puzzling this on an Hibernate entity and its collection
PostPosted: Sun Nov 20, 2011 3:09 pm 
Pro
Pro

Joined: Mon Apr 16, 2007 8:10 am
Posts: 246
I also tried to initialize the object so as to eagerly load it, but it didn't change anything in the original exception.
Code:
      Hibernate.initialize(linkCategory.getLinks());
      for (Link thelink : linkCategory.getLinks()) {
         if (thelink.getLinkCategory() == linkCategory) {
            logger.debug("========================>> The first if is true");
            linkCategory.removeLink(thelink);
         }
      }


Quote:
java.lang.AssertionError: expected:<2> but was:<3>


Top
 Profile  
 
Display posts from previous:  Sort by  
Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 18 posts ]  Go to page 1, 2  Next

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.