src/share/classes/com/sun/tools/javac/jvm/JNIWriter.java

Sun, 17 Feb 2013 16:44:55 -0500

author
dholmes
date
Sun, 17 Feb 2013 16:44:55 -0500
changeset 1571
af8417e590f4
parent 1521
71f35e4b93a5
child 1723
a2889739cf21
permissions
-rw-r--r--

Merge

     1 /*
     2  * Copyright (c) 1999, 2013, Oracle and/or its affiliates. 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.  Oracle designates this
     8  * particular file as subject to the "Classpath" exception as provided
     9  * by Oracle 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
    22  * or visit www.oracle.com if you need additional information or have any
    23  * questions.
    24  */
    26 package com.sun.tools.javac.jvm;
    28 import java.io.IOException;
    29 import java.io.Writer;
    30 import java.util.ArrayList;
    31 import java.util.List;
    32 import java.util.Stack;
    33 import java.util.StringTokenizer;
    35 import javax.lang.model.element.Element;
    36 import javax.lang.model.element.ExecutableElement;
    37 import javax.lang.model.element.Modifier;
    38 import javax.lang.model.element.Name;
    39 import javax.lang.model.element.TypeElement;
    40 import javax.lang.model.element.VariableElement;
    41 import javax.lang.model.type.ArrayType;
    42 import javax.lang.model.type.DeclaredType;
    43 import javax.lang.model.type.NoType;
    44 import javax.lang.model.type.PrimitiveType;
    45 import javax.lang.model.type.TypeKind;
    46 import javax.lang.model.type.TypeMirror;
    47 import javax.lang.model.type.TypeVariable;
    48 import javax.lang.model.type.TypeVisitor;
    49 import javax.lang.model.util.ElementFilter;
    50 import javax.lang.model.util.Elements;
    51 import javax.lang.model.util.SimpleTypeVisitor8;
    52 import javax.lang.model.util.Types;
    54 import javax.tools.FileObject;
    55 import javax.tools.JavaFileManager;
    56 import javax.tools.StandardLocation;
    58 import com.sun.tools.javac.code.Attribute;
    59 import com.sun.tools.javac.code.Flags;
    60 import com.sun.tools.javac.code.Kinds;
    61 import com.sun.tools.javac.code.Scope;
    62 import com.sun.tools.javac.code.Symbol.ClassSymbol;
    63 import com.sun.tools.javac.code.Symtab;
    64 import com.sun.tools.javac.model.JavacElements;
    65 import com.sun.tools.javac.model.JavacTypes;
    66 import com.sun.tools.javac.util.Assert;
    67 import com.sun.tools.javac.util.Context;
    68 import com.sun.tools.javac.util.Log;
    69 import com.sun.tools.javac.util.Options;
    71 import static com.sun.tools.javac.main.Option.*;
    73 /** This class provides operations to write native header files for classes.
    74  *
    75  *  <p><b>This is NOT part of any supported API.
    76  *  If you write code that depends on this, you do so at your own risk.
    77  *  This code and its internal interfaces are subject to change or
    78  *  deletion without notice.</b>
    79  */
    80 public class JNIWriter {
    81     protected static final Context.Key<JNIWriter> jniWriterKey =
    82         new Context.Key<JNIWriter>();
    84     /** Access to files. */
    85     private final JavaFileManager fileManager;
    87     JavacElements elements;
    88     JavacTypes types;
    90     /** The log to use for verbose output.
    91      */
    92     private final Log log;
    94     /** Switch: verbose output.
    95      */
    96     private boolean verbose;
    98     /** Switch: check all nested classes of top level class
    99      */
   100     private boolean checkAll;
   102     private Mangle mangler;
   104     private Context context;
   106     private Symtab syms;
   108     private String lineSep;
   110     private final boolean isWindows =
   111         System.getProperty("os.name").startsWith("Windows");
   113     /** Get the ClassWriter instance for this context. */
   114     public static JNIWriter instance(Context context) {
   115         JNIWriter instance = context.get(jniWriterKey);
   116         if (instance == null)
   117             instance = new JNIWriter(context);
   118         return instance;
   119     }
   121     /** Construct a class writer, given an options table.
   122      */
   123     private JNIWriter(Context context) {
   124         context.put(jniWriterKey, this);
   125         fileManager = context.get(JavaFileManager.class);
   126         log = Log.instance(context);
   128         Options options = Options.instance(context);
   129         verbose = options.isSet(VERBOSE);
   130         checkAll = options.isSet("javah:full");
   132         this.context = context; // for lazyInit()
   133         syms = Symtab.instance(context);
   135         lineSep = System.getProperty("line.separator");
   136     }
   138     private void lazyInit() {
   139         if (mangler == null) {
   140             elements = JavacElements.instance(context);
   141             types = JavacTypes.instance(context);
   142             mangler = new Mangle(elements, types);
   143         }
   144     }
   146     public boolean needsHeader(ClassSymbol c) {
   147         if (c.isLocal() || (c.flags() & Flags.SYNTHETIC) != 0)
   148             return false;
   150         if (checkAll)
   151             return needsHeader(c.outermostClass(), true);
   152         else
   153             return needsHeader(c, false);
   154     }
   156     private boolean needsHeader(ClassSymbol c, boolean checkNestedClasses) {
   157         if (c.isLocal() || (c.flags() & Flags.SYNTHETIC) != 0)
   158             return false;
   160         /* temporary code for backwards compatibility */
   161         for (Attribute.Compound a: c.annotations.getDeclarationAttributes()) {
   162             if (a.type.tsym == syms.nativeHeaderType_old.tsym)
   163                 return true;
   164         }
   165         /* end of temporary code for backwards compatibility */
   167         for (Scope.Entry i = c.members_field.elems; i != null; i = i.sibling) {
   168             if (i.sym.kind == Kinds.MTH && (i.sym.flags() & Flags.NATIVE) != 0)
   169                 return true;
   170             for (Attribute.Compound a: i.sym.annotations.getDeclarationAttributes()) {
   171                 if (a.type.tsym == syms.nativeHeaderType.tsym)
   172                     return true;
   173             }
   174         }
   175         if (checkNestedClasses) {
   176             for (Scope.Entry i = c.members_field.elems; i != null; i = i.sibling) {
   177                 if ((i.sym.kind == Kinds.TYP) && needsHeader(((ClassSymbol) i.sym), true))
   178                     return true;
   179             }
   180         }
   181         return false;
   182     }
   184     /** Emit a class file for a given class.
   185      *  @param c      The class from which a class file is generated.
   186      */
   187     public FileObject write(ClassSymbol c)
   188         throws IOException
   189     {
   190         String className = c.flatName().toString();
   191         FileObject outFile
   192             = fileManager.getFileForOutput(StandardLocation.NATIVE_HEADER_OUTPUT,
   193                 "", className.replaceAll("[.$]", "_") + ".h", null);
   194         Writer out = outFile.openWriter();
   195         try {
   196             write(out, c);
   197             if (verbose)
   198                 log.printVerbose("wrote.file", outFile);
   199             out.close();
   200             out = null;
   201         } finally {
   202             if (out != null) {
   203                 // if we are propogating an exception, delete the file
   204                 out.close();
   205                 outFile.delete();
   206                 outFile = null;
   207             }
   208         }
   209         return outFile; // may be null if write failed
   210     }
   212     public void write(Writer out, ClassSymbol sym)
   213             throws IOException {
   214         lazyInit();
   215         try {
   216             String cname = mangler.mangle(sym.fullname, Mangle.Type.CLASS);
   217             println(out, fileTop());
   218             println(out, includes());
   219             println(out, guardBegin(cname));
   220             println(out, cppGuardBegin());
   222             writeStatics(out, sym);
   223             writeMethods(out, sym, cname);
   225             println(out, cppGuardEnd());
   226             println(out, guardEnd(cname));
   227         } catch (TypeSignature.SignatureException e) {
   228             throw new IOException(e);
   229         }
   230     }
   232     protected void writeStatics(Writer out, ClassSymbol sym) throws IOException {
   233         List<VariableElement> classfields = getAllFields(sym);
   235         for (VariableElement v: classfields) {
   236             if (!v.getModifiers().contains(Modifier.STATIC))
   237                 continue;
   238             String s = null;
   239             s = defineForStatic(sym, v);
   240             if (s != null) {
   241                 println(out, s);
   242             }
   243         }
   244     }
   246     /**
   247      * Including super class fields.
   248      */
   249     List<VariableElement> getAllFields(TypeElement subclazz) {
   250         List<VariableElement> fields = new ArrayList<VariableElement>();
   251         TypeElement cd = null;
   252         Stack<TypeElement> s = new Stack<TypeElement>();
   254         cd = subclazz;
   255         while (true) {
   256             s.push(cd);
   257             TypeElement c = (TypeElement) (types.asElement(cd.getSuperclass()));
   258             if (c == null)
   259                 break;
   260             cd = c;
   261         }
   263         while (!s.empty()) {
   264             cd = s.pop();
   265             fields.addAll(ElementFilter.fieldsIn(cd.getEnclosedElements()));
   266         }
   268         return fields;
   269     }
   271     protected String defineForStatic(TypeElement c, VariableElement f) {
   272         CharSequence cnamedoc = c.getQualifiedName();
   273         CharSequence fnamedoc = f.getSimpleName();
   275         String cname = mangler.mangle(cnamedoc, Mangle.Type.CLASS);
   276         String fname = mangler.mangle(fnamedoc, Mangle.Type.FIELDSTUB);
   278         Assert.check(f.getModifiers().contains(Modifier.STATIC));
   280         if (f.getModifiers().contains(Modifier.FINAL)) {
   281             Object value = null;
   283             value = f.getConstantValue();
   285             if (value != null) { /* so it is a ConstantExpression */
   286                 String constString = null;
   287                 if ((value instanceof Integer)
   288                     || (value instanceof Byte)
   289                     || (value instanceof Short)) {
   290                     /* covers byte, short, int */
   291                     constString = value.toString() + "L";
   292                 } else if (value instanceof Boolean) {
   293                     constString = ((Boolean) value) ? "1L" : "0L";
   294                 } else if (value instanceof Character) {
   295                     Character ch = (Character) value;
   296                     constString = String.valueOf(((int) ch) & 0xffff) + "L";
   297                 } else if (value instanceof Long) {
   298                     // Visual C++ supports the i64 suffix, not LL.
   299                     if (isWindows)
   300                         constString = value.toString() + "i64";
   301                     else
   302                         constString = value.toString() + "LL";
   303                 } else if (value instanceof Float) {
   304                     /* bug for bug */
   305                     float fv = ((Float)value).floatValue();
   306                     if (Float.isInfinite(fv))
   307                         constString = ((fv < 0) ? "-" : "") + "Inff";
   308                     else
   309                         constString = value.toString() + "f";
   310                 } else if (value instanceof Double) {
   311                     /* bug for bug */
   312                     double d = ((Double)value).doubleValue();
   313                     if (Double.isInfinite(d))
   314                         constString = ((d < 0) ? "-" : "") + "InfD";
   315                     else
   316                         constString = value.toString();
   317                 }
   319                 if (constString != null) {
   320                     StringBuilder s = new StringBuilder("#undef ");
   321                     s.append(cname); s.append("_"); s.append(fname); s.append(lineSep);
   322                     s.append("#define "); s.append(cname); s.append("_");
   323                     s.append(fname); s.append(" "); s.append(constString);
   324                     return s.toString();
   325                 }
   327             }
   328         }
   330         return null;
   331     }
   334     protected void writeMethods(Writer out, ClassSymbol sym, String cname)
   335             throws IOException, TypeSignature.SignatureException {
   336         List<ExecutableElement> classmethods = ElementFilter.methodsIn(sym.getEnclosedElements());
   337         for (ExecutableElement md: classmethods) {
   338             if(md.getModifiers().contains(Modifier.NATIVE)){
   339                 TypeMirror mtr = types.erasure(md.getReturnType());
   340                 String sig = signature(md);
   341                 TypeSignature newtypesig = new TypeSignature(elements);
   342                 CharSequence methodName = md.getSimpleName();
   343                 boolean longName = false;
   344                 for (ExecutableElement md2: classmethods) {
   345                     if ((md2 != md)
   346                         && (methodName.equals(md2.getSimpleName()))
   347                         && (md2.getModifiers().contains(Modifier.NATIVE)))
   348                         longName = true;
   350                 }
   351                 println(out, "/*");
   352                 println(out, " * Class:     " + cname);
   353                 println(out, " * Method:    " +
   354                            mangler.mangle(methodName, Mangle.Type.FIELDSTUB));
   355                 println(out, " * Signature: " + newtypesig.getTypeSignature(sig, mtr));
   356                 println(out, " */");
   357                 println(out, "JNIEXPORT " + jniType(mtr) +
   358                            " JNICALL " +
   359                            mangler.mangleMethod(md, sym,
   360                                                (longName) ?
   361                                                Mangle.Type.METHOD_JNI_LONG :
   362                                                Mangle.Type.METHOD_JNI_SHORT));
   363                 print(out, "  (JNIEnv *, ");
   364                 List<? extends VariableElement> paramargs = md.getParameters();
   365                 List<TypeMirror> args = new ArrayList<TypeMirror>();
   366                 for (VariableElement p: paramargs) {
   367                     args.add(types.erasure(p.asType()));
   368                 }
   369                 if (md.getModifiers().contains(Modifier.STATIC))
   370                     print(out, "jclass");
   371                 else
   372                     print(out, "jobject");
   374                 for (TypeMirror arg: args) {
   375                     print(out, ", ");
   376                     print(out, jniType(arg));
   377                 }
   378                 println(out, ");"
   379                         + lineSep);
   380             }
   381         }
   382     }
   384     // c.f. MethodDoc.signature
   385     String signature(ExecutableElement e) {
   386         StringBuilder sb = new StringBuilder("(");
   387         String sep = "";
   388         for (VariableElement p: e.getParameters()) {
   389             sb.append(sep);
   390             sb.append(types.erasure(p.asType()).toString());
   391             sep = ",";
   392         }
   393         sb.append(")");
   394         return sb.toString();
   395     }
   397     protected final String jniType(TypeMirror t) {
   398         TypeElement throwable = elements.getTypeElement("java.lang.Throwable");
   399         TypeElement jClass = elements.getTypeElement("java.lang.Class");
   400         TypeElement jString = elements.getTypeElement("java.lang.String");
   401         Element tclassDoc = types.asElement(t);
   404         switch (t.getKind()) {
   405             case ARRAY: {
   406                 TypeMirror ct = ((ArrayType) t).getComponentType();
   407                 switch (ct.getKind()) {
   408                     case BOOLEAN:  return "jbooleanArray";
   409                     case BYTE:     return "jbyteArray";
   410                     case CHAR:     return "jcharArray";
   411                     case SHORT:    return "jshortArray";
   412                     case INT:      return "jintArray";
   413                     case LONG:     return "jlongArray";
   414                     case FLOAT:    return "jfloatArray";
   415                     case DOUBLE:   return "jdoubleArray";
   416                     case ARRAY:
   417                     case DECLARED: return "jobjectArray";
   418                     default: throw new Error(ct.toString());
   419                 }
   420             }
   422             case VOID:     return "void";
   423             case BOOLEAN:  return "jboolean";
   424             case BYTE:     return "jbyte";
   425             case CHAR:     return "jchar";
   426             case SHORT:    return "jshort";
   427             case INT:      return "jint";
   428             case LONG:     return "jlong";
   429             case FLOAT:    return "jfloat";
   430             case DOUBLE:   return "jdouble";
   432             case DECLARED: {
   433                 if (tclassDoc.equals(jString))
   434                     return "jstring";
   435                 else if (types.isAssignable(t, throwable.asType()))
   436                     return "jthrowable";
   437                 else if (types.isAssignable(t, jClass.asType()))
   438                     return "jclass";
   439                 else
   440                     return "jobject";
   441             }
   442         }
   444         Assert.check(false, "jni unknown type");
   445         return null; /* dead code. */
   446     }
   448     protected String fileTop() {
   449         return "/* DO NOT EDIT THIS FILE - it is machine generated */";
   450     }
   452     protected String includes() {
   453         return "#include <jni.h>";
   454     }
   456     /*
   457      * Deal with the C pre-processor.
   458      */
   459     protected String cppGuardBegin() {
   460         return "#ifdef __cplusplus" + lineSep
   461                 + "extern \"C\" {" + lineSep
   462                 + "#endif";
   463     }
   465     protected String cppGuardEnd() {
   466         return "#ifdef __cplusplus" + lineSep
   467                 + "}" + lineSep
   468                 + "#endif";
   469     }
   471     protected String guardBegin(String cname) {
   472         return "/* Header for class " + cname + " */" + lineSep
   473                 + lineSep
   474                 + "#ifndef _Included_" + cname + lineSep
   475                 + "#define _Included_" + cname;
   476     }
   478     protected String guardEnd(String cname) {
   479         return "#endif";
   480     }
   482     protected void print(Writer out, String text) throws IOException {
   483         out.write(text);
   484     }
   486     protected void println(Writer out, String text) throws IOException {
   487         out.write(text);
   488         out.write(lineSep);
   489     }
   492     private static class Mangle {
   494         public static class Type {
   495             public static final int CLASS            = 1;
   496             public static final int FIELDSTUB        = 2;
   497             public static final int FIELD            = 3;
   498             public static final int JNI              = 4;
   499             public static final int SIGNATURE        = 5;
   500             public static final int METHOD_JDK_1     = 6;
   501             public static final int METHOD_JNI_SHORT = 7;
   502             public static final int METHOD_JNI_LONG  = 8;
   503         };
   505         private Elements elems;
   506         private Types types;
   508         Mangle(Elements elems, Types types) {
   509             this.elems = elems;
   510             this.types = types;
   511         }
   513         public final String mangle(CharSequence name, int mtype) {
   514             StringBuilder result = new StringBuilder(100);
   515             int length = name.length();
   517             for (int i = 0; i < length; i++) {
   518                 char ch = name.charAt(i);
   519                 if (isalnum(ch)) {
   520                     result.append(ch);
   521                 } else if ((ch == '.') &&
   522                            mtype == Mangle.Type.CLASS) {
   523                     result.append('_');
   524                 } else if (( ch == '$') &&
   525                            mtype == Mangle.Type.CLASS) {
   526                     result.append('_');
   527                     result.append('_');
   528                 } else if (ch == '_' && mtype == Mangle.Type.FIELDSTUB) {
   529                     result.append('_');
   530                 } else if (ch == '_' && mtype == Mangle.Type.CLASS) {
   531                     result.append('_');
   532                 } else if (mtype == Mangle.Type.JNI) {
   533                     String esc = null;
   534                     if (ch == '_')
   535                         esc = "_1";
   536                     else if (ch == '.')
   537                         esc = "_";
   538                     else if (ch == ';')
   539                         esc = "_2";
   540                     else if (ch == '[')
   541                         esc = "_3";
   542                     if (esc != null) {
   543                         result.append(esc);
   544                     } else {
   545                         result.append(mangleChar(ch));
   546                     }
   547                 } else if (mtype == Mangle.Type.SIGNATURE) {
   548                     if (isprint(ch)) {
   549                         result.append(ch);
   550                     } else {
   551                         result.append(mangleChar(ch));
   552                     }
   553                 } else {
   554                     result.append(mangleChar(ch));
   555                 }
   556             }
   558             return result.toString();
   559         }
   561         public String mangleMethod(ExecutableElement method, TypeElement clazz,
   562                                           int mtype) throws TypeSignature.SignatureException {
   563             StringBuilder result = new StringBuilder(100);
   564             result.append("Java_");
   566             if (mtype == Mangle.Type.METHOD_JDK_1) {
   567                 result.append(mangle(clazz.getQualifiedName(), Mangle.Type.CLASS));
   568                 result.append('_');
   569                 result.append(mangle(method.getSimpleName(),
   570                                      Mangle.Type.FIELD));
   571                 result.append("_stub");
   572                 return result.toString();
   573             }
   575             /* JNI */
   576             result.append(mangle(getInnerQualifiedName(clazz), Mangle.Type.JNI));
   577             result.append('_');
   578             result.append(mangle(method.getSimpleName(),
   579                                  Mangle.Type.JNI));
   580             if (mtype == Mangle.Type.METHOD_JNI_LONG) {
   581                 result.append("__");
   582                 String typesig = signature(method);
   583                 TypeSignature newTypeSig = new TypeSignature(elems);
   584                 String sig = newTypeSig.getTypeSignature(typesig,  method.getReturnType());
   585                 sig = sig.substring(1);
   586                 sig = sig.substring(0, sig.lastIndexOf(')'));
   587                 sig = sig.replace('/', '.');
   588                 result.append(mangle(sig, Mangle.Type.JNI));
   589             }
   591             return result.toString();
   592         }
   593         //where
   594             private String getInnerQualifiedName(TypeElement clazz) {
   595                 return elems.getBinaryName(clazz).toString();
   596             }
   598         public final String mangleChar(char ch) {
   599             String s = Integer.toHexString(ch);
   600             int nzeros = 5 - s.length();
   601             char[] result = new char[6];
   602             result[0] = '_';
   603             for (int i = 1; i <= nzeros; i++)
   604                 result[i] = '0';
   605             for (int i = nzeros+1, j = 0; i < 6; i++, j++)
   606                 result[i] = s.charAt(j);
   607             return new String(result);
   608         }
   610         // Warning: duplicated in Gen
   611         private String signature(ExecutableElement e) {
   612             StringBuilder sb = new StringBuilder();
   613             String sep = "(";
   614             for (VariableElement p: e.getParameters()) {
   615                 sb.append(sep);
   616                 sb.append(types.erasure(p.asType()).toString());
   617                 sep = ",";
   618             }
   619             sb.append(")");
   620             return sb.toString();
   621         }
   623         /* Warning: Intentional ASCII operation. */
   624         private static boolean isalnum(char ch) {
   625             return ch <= 0x7f && /* quick test */
   626                 ((ch >= 'A' && ch <= 'Z') ||
   627                  (ch >= 'a' && ch <= 'z') ||
   628                  (ch >= '0' && ch <= '9'));
   629         }
   631         /* Warning: Intentional ASCII operation. */
   632         private static boolean isprint(char ch) {
   633             return ch >= 32 && ch <= 126;
   634         }
   635     }
   637     private static class TypeSignature {
   638         static class SignatureException extends Exception {
   639             private static final long serialVersionUID = 1L;
   640             SignatureException(String reason) {
   641                 super(reason);
   642             }
   643         }
   645         Elements elems;
   647         /* Signature Characters */
   649         private static final String SIG_VOID                   = "V";
   650         private static final String SIG_BOOLEAN                = "Z";
   651         private static final String SIG_BYTE                   = "B";
   652         private static final String SIG_CHAR                   = "C";
   653         private static final String SIG_SHORT                  = "S";
   654         private static final String SIG_INT                    = "I";
   655         private static final String SIG_LONG                   = "J";
   656         private static final String SIG_FLOAT                  = "F";
   657         private static final String SIG_DOUBLE                 = "D";
   658         private static final String SIG_ARRAY                  = "[";
   659         private static final String SIG_CLASS                  = "L";
   663         public TypeSignature(Elements elems){
   664             this.elems = elems;
   665         }
   667         /*
   668          * Returns the type signature of a field according to JVM specs
   669          */
   670         public String getTypeSignature(String javasignature) throws SignatureException {
   671             return getParamJVMSignature(javasignature);
   672         }
   674         /*
   675          * Returns the type signature of a method according to JVM specs
   676          */
   677         public String getTypeSignature(String javasignature, TypeMirror returnType)
   678                 throws SignatureException {
   679             String signature = null; //Java type signature.
   680             String typeSignature = null; //Internal type signature.
   681             List<String> params = new ArrayList<String>(); //List of parameters.
   682             String paramsig = null; //Java parameter signature.
   683             String paramJVMSig = null; //Internal parameter signature.
   684             String returnSig = null; //Java return type signature.
   685             String returnJVMType = null; //Internal return type signature.
   686             int dimensions = 0; //Array dimension.
   688             int startIndex = -1;
   689             int endIndex = -1;
   690             StringTokenizer st = null;
   691             int i = 0;
   693             // Gets the actual java signature without parentheses.
   694             if (javasignature != null) {
   695                 startIndex = javasignature.indexOf("(");
   696                 endIndex = javasignature.indexOf(")");
   697             }
   699             if (((startIndex != -1) && (endIndex != -1))
   700                 &&(startIndex+1 < javasignature.length())
   701                 &&(endIndex < javasignature.length())) {
   702                 signature = javasignature.substring(startIndex+1, endIndex);
   703             }
   705             // Separates parameters.
   706             if (signature != null) {
   707                 if (signature.indexOf(",") != -1) {
   708                     st = new StringTokenizer(signature, ",");
   709                     if (st != null) {
   710                         while (st.hasMoreTokens()) {
   711                             params.add(st.nextToken());
   712                         }
   713                     }
   714                 } else {
   715                     params.add(signature);
   716                 }
   717             }
   719             /* JVM type signature. */
   720             typeSignature = "(";
   722             // Gets indivisual internal parameter signature.
   723             while (params.isEmpty() != true) {
   724                 paramsig = params.remove(i).trim();
   725                 paramJVMSig  = getParamJVMSignature(paramsig);
   726                 if (paramJVMSig != null) {
   727                     typeSignature += paramJVMSig;
   728                 }
   729             }
   731             typeSignature += ")";
   733             // Get internal return type signature.
   735             returnJVMType = "";
   736             if (returnType != null) {
   737                 dimensions = dimensions(returnType);
   738             }
   740             //Gets array dimension of return type.
   741             while (dimensions-- > 0) {
   742                 returnJVMType += "[";
   743             }
   744             if (returnType != null) {
   745                 returnSig = qualifiedTypeName(returnType);
   746                 returnJVMType += getComponentType(returnSig);
   747             } else {
   748                 System.out.println("Invalid return type.");
   749             }
   751             typeSignature += returnJVMType;
   753             return typeSignature;
   754         }
   756         /*
   757          * Returns internal signature of a parameter.
   758          */
   759         private String getParamJVMSignature(String paramsig) throws SignatureException {
   760             String paramJVMSig = "";
   761             String componentType ="";
   763             if(paramsig != null){
   765                 if(paramsig.indexOf("[]") != -1) {
   766                     // Gets array dimension.
   767                     int endindex = paramsig.indexOf("[]");
   768                     componentType = paramsig.substring(0, endindex);
   769                     String dimensionString =  paramsig.substring(endindex);
   770                     if(dimensionString != null){
   771                         while(dimensionString.indexOf("[]") != -1){
   772                             paramJVMSig += "[";
   773                             int beginindex = dimensionString.indexOf("]") + 1;
   774                             if(beginindex < dimensionString.length()){
   775                                 dimensionString = dimensionString.substring(beginindex);
   776                             }else
   777                                 dimensionString = "";
   778                         }
   779                     }
   780                 } else componentType = paramsig;
   782                 paramJVMSig += getComponentType(componentType);
   783             }
   784             return paramJVMSig;
   785         }
   787         /*
   788          * Returns internal signature of a component.
   789          */
   790         private String getComponentType(String componentType) throws SignatureException {
   792             String JVMSig = "";
   794             if(componentType != null){
   795                 if(componentType.equals("void")) JVMSig += SIG_VOID ;
   796                 else if(componentType.equals("boolean"))  JVMSig += SIG_BOOLEAN ;
   797                 else if(componentType.equals("byte")) JVMSig += SIG_BYTE ;
   798                 else if(componentType.equals("char"))  JVMSig += SIG_CHAR ;
   799                 else if(componentType.equals("short"))  JVMSig += SIG_SHORT ;
   800                 else if(componentType.equals("int"))  JVMSig += SIG_INT ;
   801                 else if(componentType.equals("long"))  JVMSig += SIG_LONG ;
   802                 else if(componentType.equals("float")) JVMSig += SIG_FLOAT ;
   803                 else if(componentType.equals("double"))  JVMSig += SIG_DOUBLE ;
   804                 else {
   805                     if(!componentType.equals("")){
   806                         TypeElement classNameDoc = elems.getTypeElement(componentType);
   808                         if(classNameDoc == null){
   809                             throw new SignatureException(componentType);
   810                         }else {
   811                             String classname = classNameDoc.getQualifiedName().toString();
   812                             String newclassname = classname.replace('.', '/');
   813                             JVMSig += "L";
   814                             JVMSig += newclassname;
   815                             JVMSig += ";";
   816                         }
   817                     }
   818                 }
   819             }
   820             return JVMSig;
   821         }
   823         int dimensions(TypeMirror t) {
   824             if (t.getKind() != TypeKind.ARRAY)
   825                 return 0;
   826             return 1 + dimensions(((ArrayType) t).getComponentType());
   827         }
   830         String qualifiedTypeName(TypeMirror type) {
   831             TypeVisitor<Name, Void> v = new SimpleTypeVisitor8<Name, Void>() {
   832                 @Override
   833                 public Name visitArray(ArrayType t, Void p) {
   834                     return t.getComponentType().accept(this, p);
   835                 }
   837                 @Override
   838                 public Name visitDeclared(DeclaredType t, Void p) {
   839                     return ((TypeElement) t.asElement()).getQualifiedName();
   840                 }
   842                 @Override
   843                 public Name visitPrimitive(PrimitiveType t, Void p) {
   844                     return elems.getName(t.toString());
   845                 }
   847                 @Override
   848                 public Name visitNoType(NoType t, Void p) {
   849                     if (t.getKind() == TypeKind.VOID)
   850                         return elems.getName("void");
   851                     return defaultAction(t, p);
   852                 }
   854                 @Override
   855                 public Name visitTypeVariable(TypeVariable t, Void p) {
   856                     return t.getUpperBound().accept(this, p);
   857                 }
   858             };
   859             return v.visit(type).toString();
   860         }
   861     }
   863 }

mercurial