Stuart McCulloch | bb01437 | 2012-06-07 21:57:32 +0000 | [diff] [blame] | 1 | package aQute.bnd.compatibility; |
| 2 | |
| 3 | import java.lang.reflect.*; |
| 4 | |
| 5 | public class RuntimeSignatureBuilder { |
| 6 | final Scope root; |
| 7 | |
| 8 | public RuntimeSignatureBuilder(Scope root) { |
| 9 | this.root = root; |
| 10 | } |
| 11 | |
Stuart McCulloch | 2286f23 | 2012-06-15 13:27:53 +0000 | [diff] [blame^] | 12 | static public String identity(Class< ? > c) { |
Stuart McCulloch | bb01437 | 2012-06-07 21:57:32 +0000 | [diff] [blame] | 13 | return Scope.classIdentity(c.getName()); |
| 14 | } |
| 15 | |
| 16 | static public String identity(Method m) { |
Stuart McCulloch | 2286f23 | 2012-06-15 13:27:53 +0000 | [diff] [blame^] | 17 | return Scope.methodIdentity(m.getName(), getDescriptor(m.getReturnType(), m.getParameterTypes())); |
Stuart McCulloch | bb01437 | 2012-06-07 21:57:32 +0000 | [diff] [blame] | 18 | } |
| 19 | |
Stuart McCulloch | 2286f23 | 2012-06-15 13:27:53 +0000 | [diff] [blame^] | 20 | static public String identity(Constructor< ? > m) { |
Stuart McCulloch | bb01437 | 2012-06-07 21:57:32 +0000 | [diff] [blame] | 21 | return Scope.constructorIdentity(getDescriptor(void.class, m.getParameterTypes())); |
| 22 | } |
| 23 | |
| 24 | static public String identity(Field m) { |
| 25 | return Scope.fieldIdentity(m.getName(), getDescriptor(m.getType(), null)); |
| 26 | } |
| 27 | |
Stuart McCulloch | 2286f23 | 2012-06-15 13:27:53 +0000 | [diff] [blame^] | 28 | static public String getDescriptor(Class< ? > base, Class< ? >[] parameters) { |
Stuart McCulloch | bb01437 | 2012-06-07 21:57:32 +0000 | [diff] [blame] | 29 | StringBuilder sb = new StringBuilder(); |
| 30 | if (parameters != null) { |
| 31 | sb.append("("); |
Stuart McCulloch | 2286f23 | 2012-06-15 13:27:53 +0000 | [diff] [blame^] | 32 | for (Class< ? > parameter : parameters) { |
Stuart McCulloch | bb01437 | 2012-06-07 21:57:32 +0000 | [diff] [blame] | 33 | sb.append(getDescriptor(parameter)); |
| 34 | } |
| 35 | sb.append(")"); |
| 36 | } |
| 37 | sb.append(getDescriptor(base)); |
| 38 | return sb.toString(); |
| 39 | } |
| 40 | |
Stuart McCulloch | 2286f23 | 2012-06-15 13:27:53 +0000 | [diff] [blame^] | 41 | public Scope add(Class< ? > c) { |
| 42 | Scope local = add(root, getEnclosingScope(c), c.getModifiers(), c.getTypeParameters(), Kind.CLASS, identity(c), |
| 43 | c.getGenericSuperclass(), c.getGenericInterfaces(), null); |
Stuart McCulloch | bb01437 | 2012-06-07 21:57:32 +0000 | [diff] [blame] | 44 | |
| 45 | for (Field f : c.getDeclaredFields()) { |
| 46 | add(local, // declaring scope |
| 47 | local, // enclosing |
| 48 | f.getModifiers(), // access modifiers |
| 49 | null, // fields have no type vars |
| 50 | Kind.FIELD, // field |
| 51 | identity(f), // the name of the field |
| 52 | f.getGenericType(), // the type of the field |
| 53 | null, // fields have no parameters |
| 54 | null // fields have no exceptions |
| 55 | ); |
| 56 | } |
| 57 | |
Stuart McCulloch | 2286f23 | 2012-06-15 13:27:53 +0000 | [diff] [blame^] | 58 | for (Constructor< ? > constr : c.getConstructors()) { |
Stuart McCulloch | bb01437 | 2012-06-07 21:57:32 +0000 | [diff] [blame] | 59 | add(local, // class scope |
| 60 | local, // enclosing |
| 61 | constr.getModifiers(), // access modifiers |
| 62 | constr.getTypeParameters(), // Type vars |
| 63 | Kind.CONSTRUCTOR, // constructor |
| 64 | identity(constr), // <init>(type*) |
| 65 | void.class, // Always void |
| 66 | constr.getGenericParameterTypes(), // parameters types |
| 67 | constr.getGenericExceptionTypes() // exception types |
| 68 | ); |
| 69 | } |
| 70 | |
| 71 | for (Method m : c.getDeclaredMethods()) { |
| 72 | if (m.getDeclaringClass() != Object.class) { |
| 73 | add(local, // class scope |
| 74 | local, // enclosing |
| 75 | m.getModifiers(), // access modifiers |
| 76 | m.getTypeParameters(), Kind.METHOD, // method |
| 77 | identity(m), // <name>(type*)return |
| 78 | m.getGenericReturnType(), // return type |
| 79 | m.getGenericParameterTypes(), // parameter types |
| 80 | m.getGenericExceptionTypes() // exception types |
| 81 | ); |
| 82 | } |
| 83 | } |
| 84 | |
| 85 | return local; |
| 86 | } |
| 87 | |
Stuart McCulloch | 2286f23 | 2012-06-15 13:27:53 +0000 | [diff] [blame^] | 88 | private Scope getEnclosingScope(Class< ? > c) { |
Stuart McCulloch | bb01437 | 2012-06-07 21:57:32 +0000 | [diff] [blame] | 89 | Method m = c.getEnclosingMethod(); |
| 90 | if (m != null) { |
| 91 | Scope s = getGlobalScope(m.getDeclaringClass()); |
| 92 | return s.getScope(identity(m)); |
| 93 | } |
Stuart McCulloch | 2286f23 | 2012-06-15 13:27:53 +0000 | [diff] [blame^] | 94 | // TODO |
| 95 | // Constructor cnstr = c.getEnclosingConstructor(); |
| 96 | // if (m != null) { |
| 97 | // Scope s = getGlobalScope(cnstr.getDeclaringClass()); |
| 98 | // return s.getScope(identity(cnstr)); |
| 99 | // |
| 100 | // } |
| 101 | Class< ? > enclosingClass = c.getEnclosingClass(); |
Stuart McCulloch | bb01437 | 2012-06-07 21:57:32 +0000 | [diff] [blame] | 102 | if (enclosingClass != null) { |
| 103 | return getGlobalScope(enclosingClass); |
| 104 | } |
| 105 | |
| 106 | return null; |
| 107 | } |
| 108 | |
Stuart McCulloch | 2286f23 | 2012-06-15 13:27:53 +0000 | [diff] [blame^] | 109 | private Scope getGlobalScope(Class< ? > c) { |
Stuart McCulloch | bb01437 | 2012-06-07 21:57:32 +0000 | [diff] [blame] | 110 | if (c == null) |
| 111 | return null; |
| 112 | String id = identity(c); |
| 113 | return root.getScope(id); |
| 114 | } |
| 115 | |
Stuart McCulloch | 2286f23 | 2012-06-15 13:27:53 +0000 | [diff] [blame^] | 116 | private Scope add(Scope declaring, Scope enclosing, int modifiers, TypeVariable< ? >[] typeVariables, Kind kind, |
| 117 | String id, Type mainType, Type[] parameterTypes, Type exceptionTypes[]) { |
Stuart McCulloch | bb01437 | 2012-06-07 21:57:32 +0000 | [diff] [blame] | 118 | |
| 119 | Scope scope = declaring.getScope(id); |
| 120 | assert scope.access == Access.UNKNOWN; |
| 121 | scope.setAccess(Access.modifier(modifiers)); |
| 122 | scope.setKind(kind); |
| 123 | scope.setGenericParameter(convert(typeVariables)); |
Stuart McCulloch | 2286f23 | 2012-06-15 13:27:53 +0000 | [diff] [blame^] | 124 | scope.setBase(convert(scope, mainType)); |
Stuart McCulloch | bb01437 | 2012-06-07 21:57:32 +0000 | [diff] [blame] | 125 | scope.setParameterTypes(convert(parameterTypes)); |
| 126 | scope.setExceptionTypes(convert(exceptionTypes)); |
| 127 | scope.setDeclaring(declaring); |
| 128 | scope.setEnclosing(enclosing); |
| 129 | return scope; |
| 130 | } |
| 131 | |
| 132 | private GenericType convert(Scope source, Type t) { |
| 133 | if (t instanceof ParameterizedType) { |
| 134 | // C<P..> |
| 135 | ParameterizedType pt = (ParameterizedType) t; |
Stuart McCulloch | 2286f23 | 2012-06-15 13:27:53 +0000 | [diff] [blame^] | 136 | /* Scope reference = */root.getScope(identity((Class< ? >) pt.getRawType())); |
Stuart McCulloch | bb01437 | 2012-06-07 21:57:32 +0000 | [diff] [blame] | 137 | Type args[] = pt.getActualTypeArguments(); |
| 138 | GenericType[] arguments = new GenericType[args.length]; |
| 139 | int n = 0; |
| 140 | for (Type arg : args) |
Stuart McCulloch | 2286f23 | 2012-06-15 13:27:53 +0000 | [diff] [blame^] | 141 | arguments[n++] = convert(source, arg); |
| 142 | // return new GenericType(reference,null,arguments); |
| 143 | |
Stuart McCulloch | bb01437 | 2012-06-07 21:57:32 +0000 | [diff] [blame] | 144 | } else if (t instanceof TypeVariable) { |
Stuart McCulloch | 2286f23 | 2012-06-15 13:27:53 +0000 | [diff] [blame^] | 145 | // TypeVariable tv = (TypeVariable) t; |
| 146 | // return new GenericType(source,tv.getName(), null); |
Stuart McCulloch | bb01437 | 2012-06-07 21:57:32 +0000 | [diff] [blame] | 147 | } else if (t instanceof WildcardType) { |
Stuart McCulloch | 2286f23 | 2012-06-15 13:27:53 +0000 | [diff] [blame^] | 148 | // WildcardType wc = (WildcardType) t; |
| 149 | // wc. |
Stuart McCulloch | bb01437 | 2012-06-07 21:57:32 +0000 | [diff] [blame] | 150 | } else if (t instanceof GenericArrayType) { |
| 151 | |
| 152 | } |
Stuart McCulloch | 2286f23 | 2012-06-15 13:27:53 +0000 | [diff] [blame^] | 153 | if (t instanceof Class< ? >) { |
| 154 | // raw = ((Class<?>) t).getName() + ";"; |
Stuart McCulloch | bb01437 | 2012-06-07 21:57:32 +0000 | [diff] [blame] | 155 | } else |
| 156 | throw new IllegalArgumentException(t.toString()); |
| 157 | |
| 158 | return null; |
| 159 | } |
| 160 | |
Stuart McCulloch | 2286f23 | 2012-06-15 13:27:53 +0000 | [diff] [blame^] | 161 | private GenericParameter[] convert(TypeVariable< ? > vars[]) { |
Stuart McCulloch | bb01437 | 2012-06-07 21:57:32 +0000 | [diff] [blame] | 162 | if (vars == null) |
| 163 | return null; |
| 164 | |
| 165 | GenericParameter out[] = new GenericParameter[vars.length]; |
| 166 | for (int i = 0; i < vars.length; i++) { |
| 167 | GenericType gss[] = convert(vars[i].getBounds()); |
| 168 | out[i] = new GenericParameter(vars[i].getName(), gss); |
| 169 | } |
| 170 | return out; |
| 171 | } |
| 172 | |
| 173 | private GenericType[] convert(Type[] parameterTypes) { |
| 174 | if (parameterTypes == null || parameterTypes.length == 0) |
| 175 | return GenericType.EMPTY; |
| 176 | |
| 177 | GenericType tss[] = new GenericType[parameterTypes.length]; |
| 178 | for (int i = 0; i < parameterTypes.length; i++) { |
Stuart McCulloch | 2286f23 | 2012-06-15 13:27:53 +0000 | [diff] [blame^] | 179 | // tss[i] = new GenericType(parameterTypes[i]); |
Stuart McCulloch | bb01437 | 2012-06-07 21:57:32 +0000 | [diff] [blame] | 180 | } |
| 181 | return tss; |
| 182 | } |
| 183 | |
Stuart McCulloch | 2286f23 | 2012-06-15 13:27:53 +0000 | [diff] [blame^] | 184 | private static String getDescriptor(Class< ? > c) { |
Stuart McCulloch | bb01437 | 2012-06-07 21:57:32 +0000 | [diff] [blame] | 185 | StringBuilder sb = new StringBuilder(); |
| 186 | if (c.isPrimitive()) { |
| 187 | if (c == boolean.class) |
| 188 | sb.append("Z"); |
| 189 | else if (c == byte.class) |
| 190 | sb.append("Z"); |
| 191 | else if (c == char.class) |
| 192 | sb.append("C"); |
| 193 | else if (c == short.class) |
| 194 | sb.append("S"); |
| 195 | else if (c == int.class) |
| 196 | sb.append("I"); |
| 197 | else if (c == long.class) |
| 198 | sb.append("J"); |
| 199 | else if (c == float.class) |
| 200 | sb.append("F"); |
| 201 | else if (c == double.class) |
| 202 | sb.append("D"); |
| 203 | else if (c == void.class) |
| 204 | sb.append("V"); |
| 205 | else |
| 206 | throw new IllegalArgumentException("unknown primitive type: " + c); |
| 207 | } else if (c.isArray()) { |
| 208 | sb.append("["); |
| 209 | sb.append(getDescriptor(c)); |
| 210 | } else { |
| 211 | sb.append("L"); |
| 212 | sb.append(c.getName().replace('.', '/')); |
| 213 | sb.append(";"); |
| 214 | } |
| 215 | return sb.toString(); |
| 216 | } |
| 217 | |
| 218 | } |