Java Set of type POJO not able to add elements

Viewed 147

I've a data object class:

public class MyDataObject {
  private String value;
  private String text;
  private Set<MyDataObject> child;

  // Getter & setters

  // Constructor
  public MyDataObject(final String value, final String text) {
    this.value = value;
    this.text = text;
  }

  @Override
  public boolean equals(Object o) {
    if (this == o) return true;
    if (o == null || getClass() != o.getClass()) return false;
    MyDataObject that = (MyDataObject) o;
    return value.equals(that.value) &&
            text.equals(that.text) &&
            Objects.equals(child, that.child);
  }

  @Override
  public int hashCode() {
    return Objects.hash(value, text, child);
  }
}

I'm adding 2 child elements in one of my MyDataObject object.

Say:

MyDataObject myDataObject = new MyDataObject("USA", "United States");
Set<MyDataObject> childSet = new TreeSet<>(Comparator.comparing(MyDataObject::getText));
childSet.add(new MyDataObject("NY", "Bronx"));      // This is added
childSet.add(new MyDataObject("NY", "Manhattan"));  // This is not being added, returing false.
myDataObject.setChild(childSet);

I've overridden hashcode and equals method as well to consider child element.

What am I missing?

3 Answers

Your Comparator is not consistent with equals.

That is: you have selected a Comparator for your Set that returns 0 in cases where your equals(Object) method returns false.

The issue you mentioned can be reproduced by Comparator.comparing(MyDataObject::getValue). Nevertheless, both the comparators Comparator.comparing(MyDataObject::getText) and Comparator.comparing(MyDataObject::getValue) are inconsistent with the equals. See the javadoc of TreeSet where this is mentioned.

    final Comparator<MyDataObject> myDataObjectComparator = Comparator.comparing(MyDataObject::getValue);
    final MyDataObject myDataObject1 = new MyDataObject("NY", "Bronx");
    final MyDataObject myDataObject2 = new MyDataObject("NY", "Manhattan");
    System.out.println(myDataObject1.equals(myDataObject2));
    System.out.println(myDataObjectComparator.compare(myDataObject1, myDataObject2));

Note that the equals say that the objects are not equal while compareTo gives 0. For the same two objects.

I am changed a little your code. childSet.add expect object but you send two strings. This resolve work for me.

    MyDataObject myDataObject = new MyDataObject("USA", "United States");
    Set<MyDataObject> childSet = new TreeSet<>(Comparator.comparing(MyDataObject::getText));
    MyDataObject myDataObject1 = new MyDataObject("NY", "Bronx");
    MyDataObject myDataObject2 = new MyDataObject("NY", "Manhattan");
    childSet.add(myDataObject1);        // This is added
    childSet.add(myDataObject2);    // This is not being added, returing false.
    myDataObject.setChild(childSet);

    myDataObject.getChild()
            .stream()
            .map(child -> child.getValue() + " " + child.getText())
            .forEach(System.out::println);
Related