Tuesday, January 12, 2010

Class token nuisance

Fabrizio Giudici posts a nice description of type-safe map keys, a clever way to simplify life for an API user.

It exposes one of the nuisances of class tokens:

@Nonnull
public <T> T get (final @Nonnull Key<T> key)
  throws NotFoundException
  {
    return NotFoundException.throwWhenNull(
        (T)itemMap.get(key), "Not found: " + key);
  }

(Kudos to him for using JSR-305 annotations.)

See the cast (T)? That generates a compile-time warning (link just one of many complaints around this). The correct way to get ride of this warning is to use a class token:

@Nonnull
public <T> T get (final @Nonnull Key<T> key)
  throws NotFoundException
  {
    return NotFoundException.throwWhenNull(
        key.cast(itemMap.get(key)), "Not found: " + key);
  }

Where the Key<T> type is redefined:

@Immutable
public final static class Key<T>
    implements Comparable<Key<T>>
  {
    @Nonnull
    private final String name;
    @Nonnull
    private final Class<T> type;

    protected Key (final @Nonnull String name, final @Nonnull Class<T> type)
      {
        this.name = name;
        this.type = type;
      }

    public T cast(final Object that)
      {
        return type.cast(that);
      }

    @Override
    public int compareTo (final @Nonnull Key<T> other) { ... }

    @Override
    public boolean equals (final @CheckForNull Object object) { ... }

    @Override
    public int hashCode() { ... }
  }

What a nuisance.

No comments: