001    package fj;
002    
003    import fj.data.List;
004    import static fj.data.List.unfold;
005    import fj.data.Option;
006    import static fj.data.Option.none;
007    import static fj.data.Option.some;
008    import fj.data.Tree;
009    
010    import java.lang.reflect.ParameterizedType;
011    import java.lang.reflect.Type;
012    
013    /**
014     * A wrapper for a {@link java.lang.Class} that provides additional methods.
015     *
016     * @version %build.number%<br>
017     *          <ul>
018     *          <li>$LastChangedRevision: 122 $</li>
019     *          <li>$LastChangedDate: 2009-04-25 08:24:38 +1000 (Sat, 25 Apr 2009) $</li>
020     *          </ul>
021     */
022    public final class Class<T> {
023      private final java.lang.Class<T> c;
024    
025      private Class(final java.lang.Class<T> c) {
026        this.c = c;
027      }
028    
029      /**
030       * Returns the inheritance hierarchy of this class.
031       *
032       * @return The inheritance hierarchy of this class.
033       */
034      public List<Class<? super T>> inheritance() {
035        return unfold(
036            new F<java.lang.Class<? super T>, Option<P2<java.lang.Class<? super T>, java.lang.Class<? super T>>>>() {
037              public Option<P2<java.lang.Class<? super T>, java.lang.Class<? super T>>> f(
038                  final java.lang.Class<? super T> c) {
039                if (c == null)
040                  return none();
041                else {
042                  final P2<java.lang.Class<? super T>, java.lang.Class<? super T>> p =
043                      new P2<java.lang.Class<? super T>, java.lang.Class<? super T>>() {
044                        public java.lang.Class<? super T> _1() {
045                          return c;
046                        }
047    
048                        @SuppressWarnings({"unchecked"})
049                        public java.lang.Class<? super T> _2() {
050                          return c.getSuperclass();
051                        }
052                      };
053                  return some(p);
054                }
055              }
056            }, c).map(new F<java.lang.Class<? super T>, Class<? super T>>() {
057          public Class<? super T> f(final java.lang.Class<? super T> c) {
058            return clas(c);
059          }
060        });
061      }
062    
063      /**
064       * Provides this class's type parameter information as a Tree of the type expression.
065       * Only descends into Parameterized classes. Non-abstract classes, or classes that don't implement an interface,
066       * are treated as raw types. Arrays, Type Variables, and Wildcards are treated as opaque Types.
067       *
068       * @return The rose tree representing the type expression for this class.
069       */
070      public Tree<Type> classParameters() {
071        return typeParameterTree(c);
072      }
073    
074      /**
075       * Provides this class's superclass type parameter information as a Tree of the type expression.
076       * Only descends into Parameterized classes. Non-abstract classes, or classes that don't implement an interface,
077       * are treated as raw types. Arrays, Type Variables, and Wildcards are treated as opaque Types.
078       *
079       * @return The Tree representing the type expression for this class's superclass.
080       */
081      public Tree<Type> superclassParameters() {
082        return typeParameterTree(c.getGenericSuperclass());
083      }
084    
085      /**
086       * Provides this class's interface type parameter information as a list of trees.
087       *
088       * @return A list of trees representing the type expressions for this class's interfaces.
089       */
090      public List<Tree<Type>> interfaceParameters() {
091        List<Tree<Type>> ts = List.nil();
092        for (final Type t : c.getInterfaces()) {
093          ts = ts.snoc(typeParameterTree(t));
094        }
095        return ts;
096      }
097    
098      /**
099       * Provides type parameter information as a Tree of the type expression.
100       * Only descends into Parameterized classes. Non-abstract classes, or classes that don't implement an interface,
101       * are treated as raw types. Arrays, Type Variables, and Wildcards are treated as opaque Types.
102       *
103       * @param t The type (class) for which to get the generic type information.
104       * @return Type parameter information as a rose tree of the type expression.
105       */
106      public static Tree<Type> typeParameterTree(final Type t) {
107        List<Tree<Type>> typeArgs = List.nil();
108        final Tree<Type> types;
109        if (t instanceof ParameterizedType) {
110          final ParameterizedType pt = (ParameterizedType) t;
111          for (final Type arg : pt.getActualTypeArguments()) {
112            typeArgs = typeArgs.snoc(typeParameterTree(arg));
113          }
114          types = Tree.node(pt.getRawType(), typeArgs);
115        } else {
116          types = Tree.node(t, List.<Tree<Type>>nil());
117        }
118        return types;
119      }
120    
121      /**
122       * Returns the underlying class.
123       *
124       * @return The underlying class.
125       */
126      public java.lang.Class<T> clas() {
127        return c;
128      }
129    
130      /**
131       * Constructs a class from the given argument.
132       *
133       * @param c The argument to construct this class with.
134       * @return A class from the given argument.
135       */
136      public static <T> Class<T> clas(final java.lang.Class<T> c) {
137        return new Class<T>(c);
138      }
139    }