Nothing causes me more distress as a developer than libraries which silently fails. Unfortunately this is exactly what I experienced a few weeks ago, although this time the culprit was not a shady library in alpha status, fetched from the back alley of the net, but the framework I based my work on.
I was doing work for a client, who had a set of commodity functions in their own “utilities” folder. Among these commodity functions was their own wrapper for Hashtable. Since none of the other projects utilized the Hashtable located in the public package (provided by Software AG), I decided to use the client’s. From this point on, whenever I mention Hashtable, I’m referring to the client’s version.
At some point in my work I was utilizing this Hashtable, which was populated with strings as both the keys and objects being mapped. The data in the Hashtable was later consumed by extracting the keys, and iterating over them in a loop.
1) Extracting the keys from the Hashtable.
2) Renaming the keys.
As seen in picture 1, which illustrates the pipeline at the step where the keys are extracted, the legend tells us it returns an Array of Strings. For clarity I decided to rename these keys (as seen in picture 2), by mapping them into another Array of Strings with a more proper name. Since the original Array was now redundant I also dropped it in the same mapping.
A call from a coworker of mine lead to a bizarre situation, apparently that particular piece of code was misbehaving. A calculation which was supposed to occur inside a loop (which iterated over the keys), was returning nothing but a default value, as if the calculation never happened.
I went back to the code and just could not see anything wrong with it. There was just no room for error, specially since no Exceptions were being caught. It took me far longer than I would like to admit to find the source of the erroneous behaviour, since I immediately proceeded to look for the culprit somewhere else.
3) The fetched keys, debugging mode.
4) The keys renamed (?!), pipeline while debugging.
Once my denial phase was over, I decided to finally debug that particular piece of code.
What I saw shocked me. The mapping step which was supposed to rename the keys silently failed. One detail from the debugging session caught my eye; as seen in picture 3 the keys were not an Array of Strings (as described in the pipeline legend), but an Array of Objects. Picture 4 shows what happens on the mapping (renaming) step, webMethods fails to cast the Object array into a String array without throwing an Exception.
Finding the culprit
5) Hashmap.keys (the clients implementation).
The source of the problem was found inside the Hashtable.keys function, which was a Java function. As seen in the picture 5, the result placed in the pipeline is created with Javas Set.toArray(). A quick search on the Java API tells us Set.toArray() returns an array of Objects, which were never casted to Strings, a miss by the developer who wrote the commodity function.
I would very much like to present a way to catch these kind of mapping-induced casting exceptions. Unfortunately my research has been fruitless. The only word of advice I can offer to you, my reader, is to never trust what the designer tells you should be in the pipeline, but instead double check it in debug mode.