001 /* 002 * Copyright (C) 2010 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 026 /** 027 * @author <a href="mailto:julien.viet@exoplatform.com">Julien Viet</a> 028 * @version $Revision$ 029 */ 030 public class TypeResolver { 031 032 public static Class<?> resolveToClass(Type implementation, Class<?> type, int parameterIndex) { 033 if (implementation == null) { 034 throw new NullPointerException("No null type accepted"); 035 } 036 037 // First resolve to type 038 Type resolvedType = resolve(implementation, type, parameterIndex); 039 040 // 041 if (resolvedType != null) { 042 return resolveToClass(resolvedType); 043 } else { 044 return null; 045 } 046 } 047 048 public static Class resolveToClass(Type type) { 049 if (type == null) { 050 throw new NullPointerException("No null type accepted"); 051 } 052 if (type instanceof Class<?>) { 053 return (Class<?>)type; 054 } else if (type instanceof TypeVariable) { 055 TypeVariable resolvedTypeVariable = (TypeVariable)type; 056 return resolveToClass(resolvedTypeVariable.getBounds()[0]); 057 } else { 058 throw new UnsupportedOperationException("Type resolution of " + type + " not yet implemented"); 059 } 060 } 061 062 /** 063 * A simplistic implementation, it may not handle all cases but it should handle enough. 064 * 065 * @param implementation the type for which the parameter requires a resolution 066 * @param type the type that owns the parameter 067 * @param parameterIndex the parameter index 068 * @return the resolved type 069 */ 070 public static Type resolve(Type implementation, Class<?> type, int parameterIndex) { 071 if (implementation == null) { 072 throw new NullPointerException(); 073 } 074 075 // 076 if (implementation == type) { 077 TypeVariable<? extends Class<?>>[] tp = type.getTypeParameters(); 078 if (parameterIndex < tp.length) { 079 return tp[parameterIndex]; 080 } else { 081 throw new IllegalArgumentException(); 082 } 083 } else if (implementation instanceof Class<?>) { 084 Class<?> c = (Class<?>) implementation; 085 Type gsc = c.getGenericSuperclass(); 086 Type resolved = null; 087 if (gsc != null) { 088 resolved = resolve(gsc, type, parameterIndex); 089 if (resolved == null) { 090 // Try with interface 091 } 092 } 093 return resolved; 094 } else if (implementation instanceof ParameterizedType) { 095 ParameterizedType pt = (ParameterizedType) implementation; 096 Type[] typeArgs = pt.getActualTypeArguments(); 097 Type rawType = pt.getRawType(); 098 if (rawType == type) { 099 return typeArgs[parameterIndex]; 100 } else if (rawType instanceof Class<?>) { 101 Class<?> classRawType = (Class<?>)rawType; 102 Type resolved = resolve(classRawType, type, parameterIndex); 103 if (resolved == null) { 104 return null; 105 } else if (resolved instanceof TypeVariable) { 106 TypeVariable resolvedTV = (TypeVariable)resolved; 107 TypeVariable[] a = classRawType.getTypeParameters(); 108 for (int i = 0;i < a.length;i++) { 109 if (a[i].equals(resolvedTV)) { 110 return resolve(implementation, classRawType, i); 111 } 112 } 113 throw new AssertionError(); 114 } else { 115 throw new UnsupportedOperationException("Cannot support resolution of " + resolved); 116 } 117 } else { 118 throw new UnsupportedOperationException(); 119 } 120 } else { 121 throw new UnsupportedOperationException("todo " + implementation + " " + implementation.getClass()); 122 } 123 } 124 }