Archive for December, 2007

Fun with Collections and Reflection

Thursday, December 20th, 2007

I saw an interesting post on JavaBlogs about a HashSet puzzler. The problem posed was to find the original instance in a HashSet given a new instance that’s equal to the original but not the same instance, without iterating through the collection.

I’m not sure if mine is the most optimal solution, but I don’t see how to do it without reflection. HashSet is backed by a HashMap, which is inverted and uses the Set‘s entries as keys. So it’s simple to reflect in and get the Map, then reflect into that and get the corresponding Map.Entry (this is the approach used internally for the contains() check, but it’s not public), and the key of this entry is the original instance (I wrote it in JUnit style to take advantage of assertions):

import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertSame;
import static org.junit.Assert.assertTrue;

import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;

import org.junit.Test;

public class HashSetThing {

  @Test
  public void findOriginalInstance() throws NoSuchMethodException,
        NoSuchFieldException, IllegalAccessException, InvocationTargetException {

    HashSet<Thing> set = new HashSet<Thing>();
    set.add(new Thing(1));
    Thing thing2 = new Thing(2);
    set.add(thing2);
    set.add(new Thing(3));

    int instanceId = thing2._instanceId;

    HashMap<Thing, Object> map = reflectMap(set);

    Thing thingKey = new Thing(2);
    assertTrue("Contains should be true for not-same but equal instance",
        set.contains(thingKey));
    int thingKeyInstanceId = thingKey._instanceId;

    // why isn't there an assertNotEqual()?
    assertFalse("A new instance should have a unique instance id",
        instanceId == thingKeyInstanceId);

    Map.Entry<Thing, Object> entry = reflectEntry(map, thingKey);

    assertSame("The reflected instance should be the original",
        thing2, entry.getKey());
    assertTrue("The reflected instance should be the original",
        instanceId == entry.getKey()._instanceId);
  }

  @SuppressWarnings("unchecked")
  private Map.Entry<Thing, Object> reflectEntry(
      final HashMap<Thing, Object> map, final Thing thingKey)
      throws IllegalAccessException, InvocationTargetException,
                NoSuchMethodException {

    Method getEntryMethod = HashMap.class.getDeclaredMethod(
        "getEntry", Object.class);
    getEntryMethod.setAccessible(true);
    return (Map.Entry<Thing, Object>)getEntryMethod.invoke(map, thingKey);
  }

  @SuppressWarnings("unchecked")
  private HashMap<Thing, Object> reflectMap(HashSet<Thing> set)
      throws NoSuchFieldException, IllegalAccessException {

    Field mapField = HashSet.class.getDeclaredField("map");
    mapField.setAccessible(true);
    return (HashMap<Thing, Object>)mapField.get(set);
  }

  private static class Thing {

    private static int _counter;

    private int _i;
    private int _instanceId = _counter++;

    Thing(int i) {
      _i = i;
    }

    @Override
    public boolean equals(final Object other) {
      return ((Thing)other)._i == _i;
    }

    @Override
    public int hashCode() {
      return _i;
    }
  }
}

Hibernate anti-pattern #1 – hashCode/equals

Friday, December 14th, 2007

I’ve been doing a lot of Hibernate refactoring and performance tuning at work lately and have been spending time wrestling with some interesting anti-patterns that have crept into the code. One is our particularly bad hashCode/equals implementation which has some pretty frustrating implications1.

There’s a lengthy discussion here about various ways to implement hashCode and equals for Hibernate-managed entities. The post is great, and the discussion in the comments is also good.


The assumption is that the 1st-level cache (and also the 2nd-level cache if implemented) ensures that instances are unique. So our base entity class has a final equals method that uses the same logic as Object – two instances are equal if they’re the same (==). Likewise, hashCode is final and returns System.identityHashCode(this), the same value as if the method weren’t overridden (we have a base class between Object and our base entity class that necessitates explicitly reverting the behavior to that of Object):

@Override
public final boolean equals(final Object o) {
  return o == this;
}

@Override
public final int hashCode() {
  return System.identityHashCode(this);
}

This turns out to be overly simplistic and optimistic – it sure would be nice if that’s all it took, since there’s no equals/hashCode maintenance for new entity classes, no custom entity-specific logic to implement.

If you call Foo foo1 = session.get(Foo.class, 123) and Foo foo2 = session.get(Foo.class, 123), the 2nd call will return a reference to the cached 1st instance – there’s only 1 database hit. This is one of the primary benefits of using an ORM framework like Hibernate – there’s some overhead in its approach but optimizations like this will tend to far outweigh the costs as long as you’re using the framework appropriately.

So in this case, foo1 == foo2, and the equals method works fine.

But if you mix eagerly loaded entity instances and proxies, weird things happen. For example, suppose Bar has a lazy many-to-one reference to Foo (or a lazy-loaded collection of Foos); == will always be false even if the target entity of the proxy is the same as the non-proxy instance:

Foo foo = (Foo)session.get(Foo.class, 123);
Bar bar = (Bar)session.get(Bar.class, 321);

// always false since bar's Foo is a proxy
System.out.println(bar.getFoo() == foo);

// true for proper equals, always false for us
System.out.println(bar.getFoo().equals(foo));

The result is that data access implementation logic has bled up past the service tier and into the web tier; the web tier shouldn’t have to be aware of proxies but now has to be. If there’s any risk of comparing proxied and non-proxied instances, we have to use primary key equality to test instance equality instead of the much more natural equals.

What’s worse, we can’t mix persistent and new entity instances in collections that maintain uniqueness (Sets/Maps). A new instance can never be equal to a persistent instance even if every non-pk property value is the same, so we again have to deal with the data tier bleeding into other tiers and jump through hoops to get Set uniqueness and contains to work.


So here’s my proposed approach. Comparing two persistent instances using primary key is very efficient since primary keys are unique. This doesn’t help when comparing persistent and new instances though, and is inappropriate for usage in hashCode for the reasons discussed in the Hibernate post referenced above. Specifically, the hashCode will change from whatever you use before the instance is persisted to the primary key (or some value derived from it) afterwards. This will confuse hash-based collections since the instance will most likely be in the wrong hash bucket and cannot be found.

So equals compares primary keys if both are non-null. If either is null, then the class must define the fields that determine uniqueness and compare those.

hashCode always uses the same fields used in the equals comparison and never the primary key. If the entity is immutable or the fields that are used for the calculation are, then the hashCode could be cached to save the cost of unnecessary recalculation.

Most of this logic is in the base entity class, with abstract methods that force each entity class to define entity-specific behavior:

import java.io.Serializable;

import javax.persistence.Column;
import javax.persistence.MappedSuperclass;
import javax.persistence.Transient;
import javax.persistence.Version;

import org.apache.commons.lang.builder.HashCodeBuilder;
import org.hibernate.Hibernate;

/**
 * Abstract base class for entities.
 * @param <T> the type
 */
@MappedSuperclass
public abstract class BaseEntity<T extends BaseEntity<T>>
       extends ValueObject {

  private int _version;

  /**
   * Default.
   */
  protected BaseEntity() {
    // default
  }

  // optimistic locking version, private since only Hibernate uses these
  @Version @Column(name = "oplock", nullable = false)
  @SuppressWarnings("unused")
  private int getVersion() {
    return _version;
  }
  @SuppressWarnings("unused")
  private void setVersion(final int version) {
    _version = version;
  }

  /**
   * Utility method for <code>equals()</code> methods.
   * @param o1  one object
   * @param o2  another object
   * @return <code>true</code> if they're both <code>null</code> or both equal
   */
  protected boolean areEqual(final Object o1, final Object o2) {
    if (o1 == null) {
      if (o2 != null) {
        return false;
      }
    }
    else if (!o1.equals(o2)) {
      return false;
    }

    return true;
  }

  /**
   * Utility method for <code>equals()</code> methods.
   * @param s1  one string
   * @param s2  another string
   * @param ignoreCase if <code>false</code> do case-sensitive comparison
   * @return <code>true</code> if they're both <code>null</code> or both equal
   */
  protected boolean areEqual(
      final String s1,
      final String s2,
      final boolean ignoreCase) {
    // for use in custom equals() methods

    if (s1 == null && s2 == null) {
      return true;
    }

    if (s1 == null || s2 == null) {
      return false;
    }

    return ignoreCase ? s1.equalsIgnoreCase(s2) : s1.equals(s2);
  }

  /**
   * Utility method for <code>equals()</code> methods.
   * @param d1  one date
   * @param d2  another date
   * @return <code>true</code> if they're both <code>null</code> or both equal
   */
  protected boolean areEqual(
      final Date d1,
      final Date d2) {
    // for use in custom equals() methods

    if (d1 == null && d2 == null) {
      return true;
    }

    if (d1 == null || d2 == null) {
      return false;
    }

    return d1.getTime() == d2.getTime();
  }

  /**
   * Utility method for <code>equals()</code> methods.
   * @param f1  one float
   * @param f2  another float
   * @return <code>true</code> if they're equal
   */
  protected boolean areEqual(
      final float f1,
      final float f2) {
    // for use in custom equals() methods

    return Float.floatToIntBits(f1) == Float.floatToIntBits(f2);
  }

  /**
   * Utility method for <code>hashCode()</code> methods.
   * @param values  the values to use in calculation
   * @return  the hash code value
   */
  protected int calculateHashCode(final Object... values) {
    HashCodeBuilder builder = new HashCodeBuilder();
    for (Object value : values) {
      builder.append(value);
    }
    return builder.toHashCode();
  }

  /**
   * {@inheritDoc}
   */
  @Override
  public int hashCode() {
    return calculateHashCode(getHashCodeData());
  }

  /**
   * Get the data used to calculate hash code;
   * use getters not fields in case the instance is a proxy.
   * @return the data
   */
  @Transient
  protected abstract Object[] getHashCodeData();

  /**
   * Allows type-specific "this".
   * @return  this
   */
  @Transient
  protected abstract T getThis();

  /**
   * Get the primary key.
   * @return  the pk, or <code>null</code> if not set or if not supported
   */
  @Transient
  public abstract Serializable getPk();

  /**
   * {@inheritDoc}
   */
  @SuppressWarnings("unchecked")
  @Override
  public final boolean equals(final Object other) {
    if (this == other) {
      return true;
    }

    if (other == null
        || // looks into the target class of a proxy if necessary
        !Hibernate.getClass(other).equals(Hibernate.getClass(this))) {
      return false;
    }

    // if pks are both set, compare
    if (getPk() != null) {
      Serializable otherPk = ((BaseEntity)other).getPk();
      if (otherPk != null) {
        return getPk().equals(otherPk);
      }
    }

    return dataEquals((T)other);
  }

  /**
   * Compare data only; null, class, and pk have been checked.
   * @param other the other instance
   * @return <code>true</code> if equal
   */
  protected abstract boolean dataEquals(T other);
}

A concrete subclass must implement getHashCodeData and dataEquals, for example using the username property for a User class:

/**
 * {@inheritDoc}
 */
@Override
protected boolean dataEquals(final User other) {
  return areEqual(getUsername(), other.getUsername(), true);
}

/**
 * {@inheritDoc}
 */
@Override
@Transient
protected Object[] getHashCodeData() {
  return new Object[] { getUsername() };
}

This has worked well so far. It’s consistent, even when an instance transitions from new to persistent and its primary key becomes non-null. The data used for hashCode calculation never changes, so that’s consistent. The data for equals does change, but it stays consistent – comparing two persistent entities or mixing persistent and new returns the correct result in all cases since non-pk data is used for comparison.

Note that equals is final but hashCode isn’t to allow caching.


My original implementation of this was way too simplistic, just using the Jakarta Commons Lang reflection methods that I described here. This approach is great for regular value objects and DTOs, but is way too expensive for Hibernate entities since every field is used, even collections and the primary key. Lazy-loaded collections will be retrieved from the database to calculate hashCode and equals, which is almost always inappropriate.

So I worked on a slightly smarter approach that skipped the primary key and collections but still used reflection for the rest of the fields. This is still too expensive, and breaks when using proxies since the fields will be null – the getter methods delegate to the data that’s in the proxy’s target instance.

Eventually I ended up with the current implementation, which has lasted for a while with no issues.




  1. Ironically, The Decidertm was asked recently why this choice was made and he couldn’t defend it, but was sure that there was a good reason for it and wasn’t willing to change anything even given the implications of the decision.[back]

An Updated JUnit AllTests Suite

Thursday, December 13th, 2007

I upgraded to JUnit 4.4 and my AllTests utility class that runs all tests in a project broke because I’d been using internal APIs (org.junit.internal) that were refactored between 4.1 and 4.4. It took some digging into their source code but I’ve got it fixed.

Of course Ant has great support for JUnit from the command line – I use this in Eclipse to allow quick “Run As JUnit Test” support, set breakpoints, take advantage of the IDE’s UI that monitors progress, etc.

This is an extension of their @RunWith/@SuiteClasses annotation facility that auto-discovers all test classes rather than specifying a list of class names. A hard-coded list is a pain to maintain and for a large project would be enormous (assuming decent test coverage that is …).

The old code had a static inner class that extended org.junit.internal.runners.TestClassRunner and passed in the results of a directory scan of *Test.class files that aren’t abstract, rather than using the value of the @SuiteClasses annotation. The current implementation is very similar – it extends org.junit.runners.Suite instead.

One interesting feature of this approach is that you have a hook into the start of the test suite, and can also attach event listeners to be notified of start/stop events, failures, etc. This is important because test classes no longer extend a JUnit class – annotations are used instead. So for example it’s no longer possible for to access the name of the currently running test method in a generic fashion.

You could add code to each method but this is brittle and clutters the code. Instead of overriding setUp we use @Before annotatons on one or more methods, but these aren’t the test methods and are invoked using reflection so there’s no hook into the test method that’s about to be run. So in the code below I add an event listener to log the start and end of each test method. This was useful recently when I was chasing down a Collection leak that caused tests to hang once the connection pool was maxed out.

To use this, just right-click it in the class tree in Eclipse and click “Run As JUnit Test”.

import java.io.File;
import java.io.UnsupportedEncodingException;
import java.lang.reflect.Modifier;
import java.net.URLDecoder;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;

import org.apache.log4j.Logger;
import org.junit.internal.runners.InitializationError;
import org.junit.runner.Description;
import org.junit.runner.RunWith;
import org.junit.runner.notification.RunListener;
import org.junit.runner.notification.RunNotifier;
import org.junit.runners.Suite;

/**
 * Discovers all JUnit tests and runs them in a suite.
 */
@RunWith(AllTests.AllTestsRunner.class)
public final class AllTests {

  private static final File CLASSES_DIR = findClassesDir();

  private AllTests() {
    // static only
  }

  /**
   * Finds and runs tests.
   */
  public static class AllTestsRunner extends Suite {

    private final Logger _log = Logger.getLogger(getClass());

    /**
     * Constructor.
     *
     * @param clazz  the suite class - <code>AllTests</code>
     * @throws InitializationError  if there's a problem
     */
    public AllTestsRunner(final Class<?> clazz) throws InitializationError {
      super(clazz, findClasses());
    }

    /**
     * {@inheritDoc}
     * @see org.junit.runners.Suite#run(org.junit.runner.notification.RunNotifier)
     */
    @Override
    public void run(final RunNotifier notifier) {
      initializeBeforeTests();

      notifier.addListener(new RunListener() {
        @Override
        public void testStarted(final Description description) {
          if (_log.isTraceEnabled()) {
            _log.trace("Before test " + description.getDisplayName());
          }
        }

        @Override
        public void testFinished(final Description description) {
          if (_log.isTraceEnabled()) {
            _log.trace("After test " + description.getDisplayName());
          }
        }
      });

      super.run(notifier);
    }

    private static Class<?>[] findClasses() {
      List<File> classFiles = new ArrayList<File>();
      findClasses(classFiles, CLASSES_DIR);
      List<Class<?>> classes = convertToClasses(classFiles, CLASSES_DIR);
      return classes.toArray(new Class[classes.size()]);
    }

    private static void initializeBeforeTests() {
      // do one-time initialization here
    }

    private static List<Class<?>> convertToClasses(
        final List<File> classFiles, final File classesDir) {

      List<Class<?>> classes = new ArrayList<Class<?>>();
      for (File file : classFiles) {
        if (!file.getName().endsWith("Test.class")) {
          continue;
        }
        String name = file.getPath().substring(classesDir.getPath().length() + 1)
          .replace('/', '.')
          .replace('\\', '.');
        name = name.substring(0, name.length() - 6);
        Class<?> c;
        try {
          c = Class.forName(name);
        }
        catch (ClassNotFoundException e) {
          throw new AssertionError(e);
        }
        if (!Modifier.isAbstract(c.getModifiers())) {
          classes.add(c);
        }
      }

      // sort so we have the same order as Ant
      Collections.sort(classes, new Comparator<Class<?>>() {
        public int compare(final Class<?> c1, final Class<?> c2) {
          return c1.getName().compareTo(c2.getName());
        }
      });

      return classes;
    }

    private static void findClasses(final List<File> classFiles, final File dir) {
      for (File file : dir.listFiles()) {
        if (file.isDirectory()) {
          findClasses(classFiles, file);
        }
        else if (file.getName().toLowerCase().endsWith(".class")) {
          classFiles.add(file);
        }
      }
    }
  }

  private static File findClassesDir() {
    try {
      String path = AllTests.class.getProtectionDomain()
        .getCodeSource().getLocation().getFile();
      return new File(URLDecoder.decode(path, "UTF-8"));
    }
    catch (UnsupportedEncodingException impossible) {
      // using default encoding, has to exist
      throw new AssertionError(impossible);
    }
  }
}

Don’t change the parameter value in a Hibernate setter

Tuesday, December 04th, 2007

A while back a co-worker asked for some help with a Hibernate problem – he thought he’d found a serious bug. He was an experienced database architect but new to Hibernate, so he’d written some basic test code. It was trivial – just reading objects from various HQL queries and displaying them to the console. The weird thing was, after reading an object the ‘name’ property was always null (even though the column wasn’t – the sample data had values for every column) and weirder still after reading a row, the column became null.

I looked at his mapping files and his environment but everything seemed fine. Then I noticed that his setter method looked something like this:

public void setName(String naem) {
  this.name = name;
}

So it was a classic typo – the parameter was misspelled, so the setter was just setting the field to itself (Eclipse has a check for this and I find it’s best to flag it as an error). Since the state at flush time was different from the original values that Hibernate caches for dirty detection, Hibernate dutifully pushed the “change” to the database.

I was reminded of this today because of a similar bug that was introduced last week. One of the developers was seeing an unexpected optimistic locking exception in an entity that wasn’t being updated concurrently – in fact there are no public setters in the class.

Since the class is effectively immutable, I added the mutable='false' attribute to the class element in the mapping file, removed the non-public setters only called by Hibernate during instantiation and switched to field access. I also removed the optimistic locking <version> element since there’s no need to check for concurrent updates, and the bug went away.

I felt guilty checking that in though since it felt like fixing the symptom and not the real problem – just setting up someone else the next time something similar triggered the root bug. Luckily I realized the real issue a little while later.

We have a custom type for storing dates independent of timezone (it converts to GMT on insert and we adjust for the current time zone on read) and it was implemented using java.sql.Timestamp. Apparently this caused problems when comparing equality with java.util.Date, so the custom type’s nullSafeGet was changed to read the database timestamp and convert to a java.util.Date. As with the earlier example – an apparent change of the value (Timestamp‘s equals method isn’t symmetric with Date‘s) caused Hibernate to detect the change and push the update to the database. Two users were concurrently reading the object and Hibernate was pushing both changes to the database, hence the optimistic locking exception.

So I’ll keep the entity class immutable – it matches the actual usage – but will fix the custom type to do the right thing.

The first time I burned myself like this was with mapped collections. I had a mapped List on an entity and when I wrote the unit tests for the DAO tier, I mistakenly created test SQL scripts with index column values that started at 1 instead of 0. So I was seeing that the lists always had N+1 elements, and the first was always null. I spent way too long banging on this and finally put in a hack where I created a copy of the List in the setter (a new ArrayList), keeping only non-null elements.

This was a side project I was working on from home, and I ended up getting too busy and leaving the project. I recently started working on it again after being away for a year, and was able to fix a lot of dumb mistakes I’d made (this was my first time using Spring and Hibernate a real project).

The folks on the team mentioned that the SQL logs showed lots of deletes and inserts every time the entity was loaded from the database, resulting in significant slowness, so they wanted me to take a look. It didn’t take long to realize that it was due to replacing the managed PersistentList with a new list. Since it’s a new instance, Hibernate doesn’t detect specific changes so it deletes all of the old rows and inserts all the new, even in a case like this where there was no net change. In the production code, there were no nulls and in fact no actual changes, so no actions were necessary at all. This realization lead to the discovery of the unit test bug, and I was able to remove the hack and just keep the List that Hibernate passed in the setter.

More fun with Generics – Class.cast()

Tuesday, December 04th, 2007

Continuing the discussion from here and here.

We’ve been making extensive use of generics at work and in the process have discovered a bug in the 1.6 JDK (more on that later). The problem is that we can’t cast to the actual type of some generic instance variables, and also can’t use instanceof. The annoying thing is that it works fine in Eclipse – it’s only an issue in Sun’s JDK, so it fails during a command-line compile. Also it works fine in 1.5, so being one of the few on the team to use 1.6, I end up needing to fix things since it doesn’t affect the rest of the team or the continuous build.

We’ve worked around it by replacing casts with the Class.cast() method:

public T cast(Object obj) {
   if (obj != null && !isInstance(obj))
      throw new ClassCastException();
   return (T) obj;
}

and replace instanceof checks with Class.isAssignableFrom().

But take a look at the cast method. If we were to take the optimistic approach assuming no improper usage and remove the null and isInstance checks, then the method becomes

public T cast(Object obj) {
   return (T) obj;
}

Huh. That’s odd – we’re just replacing a cast with a cast.

So I wrote a simple test method to see why this works:

@SuppressWarnings("unchecked")
public static <T> T cast(@SuppressWarnings("unused") final Class<T> clazz,
       final Object o) {
  return (T)o;
}

(It turns out that the clazz parameter isn’t necessary, but at first I thought it was to justify the T type.)

I wrote some test code:

public static void main(final String... args) {
  List<String> list = new ArrayList<String>();

  ArrayList<String> c1 = cast(ArrayList.class, list);
  System.out.println("c1: " + c1.getClass().getName());

  Object c2 = cast(String.class, list);
  System.out.println("c2: " + c2.getClass().getName());

  String c3 = cast(String.class, list);
  System.out.println("c3: " + c3.getClass().getName());
}

and was surprised that the cast using String.class compiled – I can cast to any class. Of course it fails at runtime – the cast isn’t legal, so the output is

c1: java.util.ArrayList
c2: java.util.ArrayList
Exception in thread "main" java.lang.ClassCastException:
 java.util.ArrayList cannot be cast to java.lang.String

Looking at the decompiled code makes it clear what’s going on – it’s just erasure. The type of T is only used by the compiler to ensure (to the extent possible) that the code is valid, but the runtime type still has to be valid:

public static Object cast(Class clazz, Object o) {
  return o;
}

public static void main(String[] args) {
  List list = new ArrayList();
  ArrayList c1 = (ArrayList)cast(ArrayList.class, list);
  System.out.println((new StringBuilder("c1: ")).append(
         c1.getClass().getName()).toString());
  Object c2 = cast(String.class, list);
  System.out.println((new StringBuilder("c2: ")).append(
         c2.getClass().getName()).toString());
  String c3 = (String)cast(String.class, list);
  System.out.println((new StringBuilder("c3: ")).append(
         c3.getClass().getName()).toString());
}

Of course the Class parameter isn’t necessary:

@SuppressWarnings("unchecked")
public static <T> T cast(final Object o) {
  return (T)o;
}

public static void main(final String... args) {
  List<String> list = new ArrayList<String>();

  ArrayList<String> c1 = cast(list);
  System.out.println("c1: " + c1.getClass().getName());

  Object c2 = cast(list);
  System.out.println("c2: " + c2.getClass().getName());

  String c3 = cast(list);
  System.out.println("c3: " + c3.getClass().getName());
}

would have worked fine.

More generics hacks

Monday, December 03rd, 2007

Continuing on the generics discussion here, I’ve been using a pattern that I’ve seen discussed in the blogosphere to reduce redundancy in creating collections, e.g. some utility methods on a CollectionUtils class:

public static <T> ArrayList<T> newArrayList() {
  return new ArrayList<T>();
}

public static <T> HashSet<T> newHashSet() {
  return new HashSet<T>();
}

public static <K, V> HashMap<K, V> newHashMap() {
  return new HashMap<K, V>();
}

This eliminates the redundancy of specifying the type(s) twice:

List<VerboseTypeName> list = new ArrayList<VerboseTypeName>();

Map<VerboseKeyName, VerboseValueName> map =
        new HashMap<VerboseKeyName, VerboseValueName>();

becomes

List<VerboseTypeName> list = newArrayList();

Map<VerboseKeyName, VerboseValueName> map = newHashMap();

assuming we use static imports for the utility methods.

But Groovy and other scripting languages are making me realize how unnecessarily verbose Java is. For example, in Groovy I can create a List and initialize its elements in one line:

def numbers = [1, 1, 2, 3, 5, 8, 13, 21];

I recently realized that I can use VarArgs and amend the utility methods to take optional initializing values:

public static <T> ArrayList<T> newArrayList(final T... elements) {
  return new ArrayList<T>(Arrays.asList(elements));
}

public static <T> HashSet<T> newHashSet(final T... elements) {
  return new HashSet<T>(Arrays.asList(elements));
}

and then

List<String> strings = new ArrayList<String>();
strings.add("foo");
strings.add("bar");
strings.add("baz");

becomes

List<String> strings = newArrayList("foo", "bar", "baz");

Of course this isn’t new – for example Hibernate Shards has a similar implementation but with the various methods split by interface.

Avoiding cast with a generics hack

Monday, December 03rd, 2007

Say you have a method that returns Object that you need to cast to the actual type. Collection classes have always worked with Objects and required casting, but retrofitting with generics helped reduce this. Methods can be generic too, and we can use a quasi-hack to pre-cast the Object return values. The more I work with scripting languages, the more I realize how verbose Java is, and techniques like this help a lot with reduction of repetition and cruft.

One example is the case in a Spring (or other DI framework) app where you don’t have control over the creation of instances that need Spring-managed resources and cannot use DI (for example JSP custom tags, which are created by the container). In this case we need to pull resources instead of having them pushed.

So we create a utility class that has access to the ApplicationContext, e.g.:

import org.springframework.beans.factory.annotation.Required;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;

public final class SpringContext implements ApplicationContextAware {

  private static final SpringContext INSTANCE = new SpringContext();

  private ApplicationContext context;

  private SpringContext() {
    // singleton
  }

  public static SpringContext instance() {
    return INSTANCE;
  }

  public Object getBean(final String name) {
    return context.getBean(name);
  }

  @Required
  public void setApplicationContext(final ApplicationContext c) {
    context = c;
  }
}

and map it in Spring using:

<bean class='com.myco.myapp.spring.SpringContext' factory-method='instance' />

Usage of getBean requires a cast to the actual type, e.g.:

UserDAO dao = (UserDAO)SpringContext.instance().getBean("userDao");

But we’ve already specified that the type is UserDAO, so we can amend getBean to be generic:

@SuppressWarnings("unchecked")
public <T> T getBean(final String name) {
  return (T)context.getBean(name);
}

and then the client code becomes:

UserDAO dao = SpringContext.instance().getBean("userDao");

This is also useful for methods that return a base class. For example, suppose you have a hierarchy of user classes; an abstract User base class with concrete subclasses Subscriber and Admin. If you have this method in UserDAO:

User findUserByUsername(String username);

then usage looks like:

Admin admin = (Admin)dao.findUserByUsername("bob");

As before, we’ve specified Admin twice, so we can change the method to:

<T extends User> T findUserByUsername(String username);

and this simplifies the calling code to:

Admin admin = dao.findUserByUsername("bob");

Of course this is just syntactic sugar – if the cast is invalid it will still fail.

Creative Commons License
This work is licensed under a Creative Commons Attribution 3.0 License.