Showing posts with label Apache Commons. Show all posts
Showing posts with label Apache Commons. Show all posts

14 October 2012

Jakarta Commons Cookbook

This summer I finished reading the Jakarta Commons Cookbook. I bought it several years ago and it was sitting on my shelf since then. It survived the last "spring cleaning" when I gave away most of my books to the local Java user group, regardless if I had read them or not. I was not very enthusiastic about it, but felt the need to read it as it covers some of the most important Java libraries available today - the Apache Commons.

Jakarta Commons Cookbook coverReview
Timothy chose a way to organize the book around common tasks, so the book is in the usual cookbook/recipes style. To me the cookbook style is rather verbose and there are many examples on minute details which make the book suitable for beginners. If you are experienced and have used Apache Commons before, the book is a quick read.

Although the book covers a lot of material, it is just a glimpse of the whole Apache Commons universe. An extensive description of all the Commons projects is impossible so squeeze into a book. Still Timothy wrote about the most important projects like Lang, Collections, IO, Math as well as about some Apache top-level projects like Velocity and Lucene.

The cookbook has been published in 2004 and shows its age. A few Apache projects described in it have retired in the meantime and some parts of the shown APIs are deprecated. Still only a few changes were needed to compile all examples against the newest versions of Commons libraries. So the content in the book is still relevant.

Examples
I wanted to keep all the source code of the book as a quick reference and as a source to copy from. Unfortunately O'Reilly did not provide the code for download or I just did not find it. So I extracted the code samples and expected output from the eBook based on their markup. My script parsed the eBook and saved the Java examples into packages derived from the chapter names and classes derived from the section names. It added a main method and appended the expected output as a comment after the code. For example the extracted code for recipe 1.11 about finding items in an array looked like that
package com.discursive.jccook.supplements;

import org.apache.commons.lang.ArrayUtils;

public class FindingItemsInArray {

   public static void main(String[] args) {
      String[] stringArray = { "Red", "Orange", "Blue", "Brown", "Red" };

      boolean containsBlue = ArrayUtils.contains(stringArray, "Blue");
      int indexOfRed = ArrayUtils.indexOf(stringArray, "Red");
      int lastIndexOfRed = ArrayUtils.lastIndexOf(stringArray, "Red");

      System.out.println("Array contains 'Blue'? " + containsBlue);
      System.out.println("Index of 'Red'? " + indexOfRed);
      System.out.println("Last Index of 'Red'? " + lastIndexOfRed);
   }

   // Array contains 'Blue'? true
   // Index of 'Red'? 0
   // Last Index of 'Red'? 4

}
And then I went overboard with this little project. For a week I worked to have all examples compile and run. This was hard work because the examples contained many syntax errors like missing semicolons or typos in variable names. These mistakes were no problem for human readers, but the compiler complained a lot. For some examples I had to second guess the code not shown, e.g. used Java beans or factory methods which had been omitted for brevity. In hindsight it was a stupid idea, but after successfully cleaning up more than half of the examples, I just had to finish the work. Remember, I am a completionist ;-)

In the end I won and now all the examples are mine! I would like to share them with you, but O'Reilly does not allow that. The examples are distributed under some special "fair use" license that prohibits "reproducing a significant portion of the code".

24 February 2009

equals and hashCode Generation

Recently we discussed equals() and hashCode() implementations. A proper implementation is not trivial, as "father" Bloch showed us years ago. Back in 2004 I wrote a plugin for Eclipse 2 to generate these methods. (Unfortunately I never managed to publish it. I know I am weak ;-) My home grown solution would produce something like
public int hashCode() {
  long bits;
  int result = 17;
  result = 37 * result + (aBoolean ? 1231 : 1237);
  result = 37 * result + (int)
    ((bits = Double.doubleToLongBits(aDouble)) ^ (bits >> 32));
  result = 37 * result + (int) (aLong ^ (aLong >> 32));
  result = 37 * result + anInt;
  if (anObject != null) {
    result = 37 * result + anObject.hashCode();
  }
  if (anArray != null) {
    result = 37 * result + anArray.hashCode();
  }
  return result;
}
public boolean equals(Object obj) {
  if (this == obj) {
    return true;
  }
  else if (obj == null || getClass() != obj.getClass()) {
    return false;
  }
  final Homegrown o = (Homegrown) obj;
  return (aBoolean == o.aBoolean &&
         aDouble == o.aDouble &&
         aLong == o.aLong &&
         anInt == o.anInt &&
         (anObject == o.anObject ||
           (anObject != null && anObject.equals(o.anObject))) &&
         (anArray == o.anArray ||
           (anArray != null && anArray.equals(o.anArray))));
}
I know, I know the implementation for arrays is most likely not what you want. (Did I say that I am weak? :-) Since Java 5 one could use the java.util.Arrays class to fix it. Nevertheless, it served me well for some years. There are several other plugins for Eclipse, and Scott McMaster wrote about in 2006. Since version 3.3 (Europa) Eclipse can finally do it on its own:
public int hashCode() {
  final int prime = 31;
  int result = 1;
  result = prime * result + (aBoolean ? 1231 : 1237);
  long temp;
  temp = Double.doubleToLongBits(aDouble);
  result = prime * result + (int) (temp ^ (temp >>> 32));
  result = prime * result + (int) (aLong ^ (aLong >>> 32));
  result = prime * result + anInt;
  result = prime * result +
                   ((anObject == null) ? 0 : anObject.hashCode());
  result = prime * result + Arrays.hashCode(anArray);
  return result;
}
public boolean equals(Object obj) {
  if (this == obj) {
    return true;
  }
  if (obj == null) {
    return false;
  }
  if (getClass() != obj.getClass()) {
    return false;
  }
  final Eclipse33Java5 other = (Eclipse33Java5) obj;
  if (aBoolean != other.aBoolean) {
    return false;
  }
  if (Double.doubleToLongBits(aDouble) !=
      Double.doubleToLongBits(other.aDouble)) {
    return false;
  }
  if (aLong != other.aLong) {
    return false;
  }
  if (anInt != other.anInt) {
    return false;
  }
  if (anObject == null) {
    if (other.anObject != null) {
      return false;
    }
  }
  else if (!anObject.equals(other.anObject)) {
    return false;
  }
  if (!Arrays.equals(anArray, other.anArray)) {
    return false;
  }
  return true;
}
Using the ternary operator the hashCode method gets quite compact, but equals is a bit too verbose for my liking. IntelliJ IDEA could always generate these methods. IDEA 7.0 creates something like
public int hashCode() {
  int result;
  long temp;
  result = (aBoolean ? 1 : 0);
  temp = aDouble != +0.0d ? Double.doubleToLongBits(aDouble) : 0L;
  result = 31 * result + (int) (temp ^ (temp >>> 32));
  result = 31 * result + (int) (aLong ^ (aLong >>> 32));
  result = 31 * result + anInt;
  result = 31 * result +
                (anObject != null ? anObject.hashCode() : 0);
  result = 31 * result +
                (anArray != null ? Arrays.hashCode(anArray) : 0);
  return result;
}
public boolean equals(Object o) {
  if (this == o) {
    return true;
  }
  if (o == null || getClass() != o.getClass()) {
    return false;
  }
  Idea70Java5 original = (Idea70Java5) o;
  if (aBoolean != original.aBoolean) {
    return false;
  }
  if (Double.compare(original.aDouble, aDouble) != 0) {
    return false;
  }
  if (aLong != original.aLong) {
    return false;
  }
  if (anInt != original.anInt) {
    return false;
  }
  if (anObject != null ? !anObject.equals(original.anObject) :
                         original.anObject != null) {
    return false;
  }
  // Probably incorrect - comparing Object[] with Arrays.equals
  if (!Arrays.equals(anArray, original.anArray)) {
    return false;
  }
  return true;
}
Typical IDEA, with a little fix for +0.0/-0.0 and some warning concerning Arrays.equals, but else totally the same. In fact, all these implementations suck (including my own, which sucks most). All these result = prime * result ... and if ... return false; are definitely not DRY. I always favour Apache Commons Lang builders. A hand-coded solution using them would look like
public int hashCode() {
  return new HashCodeBuilder().
         append(aBoolean).
         append(aDouble).
         append(aLong).
         append(anInt).
         append(anObject).toHashCode();
}
public boolean equals(Object other) {
  if (this == other) {
    return true;
  }
  if (other == null || getClass() != other.getClass()) {
    return false;
  }
  ApacheCommons o = (ApacheCommons) other;
  return new EqualsBuilder().
         append(aBoolean, o.aBoolean).
         append(aDouble, o.aDouble).
         append(aLong, o.aLong).
         append(anInt, o.anInt).
         append(anObject, o.anObject).
         append(anArray, o.anArray).isEquals();
}
Well, that's much shorter, isn't it.