| /* |
| * Copyright (c) 1999, 2013, Oracle and/or its affiliates. All rights reserved. |
| * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
| * |
| * This code is free software; you can redistribute it and/or modify it |
| * under the terms of the GNU General Public License version 2 only, as |
| * published by the Free Software Foundation. Oracle designates this |
| * particular file as subject to the "Classpath" exception as provided |
| * by Oracle in the LICENSE file that accompanied this code. |
| * |
| * This code is distributed in the hope that it will be useful, but WITHOUT |
| * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
| * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
| * version 2 for more details (a copy is included in the LICENSE file that |
| * accompanied this code). |
| * |
| * You should have received a copy of the GNU General Public License version |
| * 2 along with this work; if not, write to the Free Software Foundation, |
| * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. |
| * |
| * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA |
| * or visit www.oracle.com if you need additional information or have any |
| * questions. |
| */ |
| |
| package com.sun.tools.javac.jvm; |
| |
| import java.io.IOException; |
| import java.io.Writer; |
| import java.util.ArrayList; |
| import java.util.List; |
| import java.util.Stack; |
| import java.util.StringTokenizer; |
| |
| import javax.lang.model.element.Element; |
| import javax.lang.model.element.ExecutableElement; |
| import javax.lang.model.element.Modifier; |
| import javax.lang.model.element.Name; |
| import javax.lang.model.element.TypeElement; |
| import javax.lang.model.element.VariableElement; |
| import javax.lang.model.type.ArrayType; |
| import javax.lang.model.type.DeclaredType; |
| import javax.lang.model.type.NoType; |
| import javax.lang.model.type.PrimitiveType; |
| import javax.lang.model.type.TypeKind; |
| import javax.lang.model.type.TypeMirror; |
| import javax.lang.model.type.TypeVariable; |
| import javax.lang.model.type.TypeVisitor; |
| import javax.lang.model.util.ElementFilter; |
| import javax.lang.model.util.Elements; |
| import javax.lang.model.util.SimpleTypeVisitor8; |
| import javax.lang.model.util.Types; |
| |
| import javax.tools.FileObject; |
| import javax.tools.JavaFileManager; |
| import javax.tools.StandardLocation; |
| |
| import com.sun.tools.javac.code.Attribute; |
| import com.sun.tools.javac.code.Flags; |
| import com.sun.tools.javac.code.Kinds; |
| import com.sun.tools.javac.code.Scope; |
| import com.sun.tools.javac.code.Symbol.ClassSymbol; |
| import com.sun.tools.javac.code.Symtab; |
| import com.sun.tools.javac.model.JavacElements; |
| import com.sun.tools.javac.model.JavacTypes; |
| import com.sun.tools.javac.util.Assert; |
| import com.sun.tools.javac.util.Context; |
| import com.sun.tools.javac.util.Log; |
| import com.sun.tools.javac.util.Options; |
| |
| import static com.sun.tools.javac.main.Option.*; |
| |
| /** This class provides operations to write native header files for classes. |
| * |
| * <p><b>This is NOT part of any supported API. |
| * If you write code that depends on this, you do so at your own risk. |
| * This code and its internal interfaces are subject to change or |
| * deletion without notice.</b> |
| */ |
| public class JNIWriter { |
| protected static final Context.Key<JNIWriter> jniWriterKey = |
| new Context.Key<JNIWriter>(); |
| |
| /** Access to files. */ |
| private final JavaFileManager fileManager; |
| |
| JavacElements elements; |
| JavacTypes types; |
| |
| /** The log to use for verbose output. |
| */ |
| private final Log log; |
| |
| /** Switch: verbose output. |
| */ |
| private boolean verbose; |
| |
| /** Switch: check all nested classes of top level class |
| */ |
| private boolean checkAll; |
| |
| private Mangle mangler; |
| |
| private Context context; |
| |
| private Symtab syms; |
| |
| private String lineSep; |
| |
| private final boolean isWindows = |
| System.getProperty("os.name").startsWith("Windows"); |
| |
| /** Get the ClassWriter instance for this context. */ |
| public static JNIWriter instance(Context context) { |
| JNIWriter instance = context.get(jniWriterKey); |
| if (instance == null) |
| instance = new JNIWriter(context); |
| return instance; |
| } |
| |
| /** Construct a class writer, given an options table. |
| */ |
| private JNIWriter(Context context) { |
| context.put(jniWriterKey, this); |
| fileManager = context.get(JavaFileManager.class); |
| log = Log.instance(context); |
| |
| Options options = Options.instance(context); |
| verbose = options.isSet(VERBOSE); |
| checkAll = options.isSet("javah:full"); |
| |
| this.context = context; // for lazyInit() |
| syms = Symtab.instance(context); |
| |
| lineSep = System.getProperty("line.separator"); |
| } |
| |
| private void lazyInit() { |
| if (mangler == null) { |
| elements = JavacElements.instance(context); |
| types = JavacTypes.instance(context); |
| mangler = new Mangle(elements, types); |
| } |
| } |
| |
| public boolean needsHeader(ClassSymbol c) { |
| if (c.isLocal() || (c.flags() & Flags.SYNTHETIC) != 0) |
| return false; |
| |
| if (checkAll) |
| return needsHeader(c.outermostClass(), true); |
| else |
| return needsHeader(c, false); |
| } |
| |
| private boolean needsHeader(ClassSymbol c, boolean checkNestedClasses) { |
| if (c.isLocal() || (c.flags() & Flags.SYNTHETIC) != 0) |
| return false; |
| |
| for (Scope.Entry i = c.members_field.elems; i != null; i = i.sibling) { |
| if (i.sym.kind == Kinds.MTH && (i.sym.flags() & Flags.NATIVE) != 0) |
| return true; |
| for (Attribute.Compound a: i.sym.getDeclarationAttributes()) { |
| if (a.type.tsym == syms.nativeHeaderType.tsym) |
| return true; |
| } |
| } |
| if (checkNestedClasses) { |
| for (Scope.Entry i = c.members_field.elems; i != null; i = i.sibling) { |
| if ((i.sym.kind == Kinds.TYP) && needsHeader(((ClassSymbol) i.sym), true)) |
| return true; |
| } |
| } |
| return false; |
| } |
| |
| /** Emit a class file for a given class. |
| * @param c The class from which a class file is generated. |
| */ |
| public FileObject write(ClassSymbol c) |
| throws IOException |
| { |
| String className = c.flatName().toString(); |
| FileObject outFile |
| = fileManager.getFileForOutput(StandardLocation.NATIVE_HEADER_OUTPUT, |
| "", className.replaceAll("[.$]", "_") + ".h", null); |
| Writer out = outFile.openWriter(); |
| try { |
| write(out, c); |
| if (verbose) |
| log.printVerbose("wrote.file", outFile); |
| out.close(); |
| out = null; |
| } finally { |
| if (out != null) { |
| // if we are propogating an exception, delete the file |
| out.close(); |
| outFile.delete(); |
| outFile = null; |
| } |
| } |
| return outFile; // may be null if write failed |
| } |
| |
| public void write(Writer out, ClassSymbol sym) |
| throws IOException { |
| lazyInit(); |
| try { |
| String cname = mangler.mangle(sym.fullname, Mangle.Type.CLASS); |
| println(out, fileTop()); |
| println(out, includes()); |
| println(out, guardBegin(cname)); |
| println(out, cppGuardBegin()); |
| |
| writeStatics(out, sym); |
| writeMethods(out, sym, cname); |
| |
| println(out, cppGuardEnd()); |
| println(out, guardEnd(cname)); |
| } catch (TypeSignature.SignatureException e) { |
| throw new IOException(e); |
| } |
| } |
| |
| protected void writeStatics(Writer out, ClassSymbol sym) throws IOException { |
| List<VariableElement> classfields = getAllFields(sym); |
| |
| for (VariableElement v: classfields) { |
| if (!v.getModifiers().contains(Modifier.STATIC)) |
| continue; |
| String s = null; |
| s = defineForStatic(sym, v); |
| if (s != null) { |
| println(out, s); |
| } |
| } |
| } |
| |
| /** |
| * Including super class fields. |
| */ |
| List<VariableElement> getAllFields(TypeElement subclazz) { |
| List<VariableElement> fields = new ArrayList<VariableElement>(); |
| TypeElement cd = null; |
| Stack<TypeElement> s = new Stack<TypeElement>(); |
| |
| cd = subclazz; |
| while (true) { |
| s.push(cd); |
| TypeElement c = (TypeElement) (types.asElement(cd.getSuperclass())); |
| if (c == null) |
| break; |
| cd = c; |
| } |
| |
| while (!s.empty()) { |
| cd = s.pop(); |
| fields.addAll(ElementFilter.fieldsIn(cd.getEnclosedElements())); |
| } |
| |
| return fields; |
| } |
| |
| protected String defineForStatic(TypeElement c, VariableElement f) { |
| CharSequence cnamedoc = c.getQualifiedName(); |
| CharSequence fnamedoc = f.getSimpleName(); |
| |
| String cname = mangler.mangle(cnamedoc, Mangle.Type.CLASS); |
| String fname = mangler.mangle(fnamedoc, Mangle.Type.FIELDSTUB); |
| |
| Assert.check(f.getModifiers().contains(Modifier.STATIC)); |
| |
| if (f.getModifiers().contains(Modifier.FINAL)) { |
| Object value = null; |
| |
| value = f.getConstantValue(); |
| |
| if (value != null) { /* so it is a ConstantExpression */ |
| String constString = null; |
| if ((value instanceof Integer) |
| || (value instanceof Byte) |
| || (value instanceof Short)) { |
| /* covers byte, short, int */ |
| constString = value.toString() + "L"; |
| } else if (value instanceof Boolean) { |
| constString = ((Boolean) value) ? "1L" : "0L"; |
| } else if (value instanceof Character) { |
| Character ch = (Character) value; |
| constString = String.valueOf(((int) ch) & 0xffff) + "L"; |
| } else if (value instanceof Long) { |
| // Visual C++ supports the i64 suffix, not LL. |
| if (isWindows) |
| constString = value.toString() + "i64"; |
| else |
| constString = value.toString() + "LL"; |
| } else if (value instanceof Float) { |
| /* bug for bug */ |
| float fv = ((Float)value).floatValue(); |
| if (Float.isInfinite(fv)) |
| constString = ((fv < 0) ? "-" : "") + "Inff"; |
| else |
| constString = value.toString() + "f"; |
| } else if (value instanceof Double) { |
| /* bug for bug */ |
| double d = ((Double)value).doubleValue(); |
| if (Double.isInfinite(d)) |
| constString = ((d < 0) ? "-" : "") + "InfD"; |
| else |
| constString = value.toString(); |
| } |
| |
| if (constString != null) { |
| StringBuilder s = new StringBuilder("#undef "); |
| s.append(cname); s.append("_"); s.append(fname); s.append(lineSep); |
| s.append("#define "); s.append(cname); s.append("_"); |
| s.append(fname); s.append(" "); s.append(constString); |
| return s.toString(); |
| } |
| |
| } |
| } |
| |
| return null; |
| } |
| |
| |
| protected void writeMethods(Writer out, ClassSymbol sym, String cname) |
| throws IOException, TypeSignature.SignatureException { |
| List<ExecutableElement> classmethods = ElementFilter.methodsIn(sym.getEnclosedElements()); |
| for (ExecutableElement md: classmethods) { |
| if(md.getModifiers().contains(Modifier.NATIVE)){ |
| TypeMirror mtr = types.erasure(md.getReturnType()); |
| String sig = signature(md); |
| TypeSignature newtypesig = new TypeSignature(elements); |
| CharSequence methodName = md.getSimpleName(); |
| boolean longName = false; |
| for (ExecutableElement md2: classmethods) { |
| if ((md2 != md) |
| && (methodName.equals(md2.getSimpleName())) |
| && (md2.getModifiers().contains(Modifier.NATIVE))) |
| longName = true; |
| |
| } |
| println(out, "/*"); |
| println(out, " * Class: " + cname); |
| println(out, " * Method: " + |
| mangler.mangle(methodName, Mangle.Type.FIELDSTUB)); |
| println(out, " * Signature: " + newtypesig.getTypeSignature(sig, mtr)); |
| println(out, " */"); |
| println(out, "JNIEXPORT " + jniType(mtr) + |
| " JNICALL " + |
| mangler.mangleMethod(md, sym, |
| (longName) ? |
| Mangle.Type.METHOD_JNI_LONG : |
| Mangle.Type.METHOD_JNI_SHORT)); |
| print(out, " (JNIEnv *, "); |
| List<? extends VariableElement> paramargs = md.getParameters(); |
| List<TypeMirror> args = new ArrayList<TypeMirror>(); |
| for (VariableElement p: paramargs) { |
| args.add(types.erasure(p.asType())); |
| } |
| if (md.getModifiers().contains(Modifier.STATIC)) |
| print(out, "jclass"); |
| else |
| print(out, "jobject"); |
| |
| for (TypeMirror arg: args) { |
| print(out, ", "); |
| print(out, jniType(arg)); |
| } |
| println(out, ");" |
| + lineSep); |
| } |
| } |
| } |
| |
| // c.f. MethodDoc.signature |
| String signature(ExecutableElement e) { |
| StringBuilder sb = new StringBuilder("("); |
| String sep = ""; |
| for (VariableElement p: e.getParameters()) { |
| sb.append(sep); |
| sb.append(types.erasure(p.asType()).toString()); |
| sep = ","; |
| } |
| sb.append(")"); |
| return sb.toString(); |
| } |
| |
| protected final String jniType(TypeMirror t) { |
| TypeElement throwable = elements.getTypeElement("java.lang.Throwable"); |
| TypeElement jClass = elements.getTypeElement("java.lang.Class"); |
| TypeElement jString = elements.getTypeElement("java.lang.String"); |
| Element tclassDoc = types.asElement(t); |
| |
| |
| switch (t.getKind()) { |
| case ARRAY: { |
| TypeMirror ct = ((ArrayType) t).getComponentType(); |
| switch (ct.getKind()) { |
| case BOOLEAN: return "jbooleanArray"; |
| case BYTE: return "jbyteArray"; |
| case CHAR: return "jcharArray"; |
| case SHORT: return "jshortArray"; |
| case INT: return "jintArray"; |
| case LONG: return "jlongArray"; |
| case FLOAT: return "jfloatArray"; |
| case DOUBLE: return "jdoubleArray"; |
| case ARRAY: |
| case DECLARED: return "jobjectArray"; |
| default: throw new Error(ct.toString()); |
| } |
| } |
| |
| case VOID: return "void"; |
| case BOOLEAN: return "jboolean"; |
| case BYTE: return "jbyte"; |
| case CHAR: return "jchar"; |
| case SHORT: return "jshort"; |
| case INT: return "jint"; |
| case LONG: return "jlong"; |
| case FLOAT: return "jfloat"; |
| case DOUBLE: return "jdouble"; |
| |
| case DECLARED: { |
| if (tclassDoc.equals(jString)) |
| return "jstring"; |
| else if (types.isAssignable(t, throwable.asType())) |
| return "jthrowable"; |
| else if (types.isAssignable(t, jClass.asType())) |
| return "jclass"; |
| else |
| return "jobject"; |
| } |
| } |
| |
| Assert.check(false, "jni unknown type"); |
| return null; /* dead code. */ |
| } |
| |
| protected String fileTop() { |
| return "/* DO NOT EDIT THIS FILE - it is machine generated */"; |
| } |
| |
| protected String includes() { |
| return "#include <jni.h>"; |
| } |
| |
| /* |
| * Deal with the C pre-processor. |
| */ |
| protected String cppGuardBegin() { |
| return "#ifdef __cplusplus" + lineSep |
| + "extern \"C\" {" + lineSep |
| + "#endif"; |
| } |
| |
| protected String cppGuardEnd() { |
| return "#ifdef __cplusplus" + lineSep |
| + "}" + lineSep |
| + "#endif"; |
| } |
| |
| protected String guardBegin(String cname) { |
| return "/* Header for class " + cname + " */" + lineSep |
| + lineSep |
| + "#ifndef _Included_" + cname + lineSep |
| + "#define _Included_" + cname; |
| } |
| |
| protected String guardEnd(String cname) { |
| return "#endif"; |
| } |
| |
| protected void print(Writer out, String text) throws IOException { |
| out.write(text); |
| } |
| |
| protected void println(Writer out, String text) throws IOException { |
| out.write(text); |
| out.write(lineSep); |
| } |
| |
| |
| private static class Mangle { |
| |
| public static class Type { |
| public static final int CLASS = 1; |
| public static final int FIELDSTUB = 2; |
| public static final int FIELD = 3; |
| public static final int JNI = 4; |
| public static final int SIGNATURE = 5; |
| public static final int METHOD_JDK_1 = 6; |
| public static final int METHOD_JNI_SHORT = 7; |
| public static final int METHOD_JNI_LONG = 8; |
| }; |
| |
| private Elements elems; |
| private Types types; |
| |
| Mangle(Elements elems, Types types) { |
| this.elems = elems; |
| this.types = types; |
| } |
| |
| public final String mangle(CharSequence name, int mtype) { |
| StringBuilder result = new StringBuilder(100); |
| int length = name.length(); |
| |
| for (int i = 0; i < length; i++) { |
| char ch = name.charAt(i); |
| if (isalnum(ch)) { |
| result.append(ch); |
| } else if ((ch == '.') && |
| mtype == Mangle.Type.CLASS) { |
| result.append('_'); |
| } else if (( ch == '$') && |
| mtype == Mangle.Type.CLASS) { |
| result.append('_'); |
| result.append('_'); |
| } else if (ch == '_' && mtype == Mangle.Type.FIELDSTUB) { |
| result.append('_'); |
| } else if (ch == '_' && mtype == Mangle.Type.CLASS) { |
| result.append('_'); |
| } else if (mtype == Mangle.Type.JNI) { |
| String esc = null; |
| if (ch == '_') |
| esc = "_1"; |
| else if (ch == '.') |
| esc = "_"; |
| else if (ch == ';') |
| esc = "_2"; |
| else if (ch == '[') |
| esc = "_3"; |
| if (esc != null) { |
| result.append(esc); |
| } else { |
| result.append(mangleChar(ch)); |
| } |
| } else if (mtype == Mangle.Type.SIGNATURE) { |
| if (isprint(ch)) { |
| result.append(ch); |
| } else { |
| result.append(mangleChar(ch)); |
| } |
| } else { |
| result.append(mangleChar(ch)); |
| } |
| } |
| |
| return result.toString(); |
| } |
| |
| public String mangleMethod(ExecutableElement method, TypeElement clazz, |
| int mtype) throws TypeSignature.SignatureException { |
| StringBuilder result = new StringBuilder(100); |
| result.append("Java_"); |
| |
| if (mtype == Mangle.Type.METHOD_JDK_1) { |
| result.append(mangle(clazz.getQualifiedName(), Mangle.Type.CLASS)); |
| result.append('_'); |
| result.append(mangle(method.getSimpleName(), |
| Mangle.Type.FIELD)); |
| result.append("_stub"); |
| return result.toString(); |
| } |
| |
| /* JNI */ |
| result.append(mangle(getInnerQualifiedName(clazz), Mangle.Type.JNI)); |
| result.append('_'); |
| result.append(mangle(method.getSimpleName(), |
| Mangle.Type.JNI)); |
| if (mtype == Mangle.Type.METHOD_JNI_LONG) { |
| result.append("__"); |
| String typesig = signature(method); |
| TypeSignature newTypeSig = new TypeSignature(elems); |
| String sig = newTypeSig.getTypeSignature(typesig, method.getReturnType()); |
| sig = sig.substring(1); |
| sig = sig.substring(0, sig.lastIndexOf(')')); |
| sig = sig.replace('/', '.'); |
| result.append(mangle(sig, Mangle.Type.JNI)); |
| } |
| |
| return result.toString(); |
| } |
| //where |
| private String getInnerQualifiedName(TypeElement clazz) { |
| return elems.getBinaryName(clazz).toString(); |
| } |
| |
| public final String mangleChar(char ch) { |
| String s = Integer.toHexString(ch); |
| int nzeros = 5 - s.length(); |
| char[] result = new char[6]; |
| result[0] = '_'; |
| for (int i = 1; i <= nzeros; i++) |
| result[i] = '0'; |
| for (int i = nzeros+1, j = 0; i < 6; i++, j++) |
| result[i] = s.charAt(j); |
| return new String(result); |
| } |
| |
| // Warning: duplicated in Gen |
| private String signature(ExecutableElement e) { |
| StringBuilder sb = new StringBuilder(); |
| String sep = "("; |
| for (VariableElement p: e.getParameters()) { |
| sb.append(sep); |
| sb.append(types.erasure(p.asType()).toString()); |
| sep = ","; |
| } |
| sb.append(")"); |
| return sb.toString(); |
| } |
| |
| /* Warning: Intentional ASCII operation. */ |
| private static boolean isalnum(char ch) { |
| return ch <= 0x7f && /* quick test */ |
| ((ch >= 'A' && ch <= 'Z') || |
| (ch >= 'a' && ch <= 'z') || |
| (ch >= '0' && ch <= '9')); |
| } |
| |
| /* Warning: Intentional ASCII operation. */ |
| private static boolean isprint(char ch) { |
| return ch >= 32 && ch <= 126; |
| } |
| } |
| |
| private static class TypeSignature { |
| static class SignatureException extends Exception { |
| private static final long serialVersionUID = 1L; |
| SignatureException(String reason) { |
| super(reason); |
| } |
| } |
| |
| Elements elems; |
| |
| /* Signature Characters */ |
| |
| private static final String SIG_VOID = "V"; |
| private static final String SIG_BOOLEAN = "Z"; |
| private static final String SIG_BYTE = "B"; |
| private static final String SIG_CHAR = "C"; |
| private static final String SIG_SHORT = "S"; |
| private static final String SIG_INT = "I"; |
| private static final String SIG_LONG = "J"; |
| private static final String SIG_FLOAT = "F"; |
| private static final String SIG_DOUBLE = "D"; |
| private static final String SIG_ARRAY = "["; |
| private static final String SIG_CLASS = "L"; |
| |
| |
| |
| public TypeSignature(Elements elems){ |
| this.elems = elems; |
| } |
| |
| /* |
| * Returns the type signature of a field according to JVM specs |
| */ |
| public String getTypeSignature(String javasignature) throws SignatureException { |
| return getParamJVMSignature(javasignature); |
| } |
| |
| /* |
| * Returns the type signature of a method according to JVM specs |
| */ |
| public String getTypeSignature(String javasignature, TypeMirror returnType) |
| throws SignatureException { |
| String signature = null; //Java type signature. |
| String typeSignature = null; //Internal type signature. |
| List<String> params = new ArrayList<String>(); //List of parameters. |
| String paramsig = null; //Java parameter signature. |
| String paramJVMSig = null; //Internal parameter signature. |
| String returnSig = null; //Java return type signature. |
| String returnJVMType = null; //Internal return type signature. |
| int dimensions = 0; //Array dimension. |
| |
| int startIndex = -1; |
| int endIndex = -1; |
| StringTokenizer st = null; |
| int i = 0; |
| |
| // Gets the actual java signature without parentheses. |
| if (javasignature != null) { |
| startIndex = javasignature.indexOf("("); |
| endIndex = javasignature.indexOf(")"); |
| } |
| |
| if (((startIndex != -1) && (endIndex != -1)) |
| &&(startIndex+1 < javasignature.length()) |
| &&(endIndex < javasignature.length())) { |
| signature = javasignature.substring(startIndex+1, endIndex); |
| } |
| |
| // Separates parameters. |
| if (signature != null) { |
| if (signature.indexOf(",") != -1) { |
| st = new StringTokenizer(signature, ","); |
| if (st != null) { |
| while (st.hasMoreTokens()) { |
| params.add(st.nextToken()); |
| } |
| } |
| } else { |
| params.add(signature); |
| } |
| } |
| |
| /* JVM type signature. */ |
| typeSignature = "("; |
| |
| // Gets indivisual internal parameter signature. |
| while (params.isEmpty() != true) { |
| paramsig = params.remove(i).trim(); |
| paramJVMSig = getParamJVMSignature(paramsig); |
| if (paramJVMSig != null) { |
| typeSignature += paramJVMSig; |
| } |
| } |
| |
| typeSignature += ")"; |
| |
| // Get internal return type signature. |
| |
| returnJVMType = ""; |
| if (returnType != null) { |
| dimensions = dimensions(returnType); |
| } |
| |
| //Gets array dimension of return type. |
| while (dimensions-- > 0) { |
| returnJVMType += "["; |
| } |
| if (returnType != null) { |
| returnSig = qualifiedTypeName(returnType); |
| returnJVMType += getComponentType(returnSig); |
| } else { |
| System.out.println("Invalid return type."); |
| } |
| |
| typeSignature += returnJVMType; |
| |
| return typeSignature; |
| } |
| |
| /* |
| * Returns internal signature of a parameter. |
| */ |
| private String getParamJVMSignature(String paramsig) throws SignatureException { |
| String paramJVMSig = ""; |
| String componentType =""; |
| |
| if(paramsig != null){ |
| |
| if(paramsig.indexOf("[]") != -1) { |
| // Gets array dimension. |
| int endindex = paramsig.indexOf("[]"); |
| componentType = paramsig.substring(0, endindex); |
| String dimensionString = paramsig.substring(endindex); |
| if(dimensionString != null){ |
| while(dimensionString.indexOf("[]") != -1){ |
| paramJVMSig += "["; |
| int beginindex = dimensionString.indexOf("]") + 1; |
| if(beginindex < dimensionString.length()){ |
| dimensionString = dimensionString.substring(beginindex); |
| }else |
| dimensionString = ""; |
| } |
| } |
| } else componentType = paramsig; |
| |
| paramJVMSig += getComponentType(componentType); |
| } |
| return paramJVMSig; |
| } |
| |
| /* |
| * Returns internal signature of a component. |
| */ |
| private String getComponentType(String componentType) throws SignatureException { |
| |
| String JVMSig = ""; |
| |
| if(componentType != null){ |
| if(componentType.equals("void")) JVMSig += SIG_VOID ; |
| else if(componentType.equals("boolean")) JVMSig += SIG_BOOLEAN ; |
| else if(componentType.equals("byte")) JVMSig += SIG_BYTE ; |
| else if(componentType.equals("char")) JVMSig += SIG_CHAR ; |
| else if(componentType.equals("short")) JVMSig += SIG_SHORT ; |
| else if(componentType.equals("int")) JVMSig += SIG_INT ; |
| else if(componentType.equals("long")) JVMSig += SIG_LONG ; |
| else if(componentType.equals("float")) JVMSig += SIG_FLOAT ; |
| else if(componentType.equals("double")) JVMSig += SIG_DOUBLE ; |
| else { |
| if(!componentType.equals("")){ |
| TypeElement classNameDoc = elems.getTypeElement(componentType); |
| |
| if(classNameDoc == null){ |
| throw new SignatureException(componentType); |
| }else { |
| String classname = classNameDoc.getQualifiedName().toString(); |
| String newclassname = classname.replace('.', '/'); |
| JVMSig += "L"; |
| JVMSig += newclassname; |
| JVMSig += ";"; |
| } |
| } |
| } |
| } |
| return JVMSig; |
| } |
| |
| int dimensions(TypeMirror t) { |
| if (t.getKind() != TypeKind.ARRAY) |
| return 0; |
| return 1 + dimensions(((ArrayType) t).getComponentType()); |
| } |
| |
| |
| String qualifiedTypeName(TypeMirror type) { |
| TypeVisitor<Name, Void> v = new SimpleTypeVisitor8<Name, Void>() { |
| @Override |
| public Name visitArray(ArrayType t, Void p) { |
| return t.getComponentType().accept(this, p); |
| } |
| |
| @Override |
| public Name visitDeclared(DeclaredType t, Void p) { |
| return ((TypeElement) t.asElement()).getQualifiedName(); |
| } |
| |
| @Override |
| public Name visitPrimitive(PrimitiveType t, Void p) { |
| return elems.getName(t.toString()); |
| } |
| |
| @Override |
| public Name visitNoType(NoType t, Void p) { |
| if (t.getKind() == TypeKind.VOID) |
| return elems.getName("void"); |
| return defaultAction(t, p); |
| } |
| |
| @Override |
| public Name visitTypeVariable(TypeVariable t, Void p) { |
| return t.getUpperBound().accept(this, p); |
| } |
| }; |
| return v.visit(type).toString(); |
| } |
| } |
| |
| } |