001: /*
002: * Signature.java
003: *
004: * Copyright (c) 2005-2007 Sun Microsystems, Inc. All Rights Reserved.
005: *
006: * See the file "LICENSE.txt" for information on usage and redistribution
007: * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
008: */
009: package org.pnuts.lang;
010:
011: import java.util.*;
012: import java.lang.reflect.*;
013: import pnuts.lang.*;
014: import pnuts.lang.Runtime;
015: import pnuts.lang.Package;
016: import pnuts.compiler.*;
017:
018: public class Signature extends Runtime implements Cloneable {
019:
020: String methodName;
021: Class returnType; // UNKNOWN == null
022: int modifiers;
023: Class[] parameterTypes; // UNKNOWN == null
024: Class[] exceptionTypes; // UNKNOWN == null
025: public Object nodeInfo;
026:
027: public Signature(String methodName) {
028: this (methodName, null, null, null);
029: }
030:
031: public Signature(String methodName, Class returnType,
032: Class[] parameterTypes, Class[] exceptionTypes) {
033: this (methodName, returnType, parameterTypes, exceptionTypes,
034: null);
035: }
036:
037: public Signature(String methodName, Class returnType,
038: Class[] parameterTypes, Class[] exceptionTypes,
039: int modifiers) {
040: this (methodName, returnType, parameterTypes, exceptionTypes,
041: null);
042: this .modifiers = modifiers;
043: }
044:
045: public Signature(String methodName, Class returnType,
046: Class[] parameterTypes, Class[] exceptionTypes,
047: Object nodeInfo) {
048: this .methodName = methodName;
049: this .returnType = returnType;
050: if (parameterTypes != null) {
051: this .parameterTypes = (Class[]) parameterTypes.clone();
052: }
053: if (exceptionTypes != null) {
054: this .exceptionTypes = (Class[]) exceptionTypes.clone();
055: }
056: this .nodeInfo = nodeInfo;
057: }
058:
059: public String getMethodName() {
060: return methodName;
061: }
062:
063: public Class getReturnType() {
064: return returnType;
065: }
066:
067: public void setReturnType(Class t) {
068: this .returnType = t;
069: }
070:
071: public Class[] getParameterTypes() {
072: return parameterTypes;
073: }
074:
075: public void setParameterTypes(Class[] types) {
076: parameterTypes = types;
077: }
078:
079: public Class[] getExceptionTypes() {
080: return exceptionTypes;
081: }
082:
083: public void setExceptionTypes(Class[] types) {
084: exceptionTypes = types;
085: }
086:
087: public int getModifiers() {
088: return modifiers;
089: }
090:
091: public void setModifiers(int m) {
092: modifiers = m;
093: }
094:
095: /*
096: public void generateMethod(ClassFile cf, int mode){
097: String sig = toString();
098: SubtypeGenerator.defineMethod(cf, parameterTypes, returnType, exceptionTypes, modifiers,
099: methodName, sig, mode);
100: }
101: */
102: boolean match(String methodName, Class returnType,
103: Class[] parameterTypes, Class[] exceptionTypes) {
104: if (this .methodName != null
105: && !methodName.equals(this .methodName)) {
106: return false;
107: }
108: if (this .returnType != null
109: && !returnType.equals(this .returnType)) {
110: return false;
111: }
112: if (this .parameterTypes != null
113: && this .parameterTypes.length != parameterTypes.length) {
114: return false;
115: }
116: if (this .parameterTypes != null) {
117: for (int i = 0; i < parameterTypes.length; i++) {
118: Class t = this .parameterTypes[i];
119: if (t != null && !parameterTypes[i].equals(t)) {
120: return false;
121: }
122: }
123: }
124: if (this .exceptionTypes != null) {
125: HashSet s1 = new HashSet();
126: for (int i = 0; i < exceptionTypes.length; i++) {
127: s1.add(exceptionTypes[i]);
128: }
129: HashSet s2 = new HashSet();
130: for (int i = 0; i < this .exceptionTypes.length; i++) {
131: s2.add(this .exceptionTypes[i]);
132: }
133: if (!s1.equals(s2)) {
134: return false;
135: }
136: }
137: return true;
138: }
139:
140: public boolean resolve(Class super Class, Class[] interfaces,
141: Collection methods) {
142: Set signatures = new HashSet();
143: if (interfaces != null) {
144: for (int i = 0; i < interfaces.length; i++) {
145: Class _interface = interfaces[i];
146: Method[] _methods = _interface.getMethods();
147: for (int j = 0; j < _methods.length; j++) {
148: Method m = _methods[j];
149: int modifiers = m.getModifiers();
150: if (!Modifier.isPublic(modifiers)
151: && !Modifier.isProtected(modifiers)
152: || Modifier.isStatic(modifiers)
153: || Modifier.isFinal(modifiers)) {
154: continue;
155: }
156: Class[] parameterTypes = m.getParameterTypes();
157: Class[] exceptionTypes = m.getExceptionTypes();
158: String signature = methodName
159: + ClassFile.signature(parameterTypes);
160: if (match(m.getName(), m.getReturnType(),
161: parameterTypes, exceptionTypes)) {
162: if (signatures.add(ClassFile
163: .signature(parameterTypes))) {
164: methods.add(m);
165: }
166: }
167: }
168: }
169: }
170: if (super Class == null) {
171: super Class = Object.class;
172: }
173: while (super Class != null) {
174: Method[] _methods = ReflectionUtil
175: .getInheritableMethods(super Class);
176: for (int j = 0; j < _methods.length; j++) {
177: Method m = _methods[j];
178: int modifiers = m.getModifiers();
179: if (!Modifier.isPublic(modifiers)
180: && !Modifier.isProtected(modifiers)
181: || Modifier.isStatic(modifiers)
182: || Modifier.isFinal(modifiers)) {
183: continue;
184: }
185: Class[] parameterTypes = m.getParameterTypes();
186: Class[] exceptionTypes = m.getExceptionTypes();
187: String signature = methodName
188: + ClassFile.signature(parameterTypes);
189: if (match(m.getName(), m.getReturnType(),
190: parameterTypes, exceptionTypes)) {
191: if (signatures.add(ClassFile
192: .signature(parameterTypes))) {
193: methods.add(m);
194: }
195: }
196: }
197: super Class = super Class.getSuperclass();
198: }
199:
200: return !methods.isEmpty();
201: }
202:
203: static void getInheritableConstructors(Class cls, Set signatures,
204: Set results) {
205: Constructor c[] = cls.getDeclaredConstructors();
206: for (int j = 0; j < c.length; j++) {
207: Constructor cons = c[j];
208: int modifiers = cons.getModifiers();
209: if (!Modifier.isPublic(modifiers)
210: && !Modifier.isProtected(modifiers)
211: || Modifier.isStatic(modifiers)
212: || Modifier.isFinal(modifiers)) {
213: continue;
214: }
215: String sig = ClassFile.signature(cons.getParameterTypes());
216: if (signatures.add(sig)) {
217: results.add(cons);
218: }
219: }
220: }
221:
222: static Constructor[] getInheritableConstructors(Class cls) {
223: Set s = new HashSet();
224: Set sig = new HashSet();
225: if (cls != null) {
226: getInheritableConstructors(cls, sig, s);
227: }
228: return (Constructor[]) s.toArray(new Constructor[s.size()]);
229: }
230:
231: public boolean resolveAsConstructor(Class cls,
232: Collection/*<Constructor>*/constructors) {
233: Constructor c[] = getInheritableConstructors(cls);
234: for (int i = 0; i < c.length; i++) {
235: Constructor cons = c[i];
236: Class[] parameterTypes = cons.getParameterTypes();
237: Class[] exceptionTypes = cons.getExceptionTypes();
238: if (match(null, null, parameterTypes, exceptionTypes)) {
239: constructors.add(cons);
240: }
241: }
242: return !constructors.isEmpty();
243: }
244:
245: static String makeSignature(Class[] parameterTypes) {
246: StringBuffer buf = new StringBuffer("(");
247: for (int i = 0; i < parameterTypes.length; i++) {
248: Class type = parameterTypes[i];
249: if (type == null) {
250: type = Object.class;
251: }
252: buf.append(makeSignature(type));
253: }
254: buf.append(")");
255: return buf.toString();
256: }
257:
258: static String makeSignature(Class[] parameterTypes, Class returnType) {
259: StringBuffer buf = new StringBuffer("(");
260: for (int i = 0; i < parameterTypes.length; i++) {
261: Class type = parameterTypes[i];
262: if (type == null) {
263: type = Object.class;
264: }
265: buf.append(makeSignature(type));
266: }
267: buf.append(")");
268: if (returnType == null) {
269: returnType = Object.class;
270: }
271: buf.append(makeSignature(returnType));
272: return buf.toString();
273: }
274:
275: public static String makeSignature(Class type) {
276: if (type == int.class) {
277: return "I";
278: } else if (type == byte.class) {
279: return "B";
280: } else if (type == long.class) {
281: return "J";
282: } else if (type == char.class) {
283: return "C";
284: } else if (type == short.class) {
285: return "S";
286: } else if (type == float.class) {
287: return "F";
288: } else if (type == double.class) {
289: return "D";
290: } else if (type == boolean.class) {
291: return "Z";
292: } else if (type == void.class) {
293: return "V";
294: } else {
295: if (type.isArray()) {
296: return "[" + makeSignature(type.getComponentType());
297: } else {
298: return "L" + type.getName().replace('.', '/') + ";";
299: }
300: }
301: }
302:
303: public Object clone() {
304: try {
305: return super .clone();
306: } catch (CloneNotSupportedException e) {
307: throw new InternalError();
308: }
309: }
310:
311: public int hashCode() {
312: if (methodName != null) {
313: return methodName.hashCode() * parameterTypes.length;
314: } else {
315: return parameterTypes.length;
316: }
317: }
318:
319: public boolean equals(Object obj) {
320: if (obj instanceof Signature) {
321: Signature sig = (Signature) obj;
322: return sig.toString().equals(toString());
323: }
324: return false;
325: }
326:
327: public String toString() {
328: if (methodName != null) {
329: return (methodName + makeSignature(parameterTypes))
330: .intern();
331: } else {
332: return makeSignature(parameterTypes).intern();
333: }
334: }
335:
336: public boolean isResolved() {
337: return returnType != null && parameterTypes != null
338: && exceptionTypes != null;
339: }
340:
341: public String toJavaIdentifier() {
342: return toJavaIdentifier(toString());
343: }
344:
345: public static String toJavaIdentifier(String signature) {
346: StringBuffer sbuf = new StringBuffer();
347: for (int i = 0, len = signature.length(); i < len; i++) {
348: char ch = signature.charAt(i);
349: switch (ch) {
350: case '(':
351: sbuf.append("$0");
352: break;
353: case ')':
354: sbuf.append("$1");
355: break;
356: case ';':
357: sbuf.append("$2");
358: break;
359: case '/':
360: sbuf.append("$3");
361: break;
362: case '$':
363: sbuf.append("$$");
364: break;
365: default:
366: sbuf.append(ch);
367: }
368: }
369: return sbuf.toString();
370: }
371:
372: }
|