blob: f2a4b73954ef48be7b74573bc2e7bb4cf7fab08f [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.harmony.tools.javah;
import org.apache.bcel.classfile.ExceptionTable;
import org.apache.bcel.classfile.Method;
import org.apache.bcel.generic.ArrayType;
import org.apache.bcel.generic.ObjectType;
import org.apache.bcel.generic.Type;
import org.apache.harmony.tools.Mangler;
/**
* This class is a wrapper of BCEL's Method class.
*
* This class depends on Apache Byte Code Engineering Library (BCEL) 5.0 or
* later. Please see http://jakarta.apache.org/bcel for more information
* about this library.
*/
public class ClazzMethod {
/**
* An owner class.
*/
private Clazz clazz;
/**
* A wrapped method.
*/
private Method wrappedMethod;
/**
* Indicates if a wrapped method is overloaded.
*/
private boolean overloaded;
/**
* Constructs a <code>ClazzMethod</code> object.
*
* @param clazz - an owner.
* @param wrappedMethod - a wrapped Method class.
* @param overloaded - <code>true</code> if the wrapped method
* is overloaded; <code>false</code> otherwise.
*/
public ClazzMethod(Clazz clazz, Method wrappedMethod, boolean overloaded) {
this.clazz = clazz;
this.wrappedMethod = wrappedMethod;
this.overloaded = overloaded;
}
/**
* Returns the argument types.
*
* @return an array of the argument types.
*/
private Type[] getArgumentTypes() {
return Type.getArgumentTypes(wrappedMethod.getSignature());
}
/**
* Returns the return type.
*
* @return the return type.
*/
private Type getReturnType() {
return Type.getReturnType(wrappedMethod.getSignature());
}
/**
* Returns a parameters signature.
*
* @return a parameters signature string.
*/
private String getParamsSignature() {
StringBuffer result = new StringBuffer();
Type types[] = getArgumentTypes();
for (int i = 0; i < types.length; i++) {
result.append(types[i].getSignature());
}
return result.toString();
}
/**
* Returns a method signature.
*
* @return a method signature string.
*/
public String getSignature() {
return wrappedMethod.getSignature();
}
/**
* Determines if a wrapped method is static.
*
* @return <code>true</code> if a wrapped method is static;
* <code>false</code> otherwise.
*/
private boolean isStatic() {
return wrappedMethod.isStatic();
}
/**
* Returns a name of a wrapped method.
*
* @return a method name.
*/
public String getName() {
return wrappedMethod.getName();
}
/**
* Returns a mangled name of a wrapped method.
*
* @return a mangled method name.
*/
public String getMangledName() {
String result = Mangler.mangleMethodName(getName());
if (overloaded) {
result = result + "__" + Mangler.mangleMethodName(getParamsSignature());
}
return result;
}
/**
* Returns a JNI-style representation of the method return data type.
*
* @return a return type JNI-style representation.
*/
private String getJNIReturnType() {
return ClazzMethod.getJNIType(getReturnType());
}
/**
* Returns a string that represents a method part of
* a JNI-style header file.
*/
public String toString() {
String n = System.getProperty("line.separator");
StringBuffer result = new StringBuffer();
String methodName = Mangler.mangleUnicode(
clazz.getName() + "." + getName() + getSignature());
// Print a method comment.
result.append("/*" + n);
result.append(" * Method: " + methodName + n);
// Print the thrown exceptions.
ExceptionTable etable = wrappedMethod.getExceptionTable();
if (etable != null) {
String e = etable.toString();
if (e.length() > 0) {
result.append(" * Throws: ");
result.append(e);
result.append(n);
}
}
result.append(" */" + n);
// Print a method declaration in a readable way.
result.append("JNIEXPORT " + getJNIReturnType() + " JNICALL" + n);
result.append("Java_" + clazz.getMangledName() + "_" + getMangledName());
result.append('(');
result.append("JNIEnv *");
if (isStatic()) {
result.append(", jclass");
} else {
result.append(", jobject");
}
Type types[] = getArgumentTypes();
for (int i = 0; i < types.length; i++) {
result.append(", ");
if (i == 0) {
result.append(n);
result.append(" ");
}
result.append(ClazzMethod.getJNIType(types[i]));
}
result.append(");" + n);
result.append(n);
return result.toString();
}
/**
* Returns an alternative string that represents a method part of
* a JNI-style header file.
*/
public String toAlternativeString() {
String n = System.getProperty("line.separator");
StringBuffer result = new StringBuffer();
// Print a method comment.
result.append("/*" + n);
result.append(" * Class: " + Mangler.mangleUnicode(clazz.getName())
+ n);
result.append(" * Method: " + Mangler.mangleUnicode(getName()) + n);
result.append(" * Signature: " + getSignature() + n);
// Print the thrown exceptions.
ExceptionTable etable = wrappedMethod.getExceptionTable();
if (etable != null) {
String e = etable.toString();
if (e.length() > 0) {
result.append(" * Throws: ");
result.append(e);
result.append(n);
}
}
result.append(" */" + n);
// Print a method declaration in a readable way.
result.append("JNIEXPORT " + getJNIReturnType() + " JNICALL "
+ "Java_" + clazz.getMangledName() + "_" + getMangledName() + n);
result.append(" (JNIEnv *, ");
if (isStatic()) {
result.append("jclass");
} else {
result.append("jobject");
}
Type types[] = getArgumentTypes();
for (int i = 0; i < types.length; i++) {
result.append(", ");
result.append(ClazzMethod.getJNIType(types[i]));
}
result.append(");" + n);
result.append(n);
return result.toString();
}
/**
* Returns a JNI-style representation of the given data type passed
* as a Class object.
*
* @param type - a Class object that wraps a data type.
* @return a string that represents a JNI-style data type.
*/
public static String getJNIType(Type type) {
StringBuffer result = new StringBuffer();
String suffix = "";
if (type instanceof ArrayType) {
suffix = "Array";
type = ((ArrayType) type).getElementType();
}
if (type instanceof ObjectType) {
String objectType = "jobject";
// The suffix length is 0 only if the given type is not an array.
if (suffix.length() == 0) {
if (type.equals(Type.STRING)) {
objectType = "jstring";
} else if (type.equals(Type.THROWABLE)) {
objectType = "jthrowable";
} else if (((ObjectType) type).getClassName()
.equals("java.lang.Class")) {
objectType = "jclass";
}
}
result.append(objectType);
} else if (type == Type.INT) {
result.append("jint");
} else if (type == Type.BYTE) {
result.append("jbyte");
} else if (type == Type.LONG) {
result.append("jlong");
} else if (type == Type.FLOAT) {
result.append("jfloat");
} else if (type == Type.DOUBLE) {
result.append("jdouble");
} else if (type == Type.SHORT) {
result.append("jshort");
} else if (type == Type.CHAR) {
result.append("jchar");
} else if (type == Type.BOOLEAN) {
result.append("jboolean");
} else if (type == Type.VOID) {
result.append("void");
}
return result.append(suffix).toString();
}
}