Archive for December 3rd, 2007

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.