1 /*
   2  * Copyright 2008-2009 Sun Microsystems, Inc.  All Rights Reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Sun designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Sun in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
  22  * CA 95054 USA or visit www.sun.com if you need additional information or
  23  * have any questions.
  24  */
  25 
  26 package impl.java.dyn.util;
  27 
  28 import java.dyn.MethodType;
  29 import java.util.ArrayList;
  30 import java.util.List;
  31 
  32 public class Signatures {
  33 
  34     private Signatures() { }  // cannot instantiate
  35 
  36     public static List<Class<?>> parseMethod(String bytecodeSignature, ClassLoader loader) {
  37         return parseMethod(bytecodeSignature, 0, bytecodeSignature.length(), loader);
  38     }
  39 
  40     public static List<Class<?>> parseMethod(String bytecodeSignature,
  41             int start, int end, ClassLoader loader) {
  42         if (loader == null)
  43             loader = ClassLoader.getSystemClassLoader();
  44         String str = bytecodeSignature;
  45         int[] i = {start};
  46         ArrayList<Class<?>> ptypes = new ArrayList<Class<?>>();
  47         if (i[0] < end && str.charAt(i[0]) == '(') {
  48             ++i[0];  // skip '('
  49             while (i[0] < end && str.charAt(i[0]) != ')') {
  50                 Class<?> pt = parseSig(str, i, end, loader);
  51                 if (pt == null || pt == void.class)
  52                     parseError(str, "bad argument type");
  53                 ptypes.add(pt);
  54             }
  55             ++i[0];  // skip ')'
  56         } else {
  57             parseError(str, "not a method type");
  58         }
  59         Class<?> rtype = parseSig(str, i, end, loader);
  60         if (rtype == null || i[0] != end)
  61             parseError(str, "bad return type");
  62         ptypes.add(rtype);
  63         return ptypes;
  64     }
  65 
  66     static private void parseError(String str, String msg) {
  67         throw new IllegalArgumentException("bad signature: "+str+": "+msg);
  68     }
  69 
  70     static private Class<?> parseSig(String str, int[] i, int end, ClassLoader loader) {
  71         if (i[0] == end)  return null;
  72         char c = str.charAt(i[0]++);
  73         if (c == 'L') {
  74             int begc = i[0], endc = str.indexOf(';', begc);
  75             if (endc < 0)  return null;
  76             i[0] = endc+1;
  77             String name = str.substring(begc, endc).replace('/', '.');
  78             try {
  79                 return loader.loadClass(name);
  80             } catch (ClassNotFoundException ex) {
  81                 throw new TypeNotPresentException(name, ex);
  82             }
  83         } else if (c == '[') {
  84             Class<?> t = parseSig(str, i, end, loader);
  85             if (t != null)
  86                 t = java.lang.reflect.Array.newInstance(t, 0).getClass();
  87             return t;
  88         } else {
  89             return Wrappers.basicTypeFromChar(c);
  90         }
  91     }
  92 
  93     public static String unparse(Class<?> type) {
  94         StringBuilder sb = new StringBuilder();
  95         unparseSig(type, sb);
  96         return sb.toString();
  97     }
  98 
  99     public static String unparse(MethodType type) {
 100         return unparseMethod(type.returnType(), type.parameterList());
 101     }
 102 
 103     public static String unparse(Object type) {
 104         if (type instanceof Class<?>)
 105             return unparse((Class<?>) type);
 106         if (type instanceof MethodType)
 107             return unparse((MethodType) type);
 108         return (String) type;
 109     }
 110 
 111     public static String unparseMethod(Class<?> rtype, List<Class<?>> ptypes) {
 112         StringBuilder sb = new StringBuilder();
 113         sb.append('(');
 114         for (Class<?> pt : ptypes)
 115             unparseSig(pt, sb);
 116         sb.append(')');
 117         unparseSig(rtype, sb);
 118         return sb.toString();
 119     }
 120 
 121     static private void unparseSig(Class<?> t, StringBuilder sb) {
 122         char c = Wrappers.basicTypeChar(t);
 123         if (c != 'L') {
 124             sb.append(c);
 125         } else {
 126             boolean lsemi = (!t.isArray());
 127             if (lsemi)  sb.append('L');
 128             sb.append(t.getName().replace('.', '/'));
 129             if (lsemi)  sb.append(';');
 130         }
 131     }
 132 
 133 }