Kevin's Blog

IT, Java, Web, Ubuntu

Category: API Design

Java Generics: Generics in Real Life Programming

It is surprising to see that there are still many people who do not use generics even when they are using JDK 5 or higher. I can often see it especially when I teach some Java programming subjects at uni. Generics can be very useful and I use it a lot in my libraries and projects. So I’d like to talk about generics but not a basic knowledge of it. I will talk about Java generics in real life programming and how it can be useful as well as some unusual cases may occur and annoy you. I am also going to explain some common cases of generics usage in my next post that I have plan to write soon (hopefully). Then I’m going to write about more complex cases in the sense that it’s complex when it’s designed but rather simple when it’s used, and it’s also more practical. It means I’ll probably write two more posts about generics so stay tuned if you’re interested.

Before I start to talk about usefulness of it, let’s start with problems that can happen if you don’t use generics when using generified types.
If your code looks like this, you’re making your code error-prone.

List list = new ArrayList();

As it discards all the generic type information in the class. To see what exactly happens, better take a look at some example.

If you have type like

public class SomeType<T>
{
  public <E> void test(final Collection<E> collection)
  {
    for (final E object : collection)
    {
      System.out.println("E: " + object);
    }
  }

  public void test(final Set<T> set)
  {
    for (final T t : set)
    {
      System.out.println("T from set: " + t);
    }
  }

  public void test(final List<Integer> integerList)
  {
    int result = 0;
    for (final Integer integer : integerList)
    {
      result += integer.intValue();
    }
    System.out.println("result: " + result);
  }
}

and execute code like

final SomeType someType = new SomeType();
final List<String> list = Arrays.asList("some", "test", "value");
someType.test(list);

Then you will get ClassCastException saying “java.lang.String cannot be cast to java.lang.Integer” in runtime but no errors in compile-time. Why? because it uses public void test(final List<Integer> integerList) method instead of public <E> void test(final Collection<E> collection). But why does it use the one taking List of Integer instead of the one with the Collection of some type E when the passed parameter is a List of String which is a Collection of some type E, in this case, String? The reason is that SomeType is generified but when using it, no generics are used. If generified type is used without generic type info specified, the Java compiler makes it like the old type in JDK prior to 5.0 which doesn’t have generics.

Thus, the methods above all become like

  public void test(final Collection collection)

  public void test(final Set set)

  public void test(final List integerList)

So the closest type matched with a List of String is a List and that’s why public void test(final List<Integer> integerList) is called. But the method, public <E> void test(final Collection<E> collection), has nothing to do with the generic type specified in the class SomeType<T>. It’s just a generic method and the E has nothing to do with the T. Yeah, but if the type is generified, yet no generic type is specified when it is used, all the generics info including the ones in the generic methods is gone.

To solve the problem, you just need to specify the generic type. In the case above, you can even use just ‘?‘ (wildcard) since you’re not using the generic type specified in the class but the generic method, public <E> void test(final Collection<E> collection).

final SomeType<?> someType = new SomeType<Object>();
final List<String> list = Arrays.asList("some", "test", "value");
someType.test(list);

Now, with generics, you don’t have the problem you had before without generics.

So, it’s clear why you should use generics when using generified types. What I just explained is actually not new but well known to most Java programmers. Now, let’s talk about some benefits from using generics.

You can avoid a problem that you have with arrays if you use generics. Arrays of reference types in Java are covariant so you may have a problem like this.

  final Integer[] integerArray = { 1, 2, 3, 4, 5 };
  final Object[] objectArray = integerArray;
  objectArray[0] = "test";

There is no compile-time error, yet running this code results in java.lang.ArrayStoreException: java.lang.String when objectArray[0] = "test"; is executed.

Unlike arrays, generics are invariant, so if you use generics like,

  final List<Integer> integerList = Arrays.asList(1, 2, 3, 4, 5);
  final List<Object> objectList = integerList;

You get a compile-time error.

  final List<Object> objectList = (List<Integer>) integerList; // compile-time error

Even this one causes the compile-time error too since a List of Integer is not a subtype of List of Object (In arrays, an Integer array is a subtype of Object array).

On the other hand, you may need to cast it although it happens very occasionally. Here is an example taken from one of my libraries.
In KommonLee ASM, there is a visitor class, MethodAnalysisClassVisitor.

public class MethodAnalysisClassVisitor<T, M extends Member> extends EmptyVisitor
{
  private final MemberCollector<M> memberCollector;
  private final Class<T> theClass;
  private final Map<M, String[]> memberToParameterNamesMap;

  public MethodAnalysisClassVisitor(final MemberCollector<M> memberCollector, final Class<T> theClass,
      final Map<M, String[]> memberToParameterNamesMap)
  {
    this.memberCollector = memberCollector;
    this.theClass = theClass;
    this.memberToParameterNamesMap = memberToParameterNamesMap;
  }
  // Remainder omitted...
}

This visitor collects all the methods / constructors and their parameter names. Why do I need this kind of tool? It’s because I needed to get the parameter names of constructors in a class for one of my libraries, JSON Statham, but there was no easy way to get the parameter names of methods or constructors in Java. Reflection in Java certainly doesn’t have this convenience which is, I believe, an integral part for library / framework development although it would be depending on what sort of library it is. So I had to use ASM to get the method parameter names. I was shocked when I first discovered it. Anyway, back to the original topic again, the visitor is used by AsmMethodAndConstructorAnalyser.

public class AsmMethodAndConstructorAnalyser implements MethodAndConstructorAnalyser
{
  // ...

  @Override
  public <T> Map<Constructor<T>, String[]> findConstructorsWithParameterNames(final Class<T> theClass)
      throws IllegalArgumentException
  {
    final Map<Constructor<T>, String[]> constructorToParameterNamesMap = new LinkedHashMap<Constructor<T>, String[]>();

    @SuppressWarnings({ "cast", "unchecked", "rawtypes" })
    final Map<Constructor<?>, String[]> map = (Map<Constructor<?>, String[]>) ((Map) constructorToParameterNamesMap);

    getClassReader(theClass).accept(
        new MethodAnalysisClassVisitor<T, Constructor<?>>(constructorCollector, theClass, map), 0);
    return constructorToParameterNamesMap;
  }
  // ...
}

I know that the type M defined in the MethodAnalysisClassVisitor is Constructor<T> in this particular method as I’m passing Class<T> and want to collect all the constructors in it which are all Constructor<T>, yet the Java compiler can’t figure it out so I get a compile-time error if I just do

    final Map<Constructor<T>, String[]> constructorToParameterNamesMap = new LinkedHashMap<Constructor<T>, String[]>();

    getClassReader(theClass).accept(
        new MethodAnalysisClassVisitor<T, Constructor<?>>(constructorCollector, theClass, constructorToParameterNamesMap), 0);

Therefore, what I did was:
first, cast Map<Constructor<T>, String[]> constructorToParameterNamesMap to a raw type Map then it will lose all the generic type info.
second, I can cast it to Map of any key value pair since the Java compiler erases all the generic types when it’s compiled.
finally, I ended up having the following lines of code. I had to add @SuppressWarnings({ "cast", "unchecked", "rawtypes" }) to make the compiler happy. I could do it because I know the constructors stored in the Map are all Constructors of T type.

  @SuppressWarnings({ "cast", "unchecked", "rawtypes" })
  final Map<Constructor<?>, String[]> map = (Map<Constructor<?>, String[]>) ((Map) constructorToParameterNamesMap);

  getClassReader(theClass).accept(
      new MethodAnalysisClassVisitor<T, Constructor<?>>(constructorCollector, theClass, map), 0);

This doesn’t happen often though. So most of the time, you don’t need to do it and can enjoy type safety that generics offer.

Along with the benefit I mentioned above with the case compared with arrays, generics offer convenience of postponing specifying the type information until it is used with compile-time type safety. One example that everyone knows is Java’s collections framework. The programmer of collections didn’t know what types would be stored in the collections when it was created, thus when it came out, it stored just an object type as there were no generics. This is the part where Java loses static typing although it’s a static type language. However, after introduction of generics, the users of collections can have compile-time type safety. Ironically, the collections are one of the most popular examples of how generics can be useful, yet according to Neal Gafter, it’s one of the most important reasons why generics are implemented using type erasure and wild-card, which make generics more complex. If you’re interested in it, you’d better watch his presentation.

Although Generics were introduced in JDK 5.0, the GJ compiler that can handle generics were introduced much earlier in JDK 1.3 but it was disabled according to the Java language specification.

Generics give us compile-time type safety but it’s compile-time only because, as I just mentioned, it does type erasure which means the compiler removes all the generic type information when it compiles, and that’s why we can’t create a generic type object or array like.

T t = new T();
T[] t = new T[10];

This is impossible in Java and that’s why you don’t see method like E[] toArray() but Object[] toArray() and <T> T[] toArray(T[] a) in the Collection class and its sub classes. You can create an array of E type if an instance of array of E is given as a parameter value. For example,

public <E> E[] copyArray(final E[] array)
{
  @SuppressWarnings("unchecked")
  final E[] copiedArray = (E[]) Array
                          .newInstance(array
                                        .getClass()
                                        .getComponentType(),
                                      array.length);
  System.arraycopy(array, 0, copiedArray, 0, array.length);
  return copiedArray;
}

It takes an array of E object then creates a new array object of E then copies all the elements in the given one to the new one then returns it.

How is it possible? It’s possible because now I’m dealing with an ‘array object’ of E type not the generic type E directly so I can get the class of the array object in order to take the component type of the element stored in the array. So first, get the class of E[] ‘object’ (not class) which is a parameter value and given in runtime, then I can get the component type of it. However, the following case is impossible.

public <E, NE, F extends Function1<E, NE>> NE[] apply(final F function, final E[] source)
{
  final List<NE> list = new ArrayList<NE>();
  for (final E element : source)
  {
    list.add(function.apply(element));
  }
  @SuppressWarnings("unchecked")
  final NE[] resultArray = list.toArray(
      (NE[]) Array
          .newInstance(NE[].class // <- compile time error here: Illegal class literal for the type parameter NE!!!
                      .getComponentType(),
                       list.size()));
  return resultArray;
}

Because there is no such thing as an NE[] ‘class’ (not object), there is no way to get the class. When it’s compiled, NE[] becomes an Object array (Object[]).

I used to hate this type erasure as I had some issues when I developed my libraries. However, I do not anymore. It’s not just because of the reason mentioned here. I have mine and will explain it later in this post.

So let me talk about why we use generics again. We use it to have compile-time type safety without having to decide the type when designing the API. One example can be found in my old post about Easier and Better Way to Use JDBC. Simply, it makes use of callback function object much more useful.

Let’s say you want to map a type stored in a List to some other type. If you don’t use generics, you probably need to make a method for each mapped type like

public List<BigDecimal> takePricesOf(List<Product> list)
{
  List<BigDecimal> newList = new ArrayList<BigDecimal>();
  for (Product product : list)
  {
    newList.add(product.getPrice());
  }
  return newList;
}

public List<DiscountedProduct> toDiscountedProducts(int discountRate, List<Product> list)
{
  List<DiscountedProduct> newList = new ArrayList<DiscountedProduct>();
  for (Product product : list)
  {
    newList.add(new DiscountedProduct(product, discountRate));
  }
  return newList;
}

// and more...

(OK, here are actually generics used but it’s only for using List).

It can become one reusable method with some callback function object like.

public interface Mapper
{
  Object map(Object input);
}
public List<Object> mapWithoutGenerics(Mapper mapperWithoutGenerics, List<?> list) // <- this cannot be List<Object> since you want to pass a List of any type not just List<Object>.
{
  List<Object> newList = new ArrayList<Object>();
  for (Object object : list)
  {
    newList.add(mapperWithoutGenerics.map(object));
  }
  return newList;
}

When you use it.

List<Object> productPriceList = mapWithoutGenerics(new Mapper() {
  public Object map(Object input)
  {
    Product product = (Product) input;
    return product.getPrice();
  }
}, productList);

Now, you don’t have compile-time type safety anymore so you may pass a List of any type.
So the following code doesn’t cause any compile-time error but the runtime exception that is java.lang.ClassCastException.

List<Object> productPriceList = mapWithoutGenerics(new Mapper() {
  public Object map(Object input)
  {
    Product product = (Product) input;
    return product.getPrice();
  }
}, Arrays.asList("Some", "String", "List"));

 

It can surely become much better with generics.

public interface Function1<T, R>
{
  R apply(T input);
}
public <T, R, F extends Function1<T, R>> List<R> map(F mapper, List<T> list)
{
  final List<R> newList = new ArrayList<R>();
  for (final T t : list)
  {
    newList.add(mapper.apply(t));
  }
  return newList;
}

Then when you use it.

final List<BigDecimal> productPriceList = map(new Function1<Product, BigDecimal>() {
  @Override
  public BigDecimal apply(final Product product)
  {
    return product.getPrice();
  }
}, productList);

Or the function object can be reused.

private static final Function1<Product, BigDecimal> PRODUCT_TO_PRICE_MAPPER = new Function1<Product, BigDecimal>() {
  @Override
  public BigDecimal apply(final Product product)
  {
    return product.getPrice();
  }
};

//...

final List<BigDecimal> productPriceList        = map(PRODUCT_TO_PRICE_MAPPER, productList);
final List<BigDecimal> anotherProductPriceList = map(PRODUCT_TO_PRICE_MAPPER, anotherProductList);

The other method that is toDiscountedProducts() can be done with this generic map method and closure.

final int discountRate = 15;

final List<DiscountedProduct> discountedProductList = map(new Function1<Product, DiscountedProduct>() {
  @Override
  public DiscountedProduct apply(final Product product)
  {
    return new DiscountedProduct(product, discountRate);
  }
}, productList);
Although Java doesn’t really have closure, the Function1 above is used as a closure because it’s accessing a non-local variable, and in almost all the cases when people say that Java doesn’t have closure, they actually mean a way to support first-class functions (e.g. lambda expression to support first-class functions in Java).

Speaking of generics used for collections, I should point out that it would have been much more useful, if the collections had got methods like select (or filter), map, etc.

So if you had got a List of Integer and wanted to get all the positive ones, you would have done like.

List<Integer> positiveIntegerList = integerList.select(new Condition1<Integer>() {
  public boolean isMet(Integer integer)
  {
    return 0 < integer.intValue();
  }
});

Or getting all the prices from the List of Product object as I already showed. Unfortunately Java’s Collections don’t have those methods. Well, my collection library has it, but it’s incomplete and not so compatible with existing code using Java’s collections although it has a way to convert from and to Java ones. So to keep using Java’s collections, I made some helper methods to achieve the goal which is having one generic method to apply different kinds of functions to all the elements in the collections. By the way, why do I bother about it? Can’t I just use for or foreach loop? Sure, I can. So why? With the generic methods mentioned above and function objects, I can focus on the actual problems. For instance, to get all the prices from the list of Product, my concern should be getting the price of each Product not how to use for or foreach loop.

Here, I need to worry about using foreach and creating ArrayList.

List<BigDecimal> productPriceList = new ArrayList<BigDecimal>();
for (Product product : productList)
{
  productPriceList.add(product.getPrice());
}

With the generic one (if there were one), I wouldn’t.

List<BigDecimal> productPriceList = productList.map(new Function1<Product, BigDecimal>() {
  public BigDecimal apply(Product product)
  {
    return product.getPrice(); // <- here I'm focusing on getting the price.
  }
});

Since Java doesn’t support first-class function, the syntax is not so pleasant. However, JDK 8 will have lambda expression to support it so when it comes out, it can probably be like.

List<BigDecimal> productPriceList = productList.map((product) -> product.getPrice());
// It hasn't been finalised yet so the syntax can be different.

Anyway, Java collections still don’t have those methods so, as I said already, I made the ones for the collections. So let me talk about one of these that is Selector. What Selector does is checking all the elements in a collection and takes only the ones that meet the given Condition. I wanted to have only one Selector that can easily deal with all the classes extends Collection instead of having one for each (e.g. ListToArrayListSelector, ListToHashSetSetSelector, SetToListSelector, and so on). Thus I made it like this.

public class IterableToCollectionSelector<E, T extends Iterable<? extends E>, C extends Condition1<? super E>, R extends Collection<E>>
    implements Selector1<T, C, R>
{
  @Override
  public R select(final C condition, final T source)
  {
    final R result = // <- How can I get the Collection instance of R?
    for (final E element : source)
    {
      if (condition.isMet(element))
      {
        result.add(element);
      }
    }
    return result;
  }
}

Here are Condition1 and Selector1 in my library.

public interface Condition1<T>
{
  boolean isMet(T input);
}
public interface Selector1<T, C, R>
{
  R select(C condition, T source);
}

Let me explain it step by step. First,

public class IterableToCollectionSelector<E, T extends Iterable<? extends E>, C extends Condition1<? super E>, R extends Collection<E>>
    implements Selector1<T, C, R>
E
E is a type of an element stored in the given collection.
T

T is any type extends Iterable of the type extends E.

  1. Why is it Iterable of any type extends E (? extneds E)? Otherwise, you can’t use a List of any sub type of E.
    It would be easier to understand with an example. Let’s say you need to get a List of Product the price of which is greater than 50 dollars. If it’s just Iterable<E> then you have no problem with passing a List of Product yet you do have when you try to pass a List of DiscountedProduct which is a sub class of Product and it should be perfectly valid to pass it as a parameter of the selector made for Product (Think about Liskov substitution principle).
    If you have Iterable<? extends E>, you can pass E type and any sub-types of E, in this case, Product and DiscountedProduct are all fine.
  2. Then why T extends Iterable? Can I just have Iterable for the input type then I can remove the generic type T? Yes, it’s OK, but what if there is anyone who wants to extends this class and wants to restrict the input type to only List instead of any sub-type of Iterable (probably if you care about Open/closed principle)?
    If you have a class like this.

    // Notice that T extends Iterable<? extends E> is gone, and it has Iterable<? extends E> instead (No T).
    public class IterableToCollectionSelector<E, C extends Condition1<? super E>, R extends Collection<E>> implements
      Selector1<Iterable<? extends E>, C, R>
    {
    }
    

    You can’t restrict the input type to something other than Iterable<? extends E>, and if you try to override the select method in the sub-class of it.
    e.g.)

    public class IterableToArrayListSelector<E> extends
      IterableToCollectionSelector<E, Condition1<? super E>, ArrayList<E>>
    {
      @Override
      public ArrayList<E> select(final Condition1<? super E> condition, final List<? extends E> source)
      {
        return super.select(condition, source);
      }
    }
    

    You will get a compile-time error because T is not the same as “? extends T“. In this case, “Iterable<? extends E>” specified as a generic type T for the Selector1<T, C, R> is not the same as “? extends T” that is, in here, List<? extends E> (one of “T extends Iterable<? extends E>“) in the overridden method select() (It’s not actually overridden as List<? extends E> can’t be a substitute for Iterable<? extends E> here). Still not sure why List can’t be used? Well, think about this. List<String> is not the same as and can’t be a substitute for List<Object>. You know it, and I already explained it earlier when I talked about the side-effect of using arrays. Then think about this one. Can List<List<?>> be a substitute for List<Iterable<?>>? No, it’s just like List<String> and List<Object>, and the problem we have here is the same.

    So

    public class IterableToCollectionSelector<E, T extends Iterable<? extends E>, C extends Condition1<? super E>, R extends Collection<E>>
      implements Selector1<T, C, R>
    

    gives me freedom to restrict the input iterable to whatever extends Iterable I want.
    e.g.)

    public class IterableToArrayListSelector<E> extends
        IterableToCollectionSelector<E, List<? extends E>, Condition1<? super E>, ArrayList<E>>
    

    There will be a compile-time error when passing a Set instead of a List for the input value of the select() method.

C extends Condition1<? super E>
Next one is C extends Condition1<? super E>. What? Why is the input type of the Condition1? super E“? Because, with “? super E“, I can have one Condition1 object for many sub-types of the type E. Imagine that you want to get a List of Product the price of which is greater than 20, you can have a Condition1 for Product, then if you also need to get a List of DiscountedProduct the price of which is also greater than 20, you can reuse that Condition1 object for it as DiscountedProduct is a sub-type of Product which means Condition1<Product> is a kind of Condition1<? super DiscountedProduct>. If I have “C extends Condition1<E>” then I can’t do that, but because it’s “C extends Condition1<? super E>“, I can.
R
The last one is R. R extends Collection<E> so it can be any sub-type of Collection.

Now let’s look at the method. Here I have some problem.

  public R select(final C condition, final T source)
  {
    final R result = // <- How can I get the Collection instance of R???
    for (final E element : source)
    {
      if (condition.isMet(element))
      {
        result.add(element);
      }
    }
    return result;
  }

If it’s one type of Collection, I can easily create it but it’s not determined yet. It will be set when it’s used. Then why don’t I postpone instantiation of it until it’s used. More precisely when the selector is instantiated. So I just create another type to create one of Collection also using generics.

public interface CollectionCreator<E, T extends Collection<? extends E>>
{
  T createCollection();
}

So it can be used to create any sub-types of Collection.
e.g.) for ArrayList

public class ArrayListCreator<E> implements CollectionCreator<E, ArrayList<E>>
{
  @Override
  public ArrayList<E> createCollection()
  {
    return new ArrayList<E>();
  }
}

for HashSet

public class HashSetCreator<E> implements CollectionCreator<E, HashSet<E>>
{
  @Override
  public HashSet<E> createCollection()
  {
    return new HashSet<E>();
  }
}

With all these, the final version of IterableToCollectionSelector is

public class IterableToCollectionSelector<E, T extends Iterable<? extends E>, C extends Condition1<? super E>, R extends Collection<E>>
    implements Selector1<T, C, R>
{
  private final CollectionCreator<E, ? extends R> collectionCreator;

  public <CC extends CollectionCreator<E, ? extends R>> IterableToCollectionSelector(final CC collectionCreator)
  {
    this.collectionCreator = collectionCreator;
  }

  @Override
  public R select(final C condition, final T source)
  {
    final R result = collectionCreator.createCollection();
    for (final E element : source)
    {
      if (condition.isMet(element))
      {
        result.add(element);
      }
    }
    return result;
  }
}

It needs to have CollectionCreator but it’s immutable so I don’t need to worry about the state of the selector object once it’s created.

When IterableToCollectionSelector is used, it looks

// selector for the List of Product.
final IterableToCollectionSelector<Product, Iterable<Product>, Condition1<Product>, ArrayList<Product>> collectionSelector =
  new IterableToCollectionSelector<Product, Iterable<Product>, Condition1<Product>, ArrayList<Product>>(new ArrayListCreator());
final List<Product> resultList = collectionSelector.select(greaterThan20, productList);

// selector for the List of DiscountedProduct
final IterableToCollectionSelector<DiscountedProduct, Iterable<DiscountedProduct>, Condition1<Product>, ArrayList<DiscountedProduct>> collectionSelector2 =
  new IterableToCollectionSelector<DiscountedProduct, Iterable<DiscountedProduct>, Condition1<Product>, ArrayList<DiscountedProduct>>(new ArrayListCreator());
final List<DiscountedProduct> resultList2 = collectionSelector2.select(greaterThan20, discountedProductList)

Wait, do I have to create the IterableToCollectionSelector whenever I need to use it for a different type? It seems like it’s waste of memory and not to mention of boilerplate code. OK, here comes why I don’t hate generics’ type erasure anymore. Considering type erasure, both objects, used above, actually have no difference in runtime.

So what I can do is that I can create a helper class containing one really generic IterableToCollectionSelector then cast it using a generic method so that it always returns the same instance but can be used for different types with compile-time type safety. It would be clear if I just show the code.

public class CollectionUtil
{
  private static final IterableToCollectionSelector<?, ? extends Iterable<?>, ? extends Condition1<?>, ? extends ArrayList<?>> ITERABLE_TO_ARRAY_LIST_SELECTOR =
    new IterableToCollectionSelector<Object, Iterable<?>, Condition1<Object>, ArrayList<Object>>(
        new ArrayListCreator<Object>());

  public static <E, T extends Iterable<? extends E>, C extends Condition1<? super E>> IterableToCollectionSelector getIterableToCollectionSelector()
  {
    @SuppressWarnings("unchecked")
    final IterableToCollectionSelector<E, T, C, ArrayList<E>> iterableToCollectionSelector =
      (IterableToCollectionSelector<E, T, C, ArrayList<E>>) ITERABLE_TO_ARRAY_LIST_SELECTOR;
    return iterableToCollectionSelector;
  }
}

And similarly, ArrayListCreator doesn’t have to be created more than once. It doesn’t have any state so one instance can be and should be reused.

public class ArrayListCreator<E> implements CollectionCreator<E, ArrayList<E>>
{
  public static final ArrayListCreator<Object> ARRAY_LIST_CREATOR = new ArrayListCreator<Object>();

  @Override
  public ArrayList<E> createCollection()
  {
    return newArrayList();
  }

  public static <E> ArrayListCreator<E> getInstance()
  {
    @SuppressWarnings("unchecked")
    final ArrayListCreator<E> arrayListCreator = (ArrayListCreator<E>) ARRAY_LIST_CREATOR;
    return arrayListCreator;
  }
}

So CollectionUtil is rewritten.

public class CollectionUtil
{
  private static final IterableToCollectionSelector<?, ? extends Iterable<?>, ? extends Condition1<?>, ? extends ArrayList<?>> ITERABLE_TO_ARRAY_LIST_SELECTOR =
    new IterableToCollectionSelector<Object, Iterable<?>, Condition1<Object>, ArrayList<Object>>(
        ArrayListCreator.getInstance());

  public static <E, T extends Iterable<? extends E>, C extends Condition1<? super E>> IterableToCollectionSelector getIterableToCollectionSelector()
  {
    @SuppressWarnings("unchecked")
    final IterableToCollectionSelector<E, T, C, ArrayList<E>> iterableToCollectionSelector =
      (IterableToCollectionSelector<E, T, C, ArrayList<E>>) ITERABLE_TO_ARRAY_LIST_SELECTOR;
    return iterableToCollectionSelector;
  }
}
@SuppressWarnings("unchecked")
final IterableToCollectionSelector<E, T, C, ArrayList<E>> iterableToCollectionSelector =
  (IterableToCollectionSelector<E, T, C, ArrayList<E>>) ITERABLE_TO_ARRAY_LIST_SELECTOR;

This is possible due to type erasure, so you don’t have to create many objects of the same type with different generic type info (e.g. instances of the same type, ‘IterableToCollectionSelector‘, with ‘different generic types’ like different E, T, C) which will be all the same in runtime. That’s why I do not hate type erasure anymore. Of course, you need to @SuppressWarnings to make the compiler quiet, but it’s not a big deal and I know what I’m doing. It’s perfectly valid.

The condition can be reused.

final Condition1<Product> greaterThan20 = new Condition1<Product>() {
  private final BigDecimal twenty = new BigDecimal("20");
  @Override
  public boolean isMet(final Product input)
  {
    return 0 > twenty.compareTo(input.getPrice());
  }
};

Now I can just do,

final IterableToCollectionSelector<Product, Iterable<Product>, Condition1<Product>, ArrayList<Product>> collectionSelectorForProduct =
  CollectionUtil.getIterableToCollectionSelector();
final List<Product> resultForProduct = collectionSelectorForProduct.select(greaterThan20, productList);

final IterableToCollectionSelector<DiscountedProduct, Iterable<DiscountedProduct>, Condition1<Product>, ArrayList<DiscountedProduct>> collectionSelectorForDiscountedProduct =
  CollectionUtil.getIterableToCollectionSelector();
final List<DiscountedProduct> resultForDiscountedProduct = collectionSelectorForDiscountedProduct.select(greaterThan20, discountedProductList);

Each time when you get an instance of IterableToCollectionSelector using the getIterableToCollectionSelector() method, you get the same IterableToCollectionSelector instance.

OK, that sounds good but do I really need to know all those complex E, T, C, R and even wildcard like “? extends E” or “? super E“? Well, you don’t have to. It depends on what you do. If you’re a library or framework developer, you should probably. Otherwise, not really. The library or API designer should carefully design it to offer APIs that are easy to use and understand for the users of the library. The designer or architect, on the other hand, should know the things I talked about here to make complex things simple. That’s our job, isn’t it? Making a complex thing simple then solve it. Anyway, most of the time, you don’t need to deal with that kind of complex API if you’re an application developer. Your company should have at least one person who can deal with it and he/she should provide easy to use APIs. If your company doesn’t have any, ask your boss to hire one. :) Using well designed good APIs can surely save your time which means saving your company’s money. Also less error-prone.

So how can the IterableToCollectionSelector be simple so that the users wouldn’t need to care about E, T, C, etc.

The library designer should create more specific type of selector like

public final class IterableToArrayListSelector<E> extends
    IterableToCollectionSelector<E, Iterable<? extends E>, Condition1<? super E>, ArrayList<E>>
{
  IterableToArrayListSelector(final ArrayListCreator<E> collectionCreator)
  {
    super(collectionCreator);
  }
}

Then CollectionUtil becomes

public class CollectionUtil
{
  private static final IterableToArrayListSelector<?> ITERABLE_TO_ARRAY_LIST_SELECTOR =
    new IterableToArrayListSelector<Object>(ArrayListCreator.getInstance());

  public static <E> IterableToArrayListSelector<E> getIterableToArrayListSelector()
  {
    @SuppressWarnings("unchecked")
    final IterableToArrayListSelector<E> iterableToCollectionSelector =
      (IterableToArrayListSelector<E>) ITERABLE_TO_ARRAY_LIST_SELECTOR;
    return iterableToCollectionSelector;
  }
}

Now using it is much easier.
(with static import)

import static your.package_name.here.CollectionUtil.*;

// ...

final IterableToArrayListSelector<Product> arrayListSelectorForProduct =
  getIterableToArrayListSelector();
final List<Product> resultForProduct = arrayListSelectorForProduct.select(greaterThan20, productList);

final IterableToArrayListSelector<DiscountedProduct> arrayListSelectorForDiscountedProduct =
  getIterableToArrayListSelector();
final List<DiscountedProduct> resultForDiscountedProduct =
  arrayListSelectorForDiscountedProduct.select(greaterThan20, discountedProductList);

You may not be satisfied yet, because you have the variables for the IterableToArrayListSelector objects. Should you have these? No, you don’t have to. So you probably try like this.

final List<Product> resultForProduct = getIterableToArrayListSelector()
                                         .select(greaterThan20, productList);

Yet, this doesn’t work. When getIterableToArrayListSelector() is called there is no generic type info given so it returns just an object of IterableToArrayListSelector<Object>. Thus it causes a compile-time error on calling select(greaterThan20, productList).

It can be solved by specifying the generic type like.

final List<Product> resultForProduct2 = CollectionUtil.<Product> getIterableToArrayListSelector()
                                          .select(greaterThan20, productList);

It’s not so elegant though. It can be solved as well. How? instead of having the getIterableToArrayListSelector() method to get an instance of IterableToArrayListSelector, why don’t I just create another generic select() method which does both getting the instance and calling the select() method in it.

So CollectionUtil is re-written.

public class CollectionUtil
{
  private static final IterableToArrayListSelector<?> ITERABLE_TO_ARRAY_LIST_SELECTOR =
    new IterableToArrayListSelector<Object>(ArrayListCreator.getInstance());

  public static <E, T extends Iterable<? extends E>, C extends Condition1<? super E>> ArrayList<E> select(
      final C condition, final T iterable)
  {
    final IterableToArrayListSelector<E> iterableToCollectionSelector =
      (IterableToArrayListSelector<E>) ITERABLE_TO_ARRAY_LIST_SELECTOR;
    return iterableToCollectionSelector.select(condition, iterable);
  }
}

How to use? Really simple.
(also with static import)

import static your.package_name.here.CollectionUtil.*;

// ...

final List<Product> resultForProduct = select(greaterThan20, productList);

final List<DiscountedProduct> resultForDiscountedProduct = select(greaterThan20, discountedProduct);

So it’s

final IterableToCollectionSelector<Product, Iterable<Product>, Condition1<Product>, ArrayList<Product>> collectionSelectorForProduct =
  getIterableToCollectionSelector();
final List<Product> resultForProduct = collectionSelectorForProduct.select(greaterThan20, productList);

VS

final List<Product> resultForProduct = select(greaterThan20, productList);

As you can see, depending on how you use generics it can give you a really nice, simple and easy to use API.

Just a moment. It might not be enough. That select takes an Iterable object and returns an ArrayList object, but what if I want to get HashSet instead, or what about taking an array as an input parameter instead of an Iterable object? It can be accomplished too, but I’m not going to explain it here. I’ll do it later when I talk about good API design in another post not in the generics series.

In the meantime, you can use what I’ve already provided in my library that is KommonLee.

If you use it, you can simply do

final List<Product> anotherPositiveIntegerList = selector()
        .fromIterable()
        .toArrayList()
        .select(greaterThan20, productList);

OR

final Set<Product> anotherPositiveIntegerList = selector()
        .fromIterable()
        .toHashSet()
        .select(greaterThan20, productList);

OR

Product[] productArray = // ...
final List<Product> anotherPositiveIntegerList = selector()
        .fromArray()
        .toArrayList()
        .select(greaterThan20, productArray);

and so on…
More examples are >>here<<
It also has Mappers and SelectableMappers so you can convert one type stored in a Collection to another.

Also the example code I used here is available on Github. Example Code: CLICK HERE!!!

Next post about generics would be about something easier than the selector example. So it would be some practical but easier, then the final post would be about really complex one when it’s designed but easy when it’s used. It is also very practical and useful. Unfortunately, however, I can’t tell when I can write it as I need to think about good examples to explain. As you can see above, it can be difficult to understand without example code (or even with it, still difficult). I do actually have some examples but it’s the code I made for my work so I can’t just use it. Anyway, I will figure it out so stay tuned.
 
 

Thanks for those who retweeted and favorited this post.

 

Easier and Better Way to Use JDBC

I can still see many tutorials of JDBC that are not really talking about how JDBC programming can be done easily and more practically & efficiently. I can understand that those tutorials are to give a very basic level of knowledge of JDBC. Besides, we do often not use JDBC directly any more these days. There are easier and simpler solutions like Object Relational Mapping (ORM) and other persistence frameworks. I use Java Persistence API (JPA) with Hibernate and QueryDSL (Personally, I think QueryDSL is great. I cannot imagine life without QueryDSL anymore when using JPA. :) ). There are also other choices. For instance, EclipseLink and OpenJPA both of which are JPA implementations, Java Data Objects (JDO), MyBatis, the successor of iBATIS, and so on.

However, there may come a time when you need to directly use JDBC. It can be developing an application which requires accessing and using database or for developing your own Java persistence framework. One way or another it is good to learn this very fundamental Java persistence technology to get some good things from it as well as its drawback in order to avoid it. I am not going to talk about what JDBC is or how to use it as there are plenty of other tutorials explaining these on the Internet. What I am going to do is talking about better and easier way to use JDBC. I will not cover every single detail about it though, as my point here is giving some idea to use it better and there are already known solutions that provide what I am going to explain.

There are four steps to take to explain the better way of using JDBC. First of all, I will show a typical way to use JDBC then point out problems in it. After that analyse it to find a better way. Finally, I will implement it.

Preparation

Database and JDBC Driver

In my examples, I’ve used MySQL 5.1 and MySQL Connection/J 5.1.17 downloaded from the Connector/J download page on the MySQL website.

mysql-connector-java-5.1.17.zip

If you don’t want to become a user of the site, you can click the “No thanks, just take me to the downloads!” link at the bottom.
What you need is only one jar file that is mysql-connector-java-5.1.17-bin.jar in the zip file.

Java Beans

There are three JavaBeans used in the example to contain the data from the database.

public class Person
{
  private Long id;
  private String surname;
  private String givenName;
  private Address address;

  // getters and setters omitted.
}
public class Address
{
  private String street;
  private String suburb;
  private String state;
  private String country;
  private String postcode;
  private Date birthday;

  // constructors, getters and setters omitted.
}
import java.util.Date;

public class Book
{
  private Long id;
  private String title;
  private String authours;
  private String edition;
  private String isbn10;
  private String isbn13;
  private String publisher;
  private Date publishingDate;

  // getters and setters omitted.
}

1. Typical Way to Use JDBC

Here is a very typical way to use JDBC when retrieving data from the database.

Connection connection = null;
PreparedStatement statement = null;
ResultSet resultSet = null;

try
{
  // get connection.
  connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/testdb",
                                           "testuser",
                                           "1234");

  final String sql = "SELECT * FROM people";
  
  // get PreparedStatement
  statement = connection.prepareStatement(sql);
  
  // run the query and get the result stored in the ResultSet.
  resultSet = statement.executeQuery();
  
  final List<Person> people = new ArrayList<Person>();
  while (resultSet.next())
  {
    // Map each row to a Person object and add it to the Person List, people.
    final Person person = new Person();
    person.setId(resultSet.getLong("person_id"));
    person.setSurname(resultSet.getString("surname"));
    person.setGivenName(resultSet.getString("given_name"));
    final Address address =
      new Address(resultSet.getString("street"),
          resultSet.getString("city"),
          resultSet.getString("state"),
          resultSet.getString("country"),
          resultSet.getString("postcode"));
    person.setAddress(address);
    person.setBirthday(new Date(resultSet
                          .getDate("birthday")
                          .getTime()));
    people.add(person);
  }
  System.out.println(people);
}
catch (final SQLException e)
{
  // you MUST catch SQLException exception
  // or add the throws clause having SQLException to the method declaration.
  e.printStackTrace();
}
finally
{
  // close ResultSet, PreparedStatement and Connection.
  if (null != resultSet)
  {
    try
    {
      resultSet.close();
    }
    catch (final SQLException e)
    {
      e.printStackTrace();
    }
  }
  if (null != statement)
  {
    try
    {
      statement.close();
    }
    catch (final SQLException e)
    {
      e.printStackTrace();
    }
  }
  if (null != connection)
  {
    try
    {
      connection.close();
    }
    catch (final SQLException e)
    {
      e.printStackTrace();
    }
  }
}

2. Problems

Now, I will make DAOs for Person and Book objects to examine what issues we can have when we follow the typical way to use JDBC mentioned above. Here is the PersonDao interface.

package com.lckymn.kevin.tutorial.jdbc_old.dao;

import java.util.List;

import com.lckymn.kevin.tutorial.jdbc_old.beans.Person;

public interface PersonDao
{
  Person find(Long id);
  List<Person> findPeopleByState(String state);
  List<Person> getAllPeople();
}

The following one is the BookDao interface.

package com.lckymn.kevin.tutorial.jdbc_old.dao;

import java.util.List;

import com.lckymn.kevin.tutorial.jdbc_old.beans.Book;

public interface BookDao
{
  Book find(Long id);
  List<Book> findBooksByPublisher(String publisher);
}

Before making the implementations of these, I will create an abstract class for both DAOs.

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;

public abstract class AbstractDao
{
  private final String url;
  private final String username;
  private final String password;

  public AbstractDao(final String url, final String username, final String password)
  {
    this.url = url;
    this.username = username;
    this.password = password;
  }

  protected final Connection getConnection() throws SQLException
  {
    /*
     * depending on the version of JDBC (prior to 4.0) you may need to load the driver first.
     */
    return DriverManager.getConnection(url, username, password);
  }
}

Or for better use of database connection, Using Connection Pool and DataSource is desirable.

import java.sql.Connection;
import java.sql.SQLException;

import javax.sql.DataSource;

public abstract class AbstractDao
{
  private final DataSource dataSource;

  public AbstractDao(final DataSource dataSource)
  {
    this.dataSource = dataSource;
  }

  protected final Connection getConnection() throws SQLException
  {
    return dataSource.getConnection();
  }
}

Here is the implementation of PersonDao. The PersonDao extends AbstractDao thus it can get the Connection from the getConnection() method in the super class.

package com.lckymn.kevin.tutorial.jdbc_old.dao.impl;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;

import com.lckymn.kevin.tutorial.jdbc_old.beans.Address;
import com.lckymn.kevin.tutorial.jdbc_old.beans.Person;
import com.lckymn.kevin.tutorial.jdbc_old.dao.AbstractDao;
import com.lckymn.kevin.tutorial.jdbc_old.dao.PersonDao;

public class PersonDaoImpl extends AbstractDao implements PersonDao
{
  // constructor omitted...

  @Override
  public Person find(final Long id)
  {
    Connection connection = null;
    PreparedStatement statement = null;
    ResultSet resultSet = null;

    final List<Person> result = new ArrayList<Person>();
    try
    {
      connection = getConnection();
      final String sql = "SELECT * FROM people WHERE person_id = ?";
      statement = connection.prepareStatement(sql);
      statement.setLong(1, id);
      resultSet = statement.executeQuery();
      while (resultSet.next())
      {
        final Person person = new Person();
        person.setId(resultSet.getLong("person_id"));
        person.setSurname(resultSet.getString("surname"));
        person.setGivenName(resultSet.getString("given_name"));
        final Address address =
          new Address(resultSet.getString("street"),
              resultSet.getString("city"),
              resultSet.getString("state"),
              resultSet.getString("country"),
              resultSet.getString("postcode"));
        person.setAddress(address);
        person.setBirthday(new Date(resultSet
                              .getDate("birthday")
                              .getTime()));
        result.add(person);
      }
    }
    catch (final SQLException e)
    {
      e.printStackTrace();
    }
    finally
    {
      if (null != resultSet)
        try { resultSet.close(); }
        catch (final SQLException e) { e.printStackTrace(); }

      if (null != statement)
        try { statement.close(); }
        catch (final SQLException e) { e.printStackTrace(); }

      if (null != connection)
        try { connection.close(); }
        catch (final SQLException e) { e.printStackTrace(); }
    }
    return result.isEmpty() ? null : result.get(0);
  }

  @Override
  public List<Person> findPeopleByState(final String state)
  {
    Connection connection = null;
    PreparedStatement statement = null;
    ResultSet resultSet = null;

    final List<Person> result = new ArrayList<Person>();
    try
    {
      connection = getConnection();
      final String sql = "SELECT * FROM people WHERE state = ?";
      statement = connection.prepareStatement(sql);
      statement.setString(1, state);
      resultSet = statement.executeQuery();
      while (resultSet.next())
      {
        final Person person = new Person();
        person.setId(resultSet.getLong("person_id"));
        person.setSurname(resultSet.getString("surname"));
        person.setGivenName(resultSet.getString("given_name"));
        final Address address =
          new Address(resultSet.getString("street"),
              resultSet.getString("city"),
              resultSet.getString("state"),
              resultSet.getString("country"),
              resultSet.getString("postcode"));
        person.setAddress(address);
        person.setBirthday(new Date(resultSet
                              .getDate("birthday")
                              .getTime()));
        result.add(person);
      }
    }
    catch (final SQLException e)
    {
      e.printStackTrace();
    }
    finally
    {
      if (null != resultSet)
        try { resultSet.close(); }
        catch (final SQLException e) { e.printStackTrace(); }

      if (null != statement)
        try { statement.close(); }
        catch (final SQLException e) { e.printStackTrace(); }

      if (null != connection)
        try { connection.close(); }
        catch (final SQLException e) { e.printStackTrace(); }
    }
    return result;
  }

  @Override
  public List<Person> getAllPeople()
  {
    Connection connection = null;
    PreparedStatement statement = null;
    ResultSet resultSet = null;

    final List<Person> result = new ArrayList<Person>();
    try
    {
      connection = getConnection();
      final String sql = "SELECT * FROM people";
      statement = connection.prepareStatement(sql);
      resultSet = statement.executeQuery();
      while (resultSet.next())
      {
        final Person person = new Person();
        person.setId(resultSet.getLong("person_id"));
        person.setSurname(resultSet.getString("surname"));
        person.setGivenName(resultSet.getString("given_name"));
        final Address address =
          new Address(resultSet.getString("street"),
              resultSet.getString("city"),
              resultSet.getString("state"),
              resultSet.getString("country"),
              resultSet.getString("postcode"));
        person.setAddress(address);
        person.setBirthday(new Date(resultSet
                              .getDate("birthday")
                              .getTime()));
        result.add(person);
      }
    }
    catch (final SQLException e)
    {
      e.printStackTrace();
    }
    finally
    {
      if (null != resultSet)
        try { resultSet.close(); }
        catch (final SQLException e) { e.printStackTrace(); }

      if (null != statement)
        try { statement.close(); }
        catch (final SQLException e) { e.printStackTrace(); }

      if (null != connection)
        try { connection.close(); }
        catch (final SQLException e) { e.printStackTrace(); }
    }
    return result;
  }
}

As you can see, there is too much boilerplate code here. Then what about the implementation of BookDao?

package com.lckymn.kevin.tutorial.jdbc_old.dao.impl;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;

import com.lckymn.kevin.tutorial.jdbc_old.beans.Book;
import com.lckymn.kevin.tutorial.jdbc_old.dao.AbstractDao;
import com.lckymn.kevin.tutorial.jdbc_old.dao.BookDao;

public class BookDaoImpl extends AbstractDao implements BookDao
{
  public BookDaoImpl(final String url, final String username, final String password)
  {
    super(url, username, password);
  }

  @Override
  public Book find(final Long id)
  {
    Connection connection = null;
    PreparedStatement statement = null;
    ResultSet resultSet = null;

    final List<Book> result = new ArrayList<Book>();
    try
    {
      connection = getConnection();
      final String sql = "SELECT * FROM book WHERE book_id = ?";
      statement = connection.prepareStatement(sql);
      statement.setLong(1, id);
      resultSet = statement.executeQuery();
      while (resultSet.next())
      {
        final Book book = new Book();
        book.setId(resultSet.getLong("book_id"));
        book.setTitle(resultSet.getString("title"));
        book.setAuthours(resultSet.getString("authours"));
        book.setEdition(resultSet.getString("edition"));
        book.setIsbn10(resultSet.getString("isbn10"));
        book.setIsbn13(resultSet.getString("isbn13"));
        book.setPublisher(resultSet.getString("publisher"));
        book.setPublishingDate(resultSet.getDate("publishing_date"));
        result.add(book);
      }
    }
    catch (final SQLException e)
    {
      e.printStackTrace();
    }
    finally
    {
      if (null != resultSet)
        try { resultSet.close(); }
        catch (final SQLException e) { e.printStackTrace(); }

      if (null != statement)
        try { statement.close(); }
        catch (final SQLException e) { e.printStackTrace(); }

      if (null != connection)
        try { connection.close(); }
        catch (final SQLException e) { e.printStackTrace(); }
    }
    return result.isEmpty() ? null : result.get(0);
  }

  @Override
  public List<Book> findBooksByPublisher(final String publisher)
  {
    Connection connection = null;
    PreparedStatement statement = null;
    ResultSet resultSet = null;

    final List<Book> result = new ArrayList<Book>();
    try
    {
      connection = getConnection();
      final String sql = "SELECT * FROM book WHERE publisher = ?";
      statement = connection.prepareStatement(sql);
      statement.setString(1, publisher);
      resultSet = statement.executeQuery();
      while (resultSet.next())
      {
        final Book book = new Book();
        book.setId(resultSet.getLong("book_id"));
        book.setTitle(resultSet.getString("title"));
        book.setAuthours(resultSet.getString("authours"));
        book.setEdition(resultSet.getString("edition"));
        book.setIsbn10(resultSet.getString("isbn10"));
        book.setIsbn13(resultSet.getString("isbn13"));
        book.setPublisher(resultSet.getString("publisher"));
        book.setPublishingDate(resultSet.getDate("publishing_date"));
        result.add(book);
      }
    }
    catch (final SQLException e)
    {
      e.printStackTrace();
    }
    finally
    {
      if (null != resultSet)
        try { resultSet.close(); }
        catch (final SQLException e) { e.printStackTrace(); }

      if (null != statement)
        try { statement.close(); }
        catch (final SQLException e) { e.printStackTrace(); }

      if (null != connection)
        try { connection.close(); }
        catch (final SQLException e) { e.printStackTrace(); }
    }
    return result;
  }
}

Just the same… OK, now I will compare just one method in each DAO and try to find if there are any similarities in these methods. One method from PersonDaoImpl is findPeopleByState(String) and the other one from BookDaoImpl is findBooksByPublisher(String).

Let’s see what are different.

Method Comparison Between PersonDao and BookDao

Method Comparison Between PersonDao and BookDao

As you can see, except for a few parts highlighted, I’ve just repeated the same code. That means if the user of the DAO can dynamically give the code for these few differences when using it, I do not need to repeat the same code over and over again.

There is another problem in the catch block that catches the SQLException which can be thrown in the try block containing the main part of the code snippet.

}
catch (final SQLException e)
{
  e.printStackTrace(); // It just prints the StackTrace and ignores the exception.
}
finally
{

It just prints the StackTrace and ignores the exception, and this may cause a more serious problem as the exception is simply ignored so the programmers cannot easily find what went wrong. I need to deal with it too.

3. Finding Better Way

I will create a JdbcManager which takes care of selection, insertion, update and deletion of data.

I will try something very easy to do first. In the typical DAO code, every method has a finally block having really ugly code snippet to close ResultSet, Statement and Connection. I am sick of it so want to get rid of it first, but I cannot simply remove that code as it’s absolutely necessary therefore it’s there. Then I can make a method which closes those objects quietly without throwing any exception, for it’s already in the finally block and there might be already an exception thrown. So I don’t want the finally block to throw another exception which interrupts the fist exception.

My JdbcManager class will have the following method to close ResultSet, Statement and Connection.

private void closeQuietly(final Connection connection,
                          final PreparedStatement statement,
                          final ResultSet resultSet)
{
  if (null != resultSet)
    try { resultSet.close(); }
    catch (final SQLException e) { e.printStackTrace(); } // or log properly

  if (null != statement)
    try { statement.close(); }
    catch (final SQLException e) { e.printStackTrace(); } // or log properly

  if (null != connection)
    try { connection.close(); }
    catch (final SQLException e) { e.printStackTrace(); } // or log properly
}

So now findPeopleByState(String) looks like this.

public List<Person> findPeopleByState(final String state)
{
  Connection connection = null;
  PreparedStatement statement = null;
  ResultSet resultSet = null;

  final List<Person> result = new ArrayList<Person>();
  try
  {
    connection = getConnection();
    final String sql = "SELECT * FROM people WHERE state = ?";
    statement = connection.prepareStatement(sql);
    statement.setString(1, state);
    resultSet = statement.executeQuery();
    while (resultSet.next())
    {
      final Person person = new Person();
      person.setId(resultSet.getLong("person_id"));
      person.setSurname(resultSet.getString("surname"));
      person.setGivenName(resultSet.getString("given_name"));
      final Address address =
        new Address(resultSet.getString("street"),
                    resultSet.getString("city"),
                    resultSet.getString("state"),
                    resultSet.getString("country"),
                    resultSet.getString("postcode"));
      person.setAddress(address);
      person.setBirthday(new Date(resultSet
                            .getDate("birthday")
                            .getTime()));
      result.add(person);
    }
  }
  catch (final SQLException e)
  {
    e.printStackTrace();
  }
  finally
  {
    closeQuietly(connection, statement, resultSet);
  }
  return result;
}

Now think about the highlighted lines that are different depending on what type of object should be returned.
The first one is the method signature. I will talk about the parameters later and now focus on only the return type.

public List<Person> findPeopleByState(final String state)

It returns a List of Person but what if I want to get a List of Book? So the return type is of type List, but the type of the element should be contained in the List is undecided. It should be pending until the user of the method specifies it. In this kind of situation, what do we normally use? When we design an API and want to defer specifying what type to use until the user of the API decides it with providing compile-time type safety, we use Generics in Java.
So I can just easily make the method a generic method so that the return type would be depending on how the user of the method uses it.

public <T> T findPeopleByState( *don't worry about params for a while* )

The second part is the same, I don’t know what type of object the user wants to have in the List, so I just use a generic type parameter T.
So I’ve changed this

final List<Person> result = new ArrayList<Person>();

to

final List<T> result = new ArrayList<T>();

The third one is easy. It can easily become a parameter of the method.

final String sql = "SELECT * FROM people WHERE state = ?";

So the method signature would be like

public <T> T findPeopleByState(String sql, *don't worry about the rest params for now* )

Next one also looks simple. It’s just one line of code. Well, it is one line in this example but can be many lines depending on the given parameter values.

statement.setString(1, state);

So it might be like

statement.setLong(1, longValue);
statement.setString(2, stringValue);
statement.setBoolean(3, booleanValue);

So it seems like it will possibly have many parameters from the user of my method. So I think I should use some kind of Collection type containing the parameters or an array of Object containing these because the types of the parameters can vary. Wait. More conveniently I can just use varargs so that the user of my method doesn’t need to create any extra instance of collection or array to pass the parameters although using varargs results in creation of an array by compiler, yet in the user’s point of view, it’s hidden so can be very convenient.

public <T> T findPeopleByState(String sql,
                               //possibly more params here
                               Object ... params)

The types of the parameters can vary so I put Object type varargs. Now I need to set the parameters to the PreparedStatement. Since the varargs is actually an array, I can iterate over it to get each parameter then I use an index to get a parameter and index + 1 to set the parameterIndex in the PreparedStatement as it starts from 1. I will cover here only primitive types (including boxed ones), String and other commonly used reference types in db programming which are Date, Calendar and BigDecimal. All the other types will cause an IllegalArgumentException. It can of course improve but I am just giving an idea to use it better so am trying to make it just simple enough to understand with providing the idea. So the code would be

private void setParameters(final PreparedStatement statement, final Object... parameters) throws SQLException
{
  for (int i = 0, length = parameters.length; i < length; i++)
  {
    final Object parameter = parameters[i];
    final int parameterIndex = i + 1;
    if (null == parameter)
    {
      statement.setObject(parameterIndex, null);
    }
    else if (parameter instanceof Boolean)
    {
      statement.setBoolean(parameterIndex, (Boolean) parameter);
    }
    else if (parameter instanceof Character)
    {
      statement.setString(parameterIndex, String.valueOf(parameter));
    }
    else if (parameter instanceof Byte)
    {
      statement.setByte(parameterIndex, (Byte) parameter);
    }
    else if (parameter instanceof Short)
    {
      statement.setShort(parameterIndex, (Short) parameter);
    }
    else if (parameter instanceof Integer)
    {
      statement.setInt(parameterIndex, (Integer) parameter);
    }
    else if (parameter instanceof Long)
    {
      statement.setLong(parameterIndex, (Long) parameter);
    }
    else if (parameter instanceof Float)
    {
      statement.setFloat(parameterIndex, (Float) parameter);
    }
    else if (parameter instanceof Double)
    {
      statement.setDouble(parameterIndex, (Double) parameter);
    }
    else if (parameter instanceof String)
    {
      statement.setString(parameterIndex, (String) parameter);
    }
    else if (parameter instanceof Date)
    {
      statement.setDate(parameterIndex, new java.sql.Date(((Date) parameter)
                                            .getTime()));
    }
    else if (parameter instanceof Calendar)
    {
      statement.setDate(parameterIndex, new java.sql.Date(((Calendar) parameter)
                                            .getTimeInMillis()));
    }
    else if (parameter instanceof BigDecimal)
    {
      statement.setBigDecimal(parameterIndex, (BigDecimal) parameter);
    }
    else
    {
      throw new IllegalArgumentException(String.format(
          "Unknown type of the parameter is found. [param: %s, paramIndex: %s]",
          parameter,
          parameterIndex));
    }
  }
}

It can be used by other methods in the JdbcManager as well, so I made it a method.

Next is

while (resultSet.next())
{
  final Person person = new Person();
  person.setId(resultSet.getLong("person_id"));
  person.setSurname(resultSet.getString("surname"));
  person.setGivenName(resultSet.getString("given_name"));
  final Address address =
    new Address(resultSet.getString("street"),
                resultSet.getString("city"),
                resultSet.getString("state"),
                resultSet.getString("country"),
                resultSet.getString("postcode"));
  person.setAddress(address);
  person.setBirthday(new Date(resultSet
                        .getDate("birthday")
                        .getTime()));
  result.add(person);
}

The highlighted part should be done by the user of the API. The JdbcManager does’t know what should be there nor can it guess what data the user of it wants to retrieve from the database. It looks like I can use Callback here. Java does not have First-Class Function yet (Java will have First-Class Function in the form of lambda expression in the Java SE 8. Click here to get more details about Project Lambda), but I can define an interface which maps data in a ResultSet row to a Java object and let the user pass an instance of class implementing the interface or an anonymous class instance of the interface can be used too.
What I need to consider is the return type and the ResultSet as I’m now trying to map the data in the ResultSet to a Java object (return type). So the mapper interface should look like.

package com.lckymn.kevin.tutorial.jdbc_better.jdbc;

import java.sql.ResultSet;
import java.sql.SQLException;

public interface RowMapper<T>
{
  T map(ResultSet resultSet) throws SQLException;
}

Notice that I’ve also added the throws clause having SQLException as using ResultSet requires it and that’s why we put try-catch block in our code using JDBC. The SQLException thrown in the map() method will be handled by the try-catch block in the main part of the JdbcManager select() method.

There is one last issue left. Now I need to take care of ignoring SQLException in the catch block.

}
catch (final SQLException e)
{
  e.printStackTrace();
}
finally

I can properly log it instead of just calling the printStackTrace() method in the SQLException, but it’s not enough. I don’t want to just ignore it as it may cause some serious issue in runtime. However, I don’t want to re-throw it either because then the caller of this method or “the caller of the caller” of the method or in the worst case, all the methods in the method call hierarchy have to deal with the SQLException. Thus I want to create my own unchecked exception (an exception that extends RuntimeException) which wraps the SQLException. It is beneficial not only because the caller of the method doesn’t need to catch or re-throw it but because it is also understandable by the caller of the method even after I decide not to use JDBC at all so it doesn’t have any SQLException any more. In this case, if I used SQLException, I would have to change the code in the caller-side as the caller would directly deal with it.

Here is my new Exception for data access.

package com.lckymn.kevin.tutorial.jdbc_better.exception;

public class DataAccessException extends RuntimeException
{
  private static final long serialVersionUID = 1L;

  public DataAccessException()
  {
  }

  public DataAccessException(final String message, final Throwable cause)
  {
    super(message, cause);
  }

  public DataAccessException(final String message)
  {
    super(message);
  }

  public DataAccessException(final Throwable cause)
  {
    super(cause);
  }
}

I also want to have another exception that extends it in order to indicate data access connection failure.

package com.lckymn.kevin.tutorial.jdbc_better.exception;

public class DataAccessConnectionFailureException extends DataAccessException
{
  private static final long serialVersionUID = 1L;

  public DataAccessConnectionFailureException(final Throwable cause)
  {
    super(cause);
  }
}

Finally one for general data access operation problems.

package com.lckymn.kevin.tutorial.jdbc_better.exception;

public class DataAccessOperationErrorException extends DataAccessException
{
  private static final long serialVersionUID = 1L;

  public DataAccessOperationErrorException()
  {
  }

  public DataAccessOperationErrorException(final String message, final Throwable cause)
  {
    super(message, cause);
  }

  public DataAccessOperationErrorException(final String message)
  {
    super(message);
  }

  public DataAccessOperationErrorException(final Throwable cause)
  {
    super(cause);
  }
}

I can replace the old code that prints stack trace with

}
catch (final SQLException e)
{
  throw new DataAccessOperationErrorException(e);
}
finally

So with all the solutions I mentioned above, my new code now becomes

public <T> List<T> select(final String sql,
                          final RowMapper<T> rowMapper,
                          final Object... parameters)
      throws DataAccessException
{
  Connection connection = null;
  PreparedStatement statement = null;
  ResultSet resultSet = null;

  final List<T> result = new ArrayList<T>();
  try
  {
    connection = getConnection();
    statement = connection.prepareStatement(sql);
    setParameters(statement, parameters);
    resultSet = statement.executeQuery();
    while (resultSet.next())
    {
      result.add(rowMapper.map(resultSet));
    }
  }
  catch (final SQLException e)
  {
    throw new DataAccessOperationFailureException(e);
  }
  finally
  {
    closeQuietly(connection, statement, resultSet);
  }
  return result;
}

It’s time to use it. Before using it, I’ll show my JdbcManager interface and the implementing class.

package com.lckymn.kevin.tutorial.jdbc_better.jdbc;

import java.util.List;

import com.lckymn.kevin.tutorial.jdbc_better.exception.DataAccessException;

/**
 * @author Lee, SeongHyun (Kevin) / <a href="http://blog.lckymn.com">Kevin&#39;s Blog</a>
 * @version 0.0.1 (2011-09-04)
 */
public interface JdbcManager
{
  <T> List<T> select(String sql, RowMapper<T> rowMapper, Object... parameters) throws DataAccessException;

  int update(final String sql, final Object... parameters) throws DataAccessException;
}
package com.lckymn.kevin.tutorial.jdbc_better.jdbc.impl;

import java.math.BigDecimal;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.List;

import javax.sql.DataSource;

import com.lckymn.kevin.tutorial.jdbc_better.exception.DataAccessConnectionFailureException;
import com.lckymn.kevin.tutorial.jdbc_better.exception.DataAccessException;
import com.lckymn.kevin.tutorial.jdbc_better.exception.DataAccessOperationErrorException;
import com.lckymn.kevin.tutorial.jdbc_better.jdbc.JdbcManager;
import com.lckymn.kevin.tutorial.jdbc_better.jdbc.RowMapper;

/**
 * @author Lee, SeongHyun (Kevin) / <a href="http://blog.lckymn.com">Kevin&#39;s Blog</a>
 * @version 0.0.1 (2011-09-04)
 */
public class JdbcManagerImpl implements JdbcManager
{
  private final DataSource dataSource;

  public JdbcManagerImpl(final DataSource dataSource)
  {
    this.dataSource = dataSource;
  }

  protected final Connection getConnection()
  {
    try
    {
      return dataSource.getConnection();
    }
    catch (final SQLException e)
    {
      throw new DataAccessConnectionFailureException(e);
    }

  }

  private void closeQuietly(final Connection connection,
                            final PreparedStatement statement,
                            final ResultSet resultSet)
  {
    if (null != resultSet)
      try { resultSet.close(); }
      catch (final SQLException e) { e.printStackTrace(); }

    if (null != statement)
      try { statement.close(); }
      catch (final SQLException e) { e.printStackTrace(); }

    if (null != connection)
      try { connection.close(); }
      catch (final SQLException e) { e.printStackTrace(); }
  }

  private void setParameters(final PreparedStatement statement, final Object... parameters) throws SQLException
  {
    for (int i = 0, length = parameters.length; i < length; i++)
    {
      final Object parameter = parameters[i];
      final int parameterIndex = i + 1;
      if (null == parameter)
      {
        statement.setObject(parameterIndex, null);
      }
      else if (parameter instanceof Boolean)
      {
        statement.setBoolean(parameterIndex, (Boolean) parameter);
      }
      else if (parameter instanceof Character)
      {
        statement.setString(parameterIndex, String.valueOf(parameter));
      }
      else if (parameter instanceof Byte)
      {
        statement.setByte(parameterIndex, (Byte) parameter);
      }
      else if (parameter instanceof Short)
      {
        statement.setShort(parameterIndex, (Short) parameter);
      }
      else if (parameter instanceof Integer)
      {
        statement.setInt(parameterIndex, (Integer) parameter);
      }
      else if (parameter instanceof Long)
      {
        statement.setLong(parameterIndex, (Long) parameter);
      }
      else if (parameter instanceof Float)
      {
        statement.setFloat(parameterIndex, (Float) parameter);
      }
      else if (parameter instanceof Double)
      {
        statement.setDouble(parameterIndex, (Double) parameter);
      }
      else if (parameter instanceof String)
      {
        statement.setString(parameterIndex, (String) parameter);
      }
      else if (parameter instanceof Date)
      {
        statement.setDate(parameterIndex, new java.sql.Date(((Date) parameter).getTime()));
      }
      else if (parameter instanceof Calendar)
      {
        statement.setDate(parameterIndex, new java.sql.Date(((Calendar) parameter).getTimeInMillis()));
      }
      else if (parameter instanceof BigDecimal)
      {
        statement.setBigDecimal(parameterIndex, (BigDecimal) parameter);
      }
      else
      {
        throw new IllegalArgumentException(String.format(
            "Unknown type of the parameter is found. [param: %s, paramIndex: %s]", parameter, parameterIndex));
      }
    }
  }

  @Override
  public <T> List<T> select(final String sql,
                            final RowMapper<T> rowMapper,
                            final Object... parameters)
      throws DataAccessException
  {
    Connection connection = null;
    PreparedStatement statement = null;
    ResultSet resultSet = null;

    final List<T> result = new ArrayList<T>();
    try
    {
      connection = getConnection();
      statement = connection.prepareStatement(sql);
      setParameters(statement, parameters);
      resultSet = statement.executeQuery();
      while (resultSet.next())
      {
        result.add(rowMapper.map(resultSet));
      }
    }
    catch (final SQLException e)
    {
      throw new DataAccessOperationErrorException(e);
    }
    finally
    {
      closeQuietly(connection, statement, resultSet);
    }
    return result;
  }

  // the rest code omitted...
}

Then my AbstractDao now has the JdbcManager.

package com.lckymn.kevin.tutorial.jdbc_better.dao;

import com.lckymn.kevin.tutorial.jdbc_better.jdbc.JdbcManager;

/**
 * @author Lee, SeongHyun (Kevin) / <a href="http://blog.lckymn.com">Kevin&#39;s Blog</a>
 * @version 0.0.1 (2011-09-04)
 */
public abstract class AbstractDao
{
  private JdbcManager jdbcManager;

  public AbstractDao(final JdbcManager jdbcManager)
  {
    this.jdbcManager = jdbcManager;
  }

  protected final JdbcManager jdbcManager()
  {
    return jdbcManager;
  }
}

So the old DAO methods now look like

@Override
public Person find(final Long id)
{
  final List<Person> result =
    jdbcManager().select("SELECT * FROM people WHERE person_id = ?", new RowMapper<Person>() {

      @Override
      public Person map(final ResultSet resultSet) throws SQLException
      {
        final Person person = new Person();
        person.setId(resultSet.getLong("person_id"));
        person.setSurname(resultSet.getString("surname"));
        person.setGivenName(resultSet.getString("given_name"));
        final Address address =
            new Address(resultSet.getString("street"),
                resultSet.getString("city"),
                resultSet.getString("state"),
                resultSet.getString("country"),
                resultSet.getString("postcode"));
        person.setAddress(address);
        person.setBirthday(new Date(resultSet
                              .getDate("birthday")
                              .getTime()));
        return person;
      }
    }, id);
  return result.isEmpty() ? null : result.get(0);
}

@Override
public List<Person> findPeopleByState(final String state)
{
  return jdbcManager().select("SELECT * FROM people WHERE state = ?", new RowMapper<Person>() {

    @Override
    public Person map(final ResultSet resultSet) throws SQLException
    {
      final Person person = new Person();
      person.setId(resultSet.getLong("person_id"));
      person.setSurname(resultSet.getString("surname"));
      person.setGivenName(resultSet.getString("given_name"));
      final Address address =
          new Address(resultSet.getString("street"),
              resultSet.getString("city"),
              resultSet.getString("state"),
              resultSet.getString("country"),
              resultSet.getString("postcode"));
      person.setAddress(address);
      person.setBirthday(new Date(resultSet
                            .getDate("birthday")
                            .getTime()));
      return person;
    }
  }, state);
}

Oh, I can see the RowMapper anonymous classes used in the both methods are the same therefore I can declare constant variable for it and both can just use it.
So my new PersonDaoImpl is

package com.lckymn.kevin.tutorial.jdbc_better.dao.impl;

import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Date;
import java.util.List;

import com.lckymn.kevin.tutorial.jdbc_better.beans.Address;
import com.lckymn.kevin.tutorial.jdbc_better.beans.Person;
import com.lckymn.kevin.tutorial.jdbc_better.dao.AbstractDao;
import com.lckymn.kevin.tutorial.jdbc_better.dao.PersonDao;
import com.lckymn.kevin.tutorial.jdbc_better.jdbc.JdbcManager;
import com.lckymn.kevin.tutorial.jdbc_better.jdbc.RowMapper;

/**
 * @author Lee, SeongHyun (Kevin) / <a href="http://blog.lckymn.com">Kevin&#39;s Blog</a>
 * @version 0.0.1 (2011-09-04)
 */
public class PersonDaoImpl extends AbstractDao implements PersonDao
{
  private static final RowMapper<Person> PERSON_MAPPER = new RowMapper<Person>() {
    @Override
    public Person map(final ResultSet resultSet) throws SQLException
    {
      final Person person = new Person();
      person.setId(resultSet.getLong("person_id"));
      person.setSurname(resultSet.getString("surname"));
      person.setGivenName(resultSet.getString("given_name"));
      final Address address =
          new Address(resultSet.getString("street"),
              resultSet.getString("city"),
              resultSet.getString("state"),
              resultSet.getString("country"),
              resultSet.getString("postcode"));
      person.setAddress(address);
      person.setBirthday(new Date(resultSet
                            .getDate("birthday")
                            .getTime()));
      return person;
    }
  };

  public PersonDaoImpl(final JdbcManager jdbcManager)
  {
    super(jdbcManager);
  }

  @Override
  public Person find(final Long id)
  {
    final List<Person> result = jdbcManager().select("SELECT * FROM people WHERE person_id = ?", PERSON_MAPPER, id);
    return result.isEmpty() ? null : result.get(0);
  }

  @Override
  public List<Person> findPeopleByState(final String state)
  {
    return jdbcManager().select("SELECT * FROM people WHERE state = ?", PERSON_MAPPER, state);
  }

  @Override
  public List<Person> getAllPeople()
  {
    return jdbcManager().select("SELECT * FROM people", PERSON_MAPPER);
  }
}

Wow! It’s really simple now! Just passing an SQL query and parameters with a RowMapper.

OK, it’s good, but what happens if I want to insert or update or delete data from the database? The JdbcManager interface has the method signature for these but how can I implement it?
It would be simple too.

private void rollback(final Connection connection)
{
  if (null != connection)
  {
    try
    {
      connection.rollback();
    }
    catch (final SQLException e)
    {
      e.printStackTrace();
    }
  }
}

@Override
public int update(final String sql, final Object... parameters)
    throws DataAccessException
{
  Connection connection = null;
  PreparedStatement statement = null;

  try
  {
    connection = getConnection();
    connection.setAutoCommit(false);
    statement = connection.prepareStatement(sql);
    setParameters(statement, parameters);
    final int result = statement.executeUpdate();
    connection.commit();
    return result;
  }
  catch (final DataAccessException e)
  {
    rollback(connection);
    throw e;
  }
  catch (final Exception e)
  {
    rollback(connection);
    throw new DataAccessOperationErrorException(e);
  }
  finally
  {
    closeQuietly(connection, statement, null);
  }
}

Turn off auto commit so the changes can be rolled back if any Exception is thrown.

There is still room for improvement in JdbcManagerImpl. Instead of having the setParameters() method to set parameter values to the Statement, Strategy pattern can be used so that the user of JdbcManager can later inject an object that sets the parameters so how to handle the parameters can be decided by the user of the API.

package com.lckymn.kevin.tutorial.jdbc_better.jdbc;

import java.sql.PreparedStatement;
import java.sql.SQLException;

/**
 * @author Lee, SeongHyun (Kevin) / <a href="http://blog.lckymn.com">Kevin&#39;s Blog</a>
 * @version 0.0.1 (2011-09-04)
 */
public interface PreparedStatementParameterSetter
{
  void setParameters(final PreparedStatement statement, final Object... parameters) throws SQLException;
}
public class JdbcManagerImpl implements JdbcManager
{
  private final DataSource dataSource;
  private final PreparedStatementParameterSetter preparedStatementParameterSetter;

  public JdbcManagerImpl(DataSource dataSource, PreparedStatementParameterSetter preparedStatementParameterSetter)
  {
    this.dataSource = dataSource;
    this.preparedStatementParameterSetter = preparedStatementParameterSetter;
  }

  // code omitted...

  @Override
  public <T> List<T> select(final String sql,
                            final RowMapper<T> rowMapper,
                            final Object... parameters)
      throws DataAccessException
  {
    Connection connection = null;
    PreparedStatement statement = null;
    ResultSet resultSet = null;

    final List<T> result = new ArrayList<T>();
    try
    {
      connection = getConnection();
      statement = connection.prepareStatement(sql);
      preparedStatementParameterSetter.setParameters(statement, parameters);
      resultSet = statement.executeQuery();
      while (resultSet.next())
      {
        result.add(rowMapper.map(resultSet));
      }
    }
    catch (final SQLException e)
    {
      throw new DataAccessOperationErrorException(e);
    }
    finally
    {
      closeQuietly(connection, statement, resultSet);
    }
    return result;
  }
  
  // ... the rest omitted.
}

I think it’s enough to learn the better way to use JDBC. What I’ve explained here can be useful for solving other problems too (e.g. reading and writing files).
The code I’ve posted here is not production-ready. It’s solely for educational purpose. If you want to use it in practice, I recommend already existing libraries and frameworks which provide what I’ve explained here. These are well tested so are likely to be better than my in-house JdbcManager. If you use or are willing to use the Spring Framework, you can use its JdbcTemplate. If you don’t or cannot use the Spring Framework, you can choose Apache Commons DbUtils.

=================================================================
The source code of “Easier and Better Way to Use JDBC” is available ->HERE<-.

© 2014 Kevin's Blog

Theme by Anders NorenUp ↑

%d bloggers like this: