• Post Reply Bookmark Topic Watch Topic
  • New Topic
programming forums Java Mobile Certification Databases Caching Books Engineering Micro Controllers OS Languages Paradigms IDEs Build Tools Frameworks Application Servers Open Source This Site Careers Other Pie Elite all forums
this forum made possible by our volunteer staff, including ...
Marshals:
  • Campbell Ritchie
  • Jeanne Boyarsky
  • Ron McLeod
  • Paul Clapham
  • Liutauras Vilda
Sheriffs:
  • paul wheaton
  • Rob Spoor
  • Devaka Cooray
Saloon Keepers:
  • Stephan van Hulst
  • Tim Holloway
  • Carey Brown
  • Frits Walraven
  • Tim Moores
Bartenders:
  • Mikalai Zaikin

Set.Contains() not working in JPA?

 
Greenhorn
Posts: 8
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
I'm a bit new to this and I was doing some unit testing and I found something which totally threw me. I can't explain or work out what the problem might be. Can anyone help me?
Near the bottom in the testOperation() unit test I iterate through the elements of a set and find the element by doing an equals(). The set only has 1 element so it's very basic. Then I do a contains() but that fails???



The output looks like this:

17211 openjpa TRACE [main] openjpa.jdbc.SQL - <t 1641449698, conn 1645997488> executing prepstmnt 1372765087 SELECT NEXTVAL('webscore.OPERATION_ID_SEQ')
17216 openjpa TRACE [main] openjpa.jdbc.SQL - <t 1641449698, conn 1645997488> [4 ms] spent
17310 openjpa TRACE [main] openjpa.jdbc.SQL - <t 1641449698, conn 1848398916> executing prepstmnt 395440162 SELECT NEXTVAL('webscore.OPERATION_ID_SEQ')
17312 openjpa TRACE [main] openjpa.jdbc.SQL - <t 1641449698, conn 1848398916> [2 ms] spent
17411 openjpa TRACE [main] openjpa.jdbc.SQL - <t 1641449698, conn 242597432> executing prepstmnt 1440018046 INSERT INTO webscore.Operation (id, surgery_id) VALUES (?, ?) [params=(long) 25, (long) 42]
17418 openjpa TRACE [main] openjpa.jdbc.SQL - <t 1641449698, conn 242597432> [6 ms] spent
17418 openjpa TRACE [main] openjpa.jdbc.SQL - <t 1641449698, conn 242597432> executing prepstmnt 1319611905 INSERT INTO webscore.Operation (id, surgery_id) VALUES (?, ?) [params=(long) 26, (long) 43]
17420 openjpa TRACE [main] openjpa.jdbc.SQL - <t 1641449698, conn 242597432> [1 ms] spent
1:com.hjb.socrates.jpa.Operation@13b4cd65[surgery=com.hjb.socrates.jpa.Surgery@22cb1edc[name=My first surgery,password=password,licenses=[],operations=[com.hjb.socrates.jpa.Operation@13b4cd65[surgery=com.hjb.socrates.jpa.Surgery@22cb1edc,protocols=[],id=25]],id=42],protocols=[],id=25]
2:equals, com.hjb.socrates.jpa.Operation@13b4cd65[surgery=com.hjb.socrates.jpa.Surgery@22cb1edc[name=My first surgery,password=password,licenses=[],operations=[com.hjb.socrates.jpa.Operation@13b4cd65[surgery=com.hjb.socrates.jpa.Surgery@22cb1edc,protocols=[],id=25]],id=42],protocols=[],id=25]
3:not contained


The output from the unit test looks like this:

java.lang.AssertionError:
at org.junit.Assert.fail(Assert.java:91)
at org.junit.Assert.assertTrue(Assert.java:43)
at org.junit.Assert.assertTrue(Assert.java:54)
at com.hjb.socrates.test.jpa.Entities.testOperation(Entities.java:93)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
at java.lang.reflect.Method.invoke(Unknown Source)
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:44)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:15)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:41)
at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:20)
at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:28)
at org.junit.internal.runners.statements.RunAfters.evaluate(RunAfters.java:31)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:73)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:46)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:180)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:41)
at org.junit.runners.ParentRunner$1.evaluate(ParentRunner.java:173)
at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:28)
at org.junit.internal.runners.statements.RunAfters.evaluate(RunAfters.java:31)
at org.junit.runners.ParentRunner.run(ParentRunner.java:220)
at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:46)
at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:467)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:683)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:390)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:197)

 
Ranch Hand
Posts: 114
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Recently we too have encountered similar problem, I think when an element is added to the Set, it performs some hash on the object to find the bucket.
Even though equals and hashcode is same for object that is present in the set and the one which we are passing to it, it is not able to locate. both contains(), remove() is failing.

I guess it is not able to locate the object in a set once any of its id attributes are changed.

Someone please shed some light on this.

Thanks.
Srikanth.N
 
author & internet detective
Posts: 41860
908
Eclipse IDE VI Editor Java
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Note that [ code ] is the code tag here and not < code >. I've fixed your post for you.

Also, I'm moving this to our ORM forum since it is about JPA.
 
Jeanne Boyarsky
author & internet detective
Posts: 41860
908
Eclipse IDE VI Editor Java
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
This is how it should work. The id is used in determining the hash code. If you change the id, the hash code changes. This makes sense. If you change an id, the objects are no longer equals. If you change your primary key, what would the meaning of equality be?
 
H Blogg
Greenhorn
Posts: 8
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

Jeanne Boyarsky wrote:This is how it should work. The id is used in determining the hash code. If you change the id, the hash code changes. This makes sense. If you change an id, the objects are no longer equals. If you change your primary key, what would the meaning of equality be?



Yes, that's correct. So why does the assertion fail?

I don't changed the id. That's why I'm asking this question. It all seems fine to me but it doesn't work.
Have I made a coding error somewhere?
If you look at the output you can see what I say is the case when the test is run.
I even tried it without inheritance, but I still get the same error.

Sorry about all the edits. I wanted to make it a simple as possible and include as much details as I could. I removed any other dependant classes and added some more output as well as just storing the ids rather than the entities between test cases.
 
Jeanne Boyarsky
author & internet detective
Posts: 41860
908
Eclipse IDE VI Editor Java
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Sorry about that. Srikanth said he changed the id and had the same problem so I didn't read your post carefully.

On to your question: Have you confirmed the ops list is not empty? I ask because if the list is empty, it isn't going through the loop at all and the equality method isn't being run either.
 
H Blogg
Greenhorn
Posts: 8
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

Jeanne Boyarsky wrote:Sorry about that. Srikanth said he changed the id and had the same problem so I didn't read your post carefully.

On to your question: Have you confirmed the ops list is not empty? I ask because if the list is empty, it isn't going through the loop at all and the equality method isn't being run either.



Yes. If you look carefully, I run an iterator through the set just before the contains(). It confirms that the set does in fact have this element and it uses the equals() method to confirm. The output verifies that.

What also seems odd is that when I debug the method I see equals() being called before the contains() but I don't see equals() being called during the contains(). I thought the contains() method used the equals() method to do the comparison. Even if for some reason it was using the default Object equals(), it still should return true as this is a simple circular linkage.
 
Jeanne Boyarsky
author & internet detective
Posts: 41860
908
Eclipse IDE VI Editor Java
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

H Blogg wrote:Yes. If you look carefully, I run an iterator through the set just before the contains(). It confirms that the set does in fact have this element and it uses the equals() method to confirm. The output verifies that.


The output verifies it. The code could pass for an empty list. (I didn't see where you posted about the output. It was probably in there though; it's a long post)

H Blogg wrote:What also seems odd is that when I debug the method I see equals() being called before the contains() but I don't see equals() being called during the contains(). I thought the contains() method used the equals() method to do the comparison. Even if for some reason it was using the default Object equals(), it still should return true as this is a simple circular linkage.


Not necessarily. Assuming you have a HashSet, it calls hashCode() first. If the hash code doesn't match, it returns false. If the hash code does match, it then calls equals().

I suspect the hashCode has a problem, but I don't see what.

I'm going to move your post to Java in General where our hash code experts hang out. If this winds up being about JPA, I can move it back. I think you are more likely to get a resolution in Java in General at this point.
 
H Blogg
Greenhorn
Posts: 8
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

Jeanne Boyarsky wrote: (I didn't see where you posted about the output. It was probably in there though; it's a long post)


It's at the end

Jeanne Boyarsky wrote:I suspect the hashCode has a problem, but I don't see what.


Possibly but this code is generated automatically by eclipse, so I doubt it.

Jeanne Boyarsky wrote:I'm going to move your post to Java in General where our hash code experts hang out. If this winds up being about JPA, I can move it back. I think you are more likely to get a resolution in Java in General at this point.


Yes. I doubt this has anything to do with JPA. It seems to be a problem with the set itself.
 
H Blogg
Greenhorn
Posts: 8
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
A little modification proves there is no problem with the hashCode method:

output:
1:com.hjb.socrates.jpa.Operation@1ad8e902[surgery=com.hjb.socrates.jpa.Surgery@22cb1edc[name=My first surgery,password=password,licenses=[],operations=[com.hjb.socrates.jpa.Operation@1ad8e902[surgery=com.hjb.socrates.jpa.Surgery@22cb1edc,protocols=[],id=41]],id=58],protocols=[],id=41]
op1 hashCode() = 72
2:com.hjb.socrates.jpa.Operation@1ad8e902[surgery=com.hjb.socrates.jpa.Surgery@22cb1edc[name=My first surgery,password=password,licenses=[],operations=[com.hjb.socrates.jpa.Operation@1ad8e902[surgery=com.hjb.socrates.jpa.Surgery@22cb1edc,protocols=[],id=41]],id=58],protocols=[],id=41]
o hashCode() = 72
entities are equal
3:not contained


The only thing I can think of is that I'm using the Set incorrectly but I can't see how. Is there something wrong with the contains() method of Set.
 
H Blogg
Greenhorn
Posts: 8
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
For anyone who's interested, it was my poor understanding of Sets and the way JPA initialises them that caused the problem. There seems to be an inconsistency in the Set.add() method.

This unit test fails:


However this succeeds:



So can anyone shed some light, why the inconsistency?
In the first instance, I'd have thought the Set.add() method would fail and throw a null pointer exception of something.
 
Sheriff
Posts: 22783
131
Eclipse IDE Spring VI Editor Chrome Java Windows
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
What does this print: If this Set class does not implement contains properly, or at least the way you think it does, then this will give you nightmares. By using HashSet you have taken control of how this is implemented.
 
H Blogg
Greenhorn
Posts: 8
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
http://java.sun.com/developer/Books/effectivejava/Chapter3.pdf

Items 7 and 8 helped somewhat.
 
With a little knowledge, a cast iron skillet is non-stick and lasts a lifetime.
reply
    Bookmark Topic Watch Topic
  • New Topic