Question

I have tasked to prepare a quote search screen. I have referred to an Oracle view to create quote model. As there is no id column in the view table, I prefer to use composite id using @IdClass annotation via quoteId.class. I override hashCode and equals method on both model. quoteId equals & hashcode returns a combination of all fields and quote hashcode & equals simply just compare this.quoteNo field in the model.

Quote model:

@Override
public int hashCode()
{
    return new HashCodeBuilder(17,37)
    .append(quoteNo)
    .toHashCode();
}

/*
 * (non-Javadoc)
 * 
 * @see java.lang.Object#equals(java.lang.Object)
 */
@Override
public boolean equals(Object obj)
{
    final quoteModel other = (quoteModel ) obj;
    return new EqualsBuilder().appendSuper(super.equals(other))
            .append(quoteNo, other.quoteNo).isEquals();
}

And when I need unique items I was just accessing via:

uniqueQuoteResults = new ArrayList<Quote>(
                    new LinkedHashSet<Quote>(fullQuoteResults));

But when I start using idClass my linkedHashSet has all items even their quote number same. Am I missing any other implementation to proof each item uniqueness via quote no field(comparable, comparator)? If I trace uniqueQuoteResult list items values all of them has same quote number.

Edit Note: I have changed my way to using apache library HashCodeBuilder and EqualsBuilder support but problem stays same. I am afraid of idClass hashcode is getting effective for linkedhashset

Was it helpful?

Solution

With following code in your model you test is this.quoteNo same instance as obj.quoteNo:

@Override
public boolean equals(Object obj)
{
    // TODO Auto-generated method stub
    return this.quoteNo == ((EprocAwquoteV) obj).quoteNo;
}

Result is that two instances with separately constructed instance of IdClass will be considered to be not equals, if quoteNo is not same object. I guess you want to test equality of quoteNo's instead with something like:

this.quoteNo.equals(other.quoteNo);

Also there is some other problems with current implementation of equals in model (for example it can throw ClassCastException). Basic principles can be found from: Object.equals and Overriding the java equals() method quirk. Additionally with Hibernate it is important to remember, that you should not test are class same, but use instanceof instead (because of proxy classes). Some instructions about writing equals&hascode for entities can be found from Hibernate documentation.

EDIT: Your current approach does not work, because

 return new EqualsBuilder().appendSuper(super.equals(other))

boils it down to the Object.equals. If you do not have superclass with meaningful equals implementation. I am not totally sure do I understand your case right, so maybe you can take a look to the following working example and find out where is the difference:

public class QuoteId implements Serializable {
    private int id1;
    private int id2;

    public QuoteId() {}

    //This equals does not matter when we build LinkedHashSet
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        QuoteId other = (QuoteId) o;
        return id1 == other.id1 && id2 == other.id2;
    }

    public int hashCode() {
        return 31 * id1 + id2;
    }
}

@Entity
@IdClass(QuoteId.class)
public class Quote {
    @Id private int id1;
    @Id private int id2;
    String value;

    public Quote() {
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Quote other = (Quote) o;
        return id1 == other.id1 && id2 == other.id2;
    }

    @Override
    public int hashCode() { return 31 * id1 + id2;}

    //get&set for id1, id2, and value are omitted
}


tx.begin();
em.persist(new Quote(1, 1, "val"));
em.persist(new Quote(1, 2, "val"));
tx.commit();

TypedQuery<Quote> query = em.createQuery("SELECT q FROM Quote q", Quote.class);
List<Quote> twoQuotes = query.getResultList();//both

//duplicating (size=4) result for sake of test;
List<Quote> fullQuoteResults = new ArrayList<Quote>();
fullQuoteResults.addAll(twoQuotes);
fullQuoteResults.addAll(twoQuotes);

//will have same elements as in twoQuotes:
List<Quote> uniqueQuoteResults = new ArrayList<Quote>(
        new LinkedHashSet<Quote>(fullQuoteResults));
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top