In this post, I rant about a patch the application needs to take care of when the framework is flawed. In this case, the framework happens to be Hibernate. The jar version used is : 3.6.6.Final
I was working on database query (removing sub-selects) optimizations and hence the need for refactoring the code. Below is the method which I came up with for the optimization.
Initially, I thought the CollectionUtils.isEmpty() method does not handle Collections.EMPTY_LIST.
Hence the method was changed to following:
Still the test cases failed! Also my assumption about CollectionUtils.isEmpty method not handling Collections.EMPTY_LIST was wrong
Try out:
So finally confirming that this is a flaw, did the following as a work-around, had to add in a try catch block and document this issue.
In this case, it seems to make sense for the method to return in null so that commons utils can check for its emptiness. At this point, I will consider this as a hibernate framework bug.
Found where in hibernate, it is being initialized:
In SessionImpl.java, method list(String query, QueryParameters queryParameters), line 1263:
CollectionHelper's EMPTY_LIST constant is initialized as follows:
From the screenshot above, note the size is 1 and List.isEmpty method checks on size == 0 which explains why these methods are failing! Below is the source code snippet of isEmpty method used in ArrayList.java
I was working on database query (removing sub-selects) optimizations and hence the need for refactoring the code. Below is the method which I came up with for the optimization.
protected long getMaxOrderingNumberForTrackingNo(String xoomTrackingNumber){ List<Long> orderNumberList = getHibernateTemplate().find(HQL_GET_MAX_ORDER_NUMBER_FOR_TRACKING_NUMBER, xoomTrackingNumber); long orderNumber=0; if (!CollectionUtils.isEmpty(orderNumberList)) { orderNumber=orderNumberList.get(0); } return orderNumber; }After making my changes, I quickly ran the unit and integration tests. These tests to my surprise failed and I started the quest for finding the culprit! It turns out the issue was in the getHibernateTemplate().find() method which returned an instantiated object with size equals 1 and all elements in the list to be null. The above code hence threw a Null pointer exception. Below debugger screenshot from Idea confirms this claim.

Initially, I thought the CollectionUtils.isEmpty() method does not handle Collections.EMPTY_LIST.
Hence the method was changed to following:
protected long getMaxOrderingNumberForTrackingNo(String xoomTrackingNumber){ List<Long> orderNumberList = getHibernateTemplate().find(HQL_GET_MAX_ORDER_NUMBER_FOR_TRACKING_NUMBER, xoomTrackingNumber); long orderNumber=0; if (orderNumberList!=null && !orderNumberList.isEmpty()) { orderNumber = orderNumberList.get(0); } return orderNumber; }
Still the test cases failed! Also my assumption about CollectionUtils.isEmpty method not handling Collections.EMPTY_LIST was wrong
Try out:
assertEquals(true, CollectionUtils.isEmpty(Collections.EMPTY_LIST));
So finally confirming that this is a flaw, did the following as a work-around, had to add in a try catch block and document this issue.
protected long getMaxOrderingNumberForTrackingNo(String xoomTrackingNumber){ List<Long> orderNumberList = getHibernateTemplate().find(HQL_GET_MAX_ORDER_NUMBER_FOR_TRACKING_NUMBER, xoomTrackingNumber); long orderNumber=0; //Need to encapsulate below statement in a try-catch. //because stupid hibernate instantiates the List object with size=1 and its elements are empty. //This makes condition check !org.apache.commons.collections.CollectionUtils.isEmpty on the Collection useless. try { orderNumber=orderNumberList.get(0); } catch (NullPointerException npe) { orderNumber = 0; logger.debug("order number list is empty."); } return orderNumber; }
In this case, it seems to make sense for the method to return in null so that commons utils can check for its emptiness. At this point, I will consider this as a hibernate framework bug.
Found where in hibernate, it is being initialized:
In SessionImpl.java, method list(String query, QueryParameters queryParameters), line 1263:
List results = CollectionHelper.EMPTY_LIST;
CollectionHelper's EMPTY_LIST constant is initialized as follows:
public static final List EMPTY_LIST = Collections.unmodifiableList( new ArrayList(0) );
From the screenshot above, note the size is 1 and List.isEmpty method checks on size == 0 which explains why these methods are failing! Below is the source code snippet of isEmpty method used in ArrayList.java
/** * Returns <tt>true</tt> if this list contains no elements. * @return <tt>true</tt> if this list contains no elements */ public boolean isEmpty() { return size == 0; }As expected, a quick unit test does also confirm that when a null element is added to List, the size is not 0. Following code fails on assertEquals.
List results = new ArrayList(); results.add(null); assertEquals(0, results.size());
No comments:
Post a Comment