Page 1 of 2 12 LastLast
Results 1 to 10 of 16

Thread: set contains(obj) returns true but remove(obj) fails.

  1. #1
    Join Date
    Jan 2009
    Location
    Huntington Beach, CA
    Posts
    718

    Default set contains(obj) returns true but remove(obj) fails.

    OK, this is related to my vertex question. But this looks like the brunt of my problem.

    In my User object I have a method to remove the ItemUserSignedUpToBringToEvent from its Set collection. I have implemented ItemUserSignedUpToBringToEvent's equals method to compare nodeIds.

    Code:
    public boolean removeItemSignedUpFor(ItemUserSignedUpToBringToEvent itemSignedUp) {
            return (itemsSignedUpFor.contains(itemSignedUp) &&
                    itemsSignedUpFor.remove(itemSignedUp));
        }
    contains call returns true, but the call to remove fails. Why???

    Here is my equals and hashcode for the ItemUserSignedUpToBringToEvent

    Code:
        @Override
        public boolean equals(Object o) {
            if (this == o) return true;
            if (o == null || getClass() != o.getClass()) return false;
    
            ItemUserSignedUpToBringToEvent signedUpItem = (ItemUserSignedUpToBringToEvent) o;
            if (nodeId == null) return super.equals(o);
            return nodeId.equals(signedUpItem.nodeId);
    
        }
    
        @Override
        public int hashCode() {
            return nodeId != null ? nodeId.hashCode() : super.hashCode();
        }
    In stepping through code, the Spring Data Neo4J class ManagedFieldAccessorSet remove method is returning false.

    Code:
    @Override
        public boolean remove(Object o) {
            if (delegate.remove(o)) {
                update();
                return true;
            }
            return false;
        }
    Thanks

    Mark
    Last edited by bytor99999; May 26th, 2012 at 05:40 PM. Reason: added more

  2. #2
    Join Date
    Jan 2009
    Location
    Huntington Beach, CA
    Posts
    718

    Default

    I hate to say this but I had to do a workaround. Basically had to rewrite the remove() method of my Set instead. So basically not use the Java algorithm Big O notation for removal in a HashSet, which is backed by a HashMap.

    Instead my workaround is brute force or
    I should say brute recreate Set by copying the elements of the first set that I want to keep into the new Set. But it does the trick for now, I am done spending 2 weeks on this one problem. If you remember a couple months ago I posted about this problem but never got resolved.

    Ugly code. (I guess you could call this a Joel Spolsky Duct Tape programmer solution) I apologize in advanced.

    Code:
    public boolean removeItemSignedUpFor(ItemUserSignedUpToBringToEvent itemSignedUp) {
            boolean results = false;
            HashSet<ItemUserSignedUpToBringToEvent> newSet = new HashSet<ItemUserSignedUpToBringToEvent>();
            if (this.itemsSignedUpFor.contains(itemSignedUp)) {
                for (ItemUserSignedUpToBringToEvent inUser : this.itemsSignedUpFor) {
                    if (!inUser.equals(itemSignedUp)) {
                        newSet.add(inUser);
                    } else {
                        results = true;
                    }
                }
            }
            this.itemsSignedUpFor = newSet;
            return results;
        }
    Mark
    Last edited by bytor99999; May 26th, 2012 at 06:00 PM. Reason: forgot a line

  3. #3
    Join Date
    Jan 2009
    Location
    Huntington Beach, CA
    Posts
    718

    Default

    Michael, I am going to raise a Jira issue for this, although I have no idea what is causing this problem. I have done the same for a few other collections and that same code worked perfectly. And I don't think I could make a test that duplicates it either.

    Thanks

    Mark

  4. #4

    Default

    is there JIRA issue raised for this?
    I also ran into this weird situation - I have parent containing children entitities, and childrenSet.contains(child) == true
    but
    childrenSet.remove(child) == false
    ?1

  5. #5
    Join Date
    Jan 2009
    Location
    Huntington Beach, CA
    Posts
    718

    Default

    OK, just created the Jira

    https://jira.springsource.org/browse/DATAGRAPH-267

    Are you using simple mapping or the advanced. I am using Simple at the moment, and wondering if that might have an affect.

    But remember, I am using my hack/cludge as a workaround for now until 2.1 is at least RC1 or 2.

    Mark
    Mark

  6. #6
    Join Date
    Jan 2011
    Location
    Dresden, Germany
    Posts
    525

    Default

    Any chance for a test-case-project? I have a test for remove in SDN which works fine. Seems to be dependent on something else like equals/hashCode?

    I don't think super.hashCode and super.equals work very well in this case. As objects can get an id after they were put into the set and then their equals/hashCode might change.

  7. #7
    Join Date
    May 2012
    Posts
    107

    Default

    Quote Originally Posted by bytor99999 View Post
    Here is my equals and hashcode for the ItemUserSignedUpToBringToEvent

    Code:
        @Override
        public boolean equals(Object o) {
            if (this == o) return true;
            if (o == null || getClass() != o.getClass()) return false;
    
            ItemUserSignedUpToBringToEvent signedUpItem = (ItemUserSignedUpToBringToEvent) o;
            if (nodeId == null) return super.equals(o);
            return nodeId.equals(signedUpItem.nodeId);
    
        }
    
        @Override
        public int hashCode() {
            return nodeId != null ? nodeId.hashCode() : super.hashCode();
        }
    In stepping through code, the Spring Data Neo4J class ManagedFieldAccessorSet remove method is returning false.

    Code:
    @Override
        public boolean remove(Object o) {
            if (delegate.remove(o)) {
                update();
                return true;
            }
            return false;
        }
    Mark,

    The delegate for ManagedFieldAccessorSet should be of type HashSet, and as such, it will look at equals + hashcode for identity. That snippet of code in ManagedFieldAccessorSet is so simple we can ignore it I think.

    So my guess is, there is something subtle going on with your equals and hashcode implementations.

    • try a hashcode implementation of 'return 42;' - not for production use, just to eliminate that as a source of problems
    • for equals, try 'return o instanceof ItemUserSignedUpToBringToEvent && id.equals( (((ItemUserSignedUpToBringToEvent) o).getId()) );' - does that make your test pass?
    • I guess it can be reduced to writing tests for inserting and removing from a HashSet, try writing a unit test like that, to gain confidence your equals and hashcode work independently of SDN


    I just implemented a test to replicate, and actually managed to get equals+hashcode wrong in the first instance, which reproduced your problem Anyway, I got my test passing, so please try these simple remedies, and if it doesn't work I'll have another look.

    Regards,

    Lasse

  8. #8
    Join Date
    Jan 2009
    Location
    Huntington Beach, CA
    Posts
    718

    Default

    Thanks guys. Lasee, I will test your suggestions. And see if I can isolate my stuff for a good sample.

    Mark

  9. #9
    Join Date
    Jan 2009
    Location
    Huntington Beach, CA
    Posts
    718

    Default

    Although, what is odd, is that in many other collections it works. And that all my entity/domain objects have basically the exact same equals/hashcode. I just copied and pasted the code in all my objects, then just had to change the types in the code to match the domain object it was in.

    Mark

  10. #10

    Default

    Just want to point out that I also created yesterday the issue tied to this (maybe not the best issue title):
    https://jira.springsource.org/browse/DATAGRAPH-265

    But I finally think that crux of problem is described in:
    http://forum.springsource.org/showth...o-lazy-loading

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •