3 Replies Latest reply: Jun 14, 2010 3:12 PM by 843793 RSS

    Typesafe hetergeneous map to collection

    843793
      I was trying to work out a variant of the Bruce Eckel's Typesafe Heterogeneous Container pattern where the map retrieved a collection of a given type. This works if I fix the collection type:
      public class Favorites
      {
          private Map<Class<?>, Set<?>> favorites =
                  new HashMap<Class<?>, Set<?>>();
      
          public <T> void setFavorite(Class<T> klass, Set<T> thing)
          {
              favorites.put(klass, thing);
          }
      
          @SuppressWarnings({"unchecked"})
          public <T> Set<T> getFavorite(Class<T> klass)
          {
              return (Set<T>) favorites.get(klass);
          }
      
          public static void main(String[] args)
          {
              Favorites f = new Favorites();
              final HashSet<String> strings = new HashSet<String>();
              strings.add("Java"); strings.add("Code");
              f.setFavorite(String.class, strings);
              final HashSet<Integer> ints = new HashSet<Integer>();
              ints.add(0xcafebabe); ints.add(1);
              f.setFavorite(Integer.class, ints);
              Set<String> s = f.getFavorite(String.class);
              System.out.println(s);
              Set<Integer> i = f.getFavorite(Integer.class);
              System.out.println(i);
          }
      }
      but I would like to do something where I can parametrize Favorites on the collections class:
      public class Favorites<C extends Collection<?>>
      {
          private Map<Class<?>, C<?>> favorites =
                  new HashMap<Class<?>, C<?>>();
      
          public <T> void setFavorite(Class<T> klass, C<T> thing)
          {
              favorites.put(klass, thing);
          }
      
          @SuppressWarnings({"unchecked"})
          public <T> C<T> getFavorite(Class<T> klass)
          {
              return (C<T>) favorites.get(klass);
          }
      
          public static void main(String[] args)
          {
              Favorites<Set> f = new Favorites<Set>();
              final HashSet<String> strings = new HashSet<String>();
              strings.add("Java"); strings.add("Code");
              f.setFavorite(String.class, strings);
              final HashSet<Integer> ints = new HashSet<Integer>();
              ints.add(0xcafebabe); ints.add(1);
              f.setFavorite(Integer.class, ints);
              Set<String> s = f.getFavorite(String.class);
              System.out.println(s);
              Set<Integer> i = f.getFavorite(Integer.class);
              System.out.println(i);
          }
      }
      However this won't compile because the compiler doesn't expect that "C" can itself take type parameters, even though I specified that it extended Collection<?>.
      Is there any way to generify Favorites over the Collection class?
        • 1. Re: Typesafe hetergeneous map to collection
          843793
          Hello ross@apl,

          you may want look into [Super Type Tokens|http://gafter.blogspot.com/2006/12/super-type-tokens.html], but be aware of [their limitations|http://gafter.blogspot.com/2007/05/limitation-of-super-type-tokens.html].

          With kind regards
          Ben
          • 2. Re: Typesafe hetergeneous map to collection
            843793
            BenSchulz wrote:
            you may want look into [Super Type Tokens|http://gafter.blogspot.com/2006/12/super-type-tokens.html], but be aware of [their limitations|http://gafter.blogspot.com/2007/05/limitation-of-super-type-tokens.html].
            That is really cool Ben. I never considered forcing reification through an abstract class and anonymous inner subclasses before.

            I love Gafter. Most of the time I read something of his it's in the context of a smelly design (well, to be fair, most of what I've read comes from his puzzlers) but even so, without fail it leaves me with more insight into the language.
            • 3. Re: Typesafe hetergeneous map to collection
              843793
              Google's Guice 2.0 framework has a TypeLiteral that fits the bill pretty well. There is something similar in jQuantlib, which actually seems to detect for the "Oops" in one of Gafter's examples, that is where another layer of abstraction results in the SuperTypeToken containing an abstract type variable (e.g. "T"). This could lead to multiple tokens being equal when they were intended to be different. I went with the Guice framework, since it seems to have other utilities I may want. In this case I construct the TypeLiteral with a Set (or other collection) parametrized with the desired element.

              The construct I described would have been more useful, and I'm still curious about specifying that a type variable can itself take type parameters.