Sorting Hibernate Set using a comparator

      11 Comments on Sorting Hibernate Set using a comparator

Collection mappings in Hibernate can be configured to sort using a specific comparator.

Consider the following mapping

<hibernate-mapping>
<class name="com.example.Person" table="PERSON">
......

<set name="bankAccounts" lazy="true" cascade="all,delete-orphan" inverse="true" sort="natural">
	<key>
		<column name="BANK_ACCOUNT_ID" precision="29" scale="0" not-null="true" />
	</key>
	<one-to-many class="com.example.BankAccount" />
</set>

......
</class>
</hibernate-mapping>

In the example above Hibernate will order the bankAccounts set according to their natural order. If the BankAccout class implements Comparable interface, compareTo method will be used to sort the Set.

What if you want to sort the set differently? What if you want to use a comparator to sort the set.
The sort attribute can have three possible values

The first option is

 <set name="bankAccounts" lazy="true" cascade="all,delete-orphan" inverse="true" sort="natural">

which sorts by natural order

the second option is

 <set name="bankAccounts" lazy="true" cascade="all,delete-orphan" inverse="true" sort="unsorted">

which tells Hibernate that the Set needs not to be sorted

and the third option is

 <set name="bankAccounts" lazy="true" cascade="all,delete-orphan" inverse="true" sort="comparatorClass">

where you specify what comparator should be used to sort the Set.

Let’s see it through code example. For example suppose class BankAccount is defined as below

package com.example;
//import statements

public class BankAccount implements Comparable<BankAccount>, Serializable{

private String accountName;
private String accountShortName;
//getter and setter methods

    public int compareTo(BankAccount that) {

        final int BEFORE = -1;
        final int AFTER = 1;

        if (that == null) {
            return BEFORE;
        }

        Comparable thisAccountName = this.getAccountName();
        Comparable thatAccountName = that.getAccountName();

        if(thisAccountName == null) {
        	return AFTER;
        } else if(thatAccountName == null) {
        	return BEFORE;
        } else {
        	return thisAccountName.compareTo(thatAccountName);
        }
    }
}

In this case sort=”natural” will sort using the above compareTo method which compares the accountName to sort.
Now suppose you want that for this specific mapping you want the collection to be sorted by, say, accountShortName. You will define a Comparator like this

package com.example;
//import statements
public class BankAccountShortNameComparator implements Comparator<BankAccount>{
	public int compare(BankAccount o1, BankAccount o2) {
		if(o1!=null && o2!=null && o1.getAccountShortName()!=null && o2.getAccountShortName()!=null) {
			return o1.getAccountShortName().compareTo(o2.getAccountShortName());
		}
		if(o1!=null && o2!=null) {
			return o1.compareTo(o2);
		}

		return 0;
	}
}

Then your mapping will say something like this

	<set name="bankAccounts" lazy="true" cascade="all,delete-orphan" inverse="true" sort="com.example.BankAccountShortNameComparator">

In this way Hibernate will use your custom Comparator to sort the set

11 thoughts on “Sorting Hibernate Set using a comparator

  1. Paras

    Hello,
    I could not get your question fully. What number sorter you want to use? Is your primary key a Class? What is the relation between the number and the primary key? Please explain the scenario

    Reply
      1. salvin francis

        well i m sorry i cant share tht wid you (company code)

        but here is the thing i can say:

        something called “todo” in my application has a many-to-one relation with “priority”

        so todo relation is:

        and the priority hbm file contains:

        the HQL query (i am not allowed to use SQL) uses orderby

        The issue is priority is sorted Alphabetically, however
        this is not correct for “High”,”Medium”,”Low” (since “L” comes before “M”)
        someone suggested me to use lowercase for “l” but i consider that a Hack.

        Reply
  2. salvin francis

    Todo contains Priority:

    todo relationship

    priority relationship

    actual ordering in priority (alphabetically):
    “High”,”Low”,”Medium”

    required order:
    “High”,”Medium”,”Low”

    Reply
  3. salvin francis

    Todo contains Priority:
    todo relationship
    <code>
    <many-to-one
    name="prtyHdr"
    class=[priority class name]
    not-null="true"
    >
    <column name="PR_ID"/>
    </many-to-one>
    </code>

    priority relationship
    <code>
    <set
    name="todoLogs"
    lazy="true"
    inverse="true"
    cascade="all"
    >
    <key>
    <column name="PR_ID"/>
    </key>
    <one-to-many
    class=[todo class name]
    />
    </set>
    </code>
    actual ordering in priority (alphabetically):
    "High","Low","Medium"
    required order:
    "High","Medium","Low"

    Reply
  4. Paras

    What I understand from the scenario that you have list of to-dos and every ToDO has a priority.

    I am confused at the exact scenario. I guess the scenario could be one of the following

    i) Scenario 1 – You are showing the list of ToDos on some page and by default the ToDos are coming in the order of HLM and you want in HML order. In that case you must be holding ToDos in some collection and that collection will sort in the order of natural sorting. In order to override that your ToDo class has to implement Comparable interface and you have to write compareTo method accordingly. It is a good idea to implement equals and hashcode also for ToDo class.
    One more thing, the collection you must use for this should be TreeSet or any collection implementing SortedSet interface. I guess currently the results of your HQL query is being stored in Arraylist or something

    ii)Scenario 2 – Another scenario could be you are showing priorities in the dropdown or somewhere and your browser is shoing priorites in wrong order. In that case try Priority should implement comparable interface or your view layer should re-order

    Please not that neither of this scenario is related to my original blog post where you have set for a class. In this case you don’t have Set you have many to one relationship. One ToDo has only one priority. My blog post could be relevant had you had multiple priorities for one ToDo and you want to order them in some specific pattern.

    Hope this makes it clear. Let me know if you have any questions

    Reply
  5. Pingback: 2010 in review « Techspace

Leave a Reply

Your email address will not be published. Required fields are marked *