001    /*
002     * Copyright (C) 2012 eXo Platform SAS.
003     *
004     * This is free software; you can redistribute it and/or modify it
005     * under the terms of the GNU Lesser General Public License as
006     * published by the Free Software Foundation; either version 2.1 of
007     * the License, or (at your option) any later version.
008     *
009     * This software is distributed in the hope that it will be useful,
010     * but WITHOUT ANY WARRANTY; without even the implied warranty of
011     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
012     * Lesser General Public License for more details.
013     *
014     * You should have received a copy of the GNU Lesser General Public
015     * License along with this software; if not, write to the Free
016     * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
017     * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
018     */
019    
020    package org.crsh.util;
021    
022    import java.lang.reflect.ParameterizedType;
023    import java.lang.reflect.Type;
024    import java.lang.reflect.TypeVariable;
025    import java.util.List;
026    
027    public class TypeResolver {
028    
029      public static Class<?> resolveToClass(Type implementation, Class<?> type, int parameterIndex) {
030        if (implementation == null) {
031          throw new NullPointerException("No null type accepted");
032        }
033    
034        // First resolve to type
035        Type resolvedType = resolve(implementation, type, parameterIndex);
036    
037        //
038        if (resolvedType != null) {
039          return resolveToClass(resolvedType);
040        } else {
041          return null;
042        }
043      }
044    
045      public static Class resolveToClass(Type type) {
046        if (type == null) {
047          throw new NullPointerException("No null type accepted");
048        }
049        if (type instanceof Class<?>) {
050          return (Class<?>)type;
051        } else if (type instanceof TypeVariable) {
052          TypeVariable resolvedTypeVariable = (TypeVariable)type;
053          return resolveToClass(resolvedTypeVariable.getBounds()[0]);
054        } else {
055          throw new UnsupportedOperationException("Type resolution of " + type + " not yet implemented");
056        }
057      }
058    
059      /**
060       * A simplistic implementation, it may not handle all cases but it should handle enough.
061       *
062       * @param implementation the type for which the parameter requires a resolution
063       * @param type the type that owns the parameter
064       * @param parameterIndex the parameter index
065       * @return the resolved type
066       */
067      public static Type resolve(Type implementation, Class<?> type, int parameterIndex) {
068        if (implementation == null) {
069          throw new NullPointerException();
070        }
071    
072        //
073        if (implementation == type) {
074          TypeVariable<? extends Class<?>>[] tp = type.getTypeParameters();
075          if (parameterIndex < tp.length) {
076            return tp[parameterIndex];
077          } else {
078            throw new IllegalArgumentException();
079          }
080        } else if (implementation instanceof Class<?>) {
081          Class<?> c = (Class<?>) implementation;
082          Type gsc = c.getGenericSuperclass();
083          Type resolved = null;
084          if (gsc != null) {
085            resolved = resolve(gsc, type, parameterIndex);
086            if (resolved == null) {
087              // Try with interface
088            }
089          }
090          return resolved;
091        } else if (implementation instanceof ParameterizedType) {
092          ParameterizedType pt = (ParameterizedType) implementation;
093          Type[] typeArgs = pt.getActualTypeArguments();
094          Type rawType = pt.getRawType();
095          if (rawType == type) {
096            return typeArgs[parameterIndex];
097          } else if (rawType instanceof Class<?>) {
098            Class<?> classRawType = (Class<?>)rawType;
099            Type resolved = resolve(classRawType, type, parameterIndex);
100            if (resolved == null) {
101              return null;
102            } else if (resolved instanceof TypeVariable) {
103              TypeVariable resolvedTV = (TypeVariable)resolved;
104              TypeVariable[] a = classRawType.getTypeParameters();
105              for (int i = 0;i < a.length;i++) {
106                if (a[i].equals(resolvedTV)) {
107                  return resolve(implementation, classRawType, i);
108                }
109              }
110              throw new AssertionError();
111            } else {
112              throw new UnsupportedOperationException("Cannot support resolution of " + resolved);
113            }
114          } else {
115            throw new UnsupportedOperationException();
116          }
117        } else {
118          throw new UnsupportedOperationException("todo " + implementation + " " + implementation.getClass());
119        }
120      }
121    
122      public static boolean instanceOf(Class c, List<String> types) {
123    
124        for (String type: types) {
125          if (instanceOf(c, type)) {
126            return true;
127          }
128        }
129    
130        return false;
131    
132      }
133    
134    
135      public static boolean instanceOf(Class c, String type) {
136    
137        if (c.getName().equals(type)) {
138          return true;
139        }
140    
141        for (Class i : c.getInterfaces()) {
142          if (instanceOf(i, type)) {
143            return true;
144          }
145        }
146    
147        if (c.getSuperclass() != null) {
148          return instanceOf(c.getSuperclass(), type);
149        }
150    
151        return false;
152      }
153      
154    }