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