001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one or more
003: * contributor license agreements. See the NOTICE file distributed with
004: * this work for additional information regarding copyright ownership.
005: * The ASF licenses this file to You under the Apache License, Version 2.0
006: * (the "License"); you may not use this file except in compliance with
007: * the License. You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: */
017:
018: package org.apache.harmony.tools.javah;
019:
020: import org.apache.bcel.classfile.ExceptionTable;
021: import org.apache.bcel.classfile.Method;
022: import org.apache.bcel.generic.ArrayType;
023: import org.apache.bcel.generic.ObjectType;
024: import org.apache.bcel.generic.Type;
025: import org.apache.harmony.tools.Mangler;
026:
027: /**
028: * This class is a wrapper of BCEL's Method class.
029: *
030: * This class depends on Apache Byte Code Engineering Library (BCEL) 5.0 or
031: * later. Please see http://jakarta.apache.org/bcel for more information
032: * about this library.
033: */
034: public class ClazzMethod {
035:
036: /**
037: * An owner class.
038: */
039: private Clazz clazz;
040:
041: /**
042: * A wrapped method.
043: */
044: private Method wrappedMethod;
045:
046: /**
047: * Indicates if a wrapped method is overloaded.
048: */
049: private boolean overloaded;
050:
051: /**
052: * Constructs a <code>ClazzMethod</code> object.
053: *
054: * @param clazz - an owner.
055: * @param wrappedMethod - a wrapped Method class.
056: * @param overloaded - <code>true</code> if the wrapped method
057: * is overloaded; <code>false</code> otherwise.
058: */
059: public ClazzMethod(Clazz clazz, Method wrappedMethod,
060: boolean overloaded) {
061: this .clazz = clazz;
062: this .wrappedMethod = wrappedMethod;
063: this .overloaded = overloaded;
064: }
065:
066: /**
067: * Returns the argument types.
068: *
069: * @return an array of the argument types.
070: */
071: private Type[] getArgumentTypes() {
072: return Type.getArgumentTypes(wrappedMethod.getSignature());
073: }
074:
075: /**
076: * Returns the return type.
077: *
078: * @return the return type.
079: */
080: private Type getReturnType() {
081: return Type.getReturnType(wrappedMethod.getSignature());
082: }
083:
084: /**
085: * Returns a parameters signature.
086: *
087: * @return a parameters signature string.
088: */
089: private String getParamsSignature() {
090: StringBuffer result = new StringBuffer();
091:
092: Type types[] = getArgumentTypes();
093: for (int i = 0; i < types.length; i++) {
094: result.append(types[i].getSignature());
095: }
096:
097: return result.toString();
098: }
099:
100: /**
101: * Returns a method signature.
102: *
103: * @return a method signature string.
104: */
105: public String getSignature() {
106: return wrappedMethod.getSignature();
107: }
108:
109: /**
110: * Determines if a wrapped method is static.
111: *
112: * @return <code>true</code> if a wrapped method is static;
113: * <code>false</code> otherwise.
114: */
115: private boolean isStatic() {
116: return wrappedMethod.isStatic();
117: }
118:
119: /**
120: * Returns a name of a wrapped method.
121: *
122: * @return a method name.
123: */
124: public String getName() {
125: return wrappedMethod.getName();
126: }
127:
128: /**
129: * Returns a mangled name of a wrapped method.
130: *
131: * @return a mangled method name.
132: */
133: public String getMangledName() {
134: String result = Mangler.mangleMethodName(getName());
135: if (overloaded) {
136: result = result + "__"
137: + Mangler.mangleMethodName(getParamsSignature());
138: }
139: return result;
140: }
141:
142: /**
143: * Returns a JNI-style representation of the method return data type.
144: *
145: * @return a return type JNI-style representation.
146: */
147: private String getJNIReturnType() {
148: return ClazzMethod.getJNIType(getReturnType());
149: }
150:
151: /**
152: * Returns a string that represents a method part of
153: * a JNI-style header file.
154: */
155: public String toString() {
156: String n = System.getProperty("line.separator");
157: StringBuffer result = new StringBuffer();
158:
159: String methodName = Mangler.mangleUnicode(clazz.getName() + "."
160: + getName() + getSignature());
161:
162: // Print a method comment.
163: result.append("/*" + n);
164: result.append(" * Method: " + methodName + n);
165:
166: // Print the thrown exceptions.
167: ExceptionTable etable = wrappedMethod.getExceptionTable();
168: if (etable != null) {
169: String e = etable.toString();
170: if (e.length() > 0) {
171: result.append(" * Throws: ");
172: result.append(e);
173: result.append(n);
174: }
175: }
176:
177: result.append(" */" + n);
178:
179: // Print a method declaration in a readable way.
180: result.append("JNIEXPORT " + getJNIReturnType() + " JNICALL"
181: + n);
182: result.append("Java_" + clazz.getMangledName() + "_"
183: + getMangledName());
184:
185: result.append('(');
186: result.append("JNIEnv *");
187: if (isStatic()) {
188: result.append(", jclass");
189: } else {
190: result.append(", jobject");
191: }
192: Type types[] = getArgumentTypes();
193: for (int i = 0; i < types.length; i++) {
194: result.append(", ");
195: if (i == 0) {
196: result.append(n);
197: result.append(" ");
198: }
199: result.append(ClazzMethod.getJNIType(types[i]));
200: }
201: result.append(");" + n);
202: result.append(n);
203:
204: return result.toString();
205: }
206:
207: /**
208: * Returns an alternative string that represents a method part of
209: * a JNI-style header file.
210: */
211: public String toAlternativeString() {
212: String n = System.getProperty("line.separator");
213: StringBuffer result = new StringBuffer();
214:
215: // Print a method comment.
216: result.append("/*" + n);
217: result.append(" * Class: "
218: + Mangler.mangleUnicode(clazz.getName()) + n);
219: result.append(" * Method: "
220: + Mangler.mangleUnicode(getName()) + n);
221: result.append(" * Signature: " + getSignature() + n);
222:
223: // Print the thrown exceptions.
224: ExceptionTable etable = wrappedMethod.getExceptionTable();
225: if (etable != null) {
226: String e = etable.toString();
227: if (e.length() > 0) {
228: result.append(" * Throws: ");
229: result.append(e);
230: result.append(n);
231: }
232: }
233:
234: result.append(" */" + n);
235:
236: // Print a method declaration in a readable way.
237: result.append("JNIEXPORT " + getJNIReturnType() + " JNICALL "
238: + "Java_" + clazz.getMangledName() + "_"
239: + getMangledName() + n);
240:
241: result.append(" (JNIEnv *, ");
242: if (isStatic()) {
243: result.append("jclass");
244: } else {
245: result.append("jobject");
246: }
247: Type types[] = getArgumentTypes();
248: for (int i = 0; i < types.length; i++) {
249: result.append(", ");
250: result.append(ClazzMethod.getJNIType(types[i]));
251: }
252: result.append(");" + n);
253: result.append(n);
254:
255: return result.toString();
256: }
257:
258: /**
259: * Returns a JNI-style representation of the given data type passed
260: * as a Class object.
261: *
262: * @param type - a Class object that wraps a data type.
263: * @return a string that represents a JNI-style data type.
264: */
265: public static String getJNIType(Type type) {
266: StringBuffer result = new StringBuffer();
267:
268: String suffix = "";
269: if (type instanceof ArrayType) {
270: suffix = "Array";
271: type = ((ArrayType) type).getElementType();
272: }
273:
274: if (type instanceof ObjectType) {
275: String objectType = "jobject";
276: // The suffix length is 0 only if the given type is not an array.
277: if (suffix.length() == 0) {
278: if (type.equals(Type.STRING)) {
279: objectType = "jstring";
280: } else if (type.equals(Type.THROWABLE)) {
281: objectType = "jthrowable";
282: } else if (((ObjectType) type).getClassName().equals(
283: "java.lang.Class")) {
284: objectType = "jclass";
285: }
286: }
287: result.append(objectType);
288: } else if (type == Type.INT) {
289: result.append("jint");
290: } else if (type == Type.BYTE) {
291: result.append("jbyte");
292: } else if (type == Type.LONG) {
293: result.append("jlong");
294: } else if (type == Type.FLOAT) {
295: result.append("jfloat");
296: } else if (type == Type.DOUBLE) {
297: result.append("jdouble");
298: } else if (type == Type.SHORT) {
299: result.append("jshort");
300: } else if (type == Type.CHAR) {
301: result.append("jchar");
302: } else if (type == Type.BOOLEAN) {
303: result.append("jboolean");
304: } else if (type == Type.VOID) {
305: result.append("void");
306: }
307:
308: return result.append(suffix).toString();
309: }
310:
311: }
|