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