Coverage Report - org.mule.config.spring.util.ClassReader
 
Classes in this File Line Coverage Branch Coverage Complexity
ClassReader
0%
0/186
0%
0/87
0
ClassReader$NameAndType
0%
0/4
N/A
0
 
 1  
 /*
 2  
  * Copyright (c) MuleSoft, Inc.  All rights reserved.  http://www.mulesoft.com
 3  
  * The software in this package is published under the terms of the CPAL v1.0
 4  
  * license, a copy of which has been included with this distribution in the
 5  
  * LICENSE.txt file.
 6  
  */
 7  
 package org.mule.config.spring.util;
 8  
 
 9  
 import java.io.ByteArrayInputStream;
 10  
 import java.io.ByteArrayOutputStream;
 11  
 import java.io.EOFException;
 12  
 import java.io.IOException;
 13  
 import java.io.InputStream;
 14  
 import java.lang.reflect.Constructor;
 15  
 import java.lang.reflect.Field;
 16  
 import java.lang.reflect.InvocationTargetException;
 17  
 import java.lang.reflect.Member;
 18  
 import java.lang.reflect.Method;
 19  
 import java.util.HashMap;
 20  
 import java.util.Map;
 21  
 
 22  
 /**
 23  
  * This is the class file reader for obtaining the parameter names for declared
 24  
  * methods in a class. The class must have debugging attributes for us to obtain
 25  
  * this information.
 26  
  * <p>
 27  
  * This does not work for inherited methods. To obtain parameter names for
 28  
  * inherited methods, you must use a paramReader for the class that originally
 29  
  * declared the method.
 30  
  * <p>
 31  
  * don't get tricky, it's the bare minimum. Instances of this class are not
 32  
  * threadsafe -- don't share them.
 33  
  * <p>
 34  
  * 
 35  
  * @author Edwin Smith, Macromedia
 36  
  */
 37  
 public class ClassReader extends ByteArrayInputStream {
 38  
     // constants values that appear in java class files,
 39  
     // from jvm spec 2nd ed, section 4.4, pp 103
 40  
     private static final int CONSTANT_CLASS = 7;
 41  
     private static final int CONSTANT_FIELDREF = 9;
 42  
     private static final int CONSTANT_METHODREF = 10;
 43  
     private static final int CONSTANT_INTERFACE_METHOD_REF = 11;
 44  
     private static final int CONSTANT_STRING = 8;
 45  
     private static final int CONSTANT_INTEGER = 3;
 46  
     private static final int CONSTANT_FLOAT = 4;
 47  
     private static final int CONSTANT_LONG = 5;
 48  
     private static final int CONSTANT_DOUBLE = 6;
 49  
     private static final int CONSTANT_NAME_AND_TYPE = 12;
 50  
     private static final int CONSTANT_UTF_8 = 1;
 51  
     /**
 52  
      * the constant pool. constant pool indices in the class file directly index
 53  
      * into this array. The value stored in this array is the position in the
 54  
      * class file where that constant begins.
 55  
      */
 56  
     private int[] cpoolIndex;
 57  
     private Object[] cpool;
 58  
 
 59  
     private Map<String, Method> attrMethods;
 60  
 
 61  
     protected ClassReader(byte buf[], Map<String, Method> attrMethods) {
 62  0
         super(buf);
 63  
 
 64  0
         this.attrMethods = attrMethods;
 65  0
     }
 66  
     
 67  
     /**
 68  
      * load the bytecode for a given class, by using the class's defining
 69  
      * classloader and assuming that for a class named P.C, the bytecodes are in
 70  
      * a resource named /P/C.class.
 71  
      * 
 72  
      * @param c the class of interest
 73  
      * @return a byte array containing the bytecode
 74  
      * @throws IOException
 75  
      */
 76  
     protected static byte[] getBytes(Class c) throws IOException {
 77  0
         InputStream fin = c.getResourceAsStream('/' + c.getName().replace('.', '/') + ".class");
 78  0
         if (fin == null) {
 79  0
             throw new IOException();
 80  
         }
 81  
         try {
 82  0
             ByteArrayOutputStream out = new ByteArrayOutputStream();
 83  0
             byte[] buf = new byte[1024];
 84  
             int actual;
 85  
             do {
 86  0
                 actual = fin.read(buf);
 87  0
                 if (actual > 0) {
 88  0
                     out.write(buf, 0, actual);
 89  
                 }
 90  0
             } while (actual > 0);
 91  0
             return out.toByteArray();
 92  
         } finally {
 93  0
             fin.close();
 94  
         }
 95  
     }
 96  
 
 97  
     static String classDescriptorToName(String desc) {
 98  0
         return desc.replace('/', '.');
 99  
     }
 100  
 
 101  
     protected static Map<String, Method> findAttributeReaders(Class c) {
 102  0
         Map<String, Method> map = new HashMap<String, Method>();
 103  0
         Method[] methods = c.getMethods();
 104  
 
 105  0
         for (int i = 0; i < methods.length; i++) {
 106  0
             String name = methods[i].getName();
 107  0
             if (name.startsWith("read") && methods[i].getReturnType() == void.class) {
 108  0
                 map.put(name.substring(4), methods[i]);
 109  
             }
 110  
         }
 111  
 
 112  0
         return map;
 113  
     }
 114  
 
 115  
     protected static String getSignature(Member method, Class[] paramTypes) {
 116  
         // compute the method descriptor
 117  
 
 118  0
         StringBuffer b = new StringBuffer((method instanceof Method) ? method.getName() : "<init>");
 119  0
         b.append('(');
 120  
 
 121  0
         for (int i = 0; i < paramTypes.length; i++) {
 122  0
             addDescriptor(b, paramTypes[i]);
 123  
         }
 124  
 
 125  0
         b.append(')');
 126  0
         if (method instanceof Method) {
 127  0
             addDescriptor(b, ((Method)method).getReturnType());
 128  0
         } else if (method instanceof Constructor) {
 129  0
             addDescriptor(b, void.class);
 130  
         }
 131  
 
 132  0
         return b.toString();
 133  
     }
 134  
 
 135  
     private static void addDescriptor(StringBuffer b, Class c) {
 136  0
         if (c.isPrimitive()) {
 137  0
             if (c == void.class) {
 138  0
                 b.append('V');
 139  0
             } else if (c == int.class) {
 140  0
                 b.append('I');
 141  0
             } else if (c == boolean.class) {
 142  0
                 b.append('Z');
 143  0
             } else if (c == byte.class) {
 144  0
                 b.append('B');
 145  0
             } else if (c == short.class) {
 146  0
                 b.append('S');
 147  0
             } else if (c == long.class) {
 148  0
                 b.append('J');
 149  0
             } else if (c == char.class) {
 150  0
                 b.append('C');
 151  0
             } else if (c == float.class) {
 152  0
                 b.append('F');
 153  0
             } else if (c == double.class) {
 154  0
                 b.append('D');
 155  
             }
 156  0
         } else if (c.isArray()) {
 157  0
             b.append('[');
 158  0
             addDescriptor(b, c.getComponentType());
 159  
         } else {
 160  0
             b.append('L').append(c.getName().replace('.', '/')).append(';');
 161  
         }
 162  0
     }
 163  
 
 164  
     /**
 165  
      * @return the next unsigned 16 bit value
 166  
      */
 167  
     protected final int readShort() {
 168  0
         return (read() << 8) | read();
 169  
     }
 170  
 
 171  
     /**
 172  
      * @return the next signed 32 bit value
 173  
      */
 174  
     protected final int readInt() {
 175  0
         return (read() << 24) | (read() << 16) | (read() << 8) | read();
 176  
     }
 177  
 
 178  
     /**
 179  
      * skip n bytes in the input stream.
 180  
      */
 181  
     protected void skipFully(int n) throws IOException {
 182  0
         while (n > 0) {
 183  0
             int c = (int)skip(n);
 184  0
             if (c <= 0) {
 185  0
                 throw new EOFException();
 186  
             }
 187  
 
 188  0
             n -= c;
 189  0
         }
 190  0
     }
 191  
 
 192  
     protected final Member resolveMethod(int index) throws IOException, ClassNotFoundException,
 193  
         NoSuchMethodException {
 194  0
         int oldPos = pos;
 195  
         try {
 196  0
             Member m = (Member)cpool[index];
 197  0
             if (m == null) {
 198  0
                 pos = cpoolIndex[index];
 199  0
                 Class owner = resolveClass(readShort());
 200  0
                 NameAndType nt = resolveNameAndType(readShort());
 201  0
                 String signature = nt.name + nt.type;
 202  0
                 if ("<init>".equals(nt.name)) {
 203  0
                     Constructor[] ctors = owner.getConstructors();
 204  0
                     for (int i = 0; i < ctors.length; i++) {
 205  0
                         String sig = getSignature(ctors[i], ctors[i].getParameterTypes());
 206  0
                         if (sig.equals(signature)) {
 207  0
                             cpool[index] = ctors[i];
 208  0
                             m = ctors[i];
 209  0
                             return m;
 210  
                         }
 211  
                     }
 212  0
                 } else {
 213  0
                     Method[] methods = owner.getDeclaredMethods();
 214  0
                     for (int i = 0; i < methods.length; i++) {
 215  0
                         String sig = getSignature(methods[i], methods[i].getParameterTypes());
 216  0
                         if (sig.equals(signature)) {
 217  0
                             cpool[index] = methods[i];
 218  0
                             m = methods[i];
 219  0
                             return m;
 220  
                         }
 221  
                     }
 222  
                 }
 223  0
                 throw new NoSuchMethodException(signature);
 224  
             }
 225  0
             return m;
 226  
         } finally {
 227  0
             pos = oldPos;
 228  
         }
 229  
 
 230  
     }
 231  
 
 232  
     protected final Field resolveField(int i) throws IOException, ClassNotFoundException,
 233  
         NoSuchFieldException {
 234  0
         int oldPos = pos;
 235  
         try {
 236  0
             Field f = (Field)cpool[i];
 237  0
             if (f == null) {
 238  0
                 pos = cpoolIndex[i];
 239  0
                 Class owner = resolveClass(readShort());
 240  0
                 NameAndType nt = resolveNameAndType(readShort());
 241  0
                 cpool[i] = owner.getDeclaredField(nt.name);
 242  0
                 f = owner.getDeclaredField(nt.name);
 243  
             }
 244  0
             return f;
 245  
         } finally {
 246  0
             pos = oldPos;
 247  
         }
 248  
     }
 249  
 
 250  
     protected final NameAndType resolveNameAndType(int i) throws IOException {
 251  0
         int oldPos = pos;
 252  
         try {
 253  0
             NameAndType nt = (NameAndType)cpool[i];
 254  0
             if (nt == null) {
 255  0
                 pos = cpoolIndex[i];
 256  0
                 String name = resolveUtf8(readShort());
 257  0
                 String type = resolveUtf8(readShort());
 258  0
                 cpool[i] = new NameAndType(name, type);
 259  0
                 nt = new NameAndType(name, type);
 260  
             }
 261  0
             return nt;
 262  
         } finally {
 263  0
             pos = oldPos;
 264  
         }
 265  
     }
 266  
 
 267  
     protected final Class resolveClass(int i) throws IOException, ClassNotFoundException {
 268  0
         int oldPos = pos;
 269  
         try {
 270  0
             Class c = (Class)cpool[i];
 271  0
             if (c == null) {
 272  0
                 pos = cpoolIndex[i];
 273  0
                 String name = resolveUtf8(readShort());
 274  0
                 cpool[i] = Class.forName(classDescriptorToName(name));
 275  0
                 c = Class.forName(classDescriptorToName(name));
 276  
             }
 277  0
             return c;
 278  
         } finally {
 279  0
             pos = oldPos;
 280  
         }
 281  
     }
 282  
 
 283  
     protected final String resolveUtf8(int i) throws IOException {
 284  0
         int oldPos = pos;
 285  
         try {
 286  0
             String s = (String)cpool[i];
 287  0
             if (s == null) {
 288  0
                 pos = cpoolIndex[i];
 289  0
                 int len = readShort();
 290  0
                 skipFully(len);
 291  0
                 cpool[i] = new String(buf, pos - len, len, "utf-8");
 292  0
                 s = new String(buf, pos - len, len, "utf-8");
 293  
             }
 294  0
             return s;
 295  
         } finally {
 296  0
             pos = oldPos;
 297  
         }
 298  
     }
 299  
 
 300  
     @SuppressWarnings("fallthrough")
 301  
     protected final void readCpool() throws IOException {
 302  0
         int count = readShort(); // cpool count
 303  0
         cpoolIndex = new int[count];
 304  0
         cpool = new Object[count];
 305  0
         for (int i = 1; i < count; i++) {
 306  0
             int c = read();
 307  0
             cpoolIndex[i] = super.pos;
 308  
             // constant pool tag
 309  0
             switch (c) {
 310  
             case CONSTANT_FIELDREF:
 311  
             case CONSTANT_METHODREF:
 312  
             case CONSTANT_INTERFACE_METHOD_REF:
 313  
             case CONSTANT_NAME_AND_TYPE:
 314  
 
 315  0
                 readShort(); // class index or (12) name index
 316  
                 // fall through
 317  
 
 318  
             case CONSTANT_CLASS:
 319  
             case CONSTANT_STRING:
 320  
 
 321  0
                 readShort(); // string index or class index
 322  0
                 break;
 323  
 
 324  
             case CONSTANT_LONG:
 325  
             case CONSTANT_DOUBLE:
 326  
 
 327  0
                 readInt(); // hi-value
 328  
 
 329  
                 // see jvm spec section 4.4.5 - double and long cpool
 330  
                 // entries occupy two "slots" in the cpool table.
 331  0
                 i++;
 332  
                 // fall through
 333  
 
 334  
             case CONSTANT_INTEGER:
 335  
             case CONSTANT_FLOAT:
 336  
 
 337  0
                 readInt(); // value
 338  0
                 break;
 339  
 
 340  
             case CONSTANT_UTF_8:
 341  
 
 342  0
                 int len = readShort();
 343  0
                 skipFully(len);
 344  0
                 break;
 345  
 
 346  
             default:
 347  
                 // corrupt class file
 348  0
                 throw new IllegalStateException();
 349  
             }
 350  
         }
 351  0
     }
 352  
 
 353  
     protected final void skipAttributes() throws IOException {
 354  0
         int count = readShort();
 355  0
         for (int i = 0; i < count; i++) {
 356  0
             readShort(); // name index
 357  0
             skipFully(readInt());
 358  
         }
 359  0
     }
 360  
 
 361  
     /**
 362  
      * read an attributes array. the elements of a class file that can contain
 363  
      * attributes are: fields, methods, the class itself, and some other types
 364  
      * of attributes.
 365  
      */
 366  
     protected final void readAttributes() throws IOException {
 367  0
         int count = readShort();
 368  0
         for (int i = 0; i < count; i++) {
 369  0
             int nameIndex = readShort(); // name index
 370  0
             int attrLen = readInt();
 371  0
             int curPos = pos;
 372  
 
 373  0
             String attrName = resolveUtf8(nameIndex);
 374  
 
 375  0
             Method m = attrMethods.get(attrName);
 376  
 
 377  0
             if (m != null) {
 378  
                 try {
 379  0
                     m.invoke(this, new Object[] {});
 380  0
                 } catch (IllegalAccessException e) {
 381  0
                     pos = curPos;
 382  0
                     skipFully(attrLen);
 383  0
                 } catch (InvocationTargetException e) {
 384  
                     try {
 385  0
                         throw e.getTargetException();
 386  0
                     } catch (Error ex) {
 387  0
                         throw ex;
 388  0
                     } catch (RuntimeException ex) {
 389  0
                         throw ex;
 390  0
                     } catch (IOException ex) {
 391  0
                         throw ex;
 392  0
                     } catch (Throwable ex) {
 393  0
                         pos = curPos;
 394  0
                         skipFully(attrLen);
 395  
                     }
 396  0
                 }
 397  
             } else {
 398  
                 // don't care what attribute this is
 399  0
                 skipFully(attrLen);
 400  
             }
 401  
         }
 402  0
     }
 403  
 
 404  
     /**
 405  
      * read a code attribute
 406  
      * 
 407  
      * @throws IOException
 408  
      */
 409  
     public void readCode() throws IOException {
 410  0
         readShort(); // max stack
 411  0
         readShort(); // max locals
 412  0
         skipFully(readInt()); // code
 413  0
         skipFully(8 * readShort()); // exception table
 414  
 
 415  
         // read the code attributes (recursive). This is where
 416  
         // we will find the LocalVariableTable attribute.
 417  0
         readAttributes();
 418  0
     }
 419  
 
 420  
     private static class NameAndType {
 421  
         String name;
 422  
         String type;
 423  
 
 424  0
         public NameAndType(String name, String type) {
 425  0
             this.name = name;
 426  0
             this.type = type;
 427  0
         }
 428  
     }
 429  
 }