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