001: /*
002: * Janino - An embedded Java[TM] compiler
003: *
004: * Copyright (c) 2001-2007, Arno Unkrig
005: * All rights reserved.
006: *
007: * Redistribution and use in source and binary forms, with or without
008: * modification, are permitted provided that the following conditions
009: * are met:
010: *
011: * 1. Redistributions of source code must retain the above copyright
012: * notice, this list of conditions and the following disclaimer.
013: * 2. Redistributions in binary form must reproduce the above
014: * copyright notice, this list of conditions and the following
015: * disclaimer in the documentation and/or other materials
016: * provided with the distribution.
017: * 3. The name of the author may not be used to endorse or promote
018: * products derived from this software without specific prior
019: * written permission.
020: *
021: * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
022: * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
023: * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
024: * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
025: * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
026: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
027: * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
028: * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
029: * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
030: * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
031: * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
032: */
033:
034: package org.codehaus.janino;
035:
036: import java.util.*;
037: import java.lang.reflect.*;
038:
039: /**
040: * Wraps a {@link java.lang.Class} in an {@link org.codehaus.janino.IClass}.
041: */
042: class ReflectionIClass extends IClass {
043: private/*final*/Class clazz;
044: private/*final*/IClassLoader iClassLoader;
045:
046: /**
047: * @param iClassLoader required to load other {@link IClass}es on <code>get...()</code>.
048: */
049: public ReflectionIClass(Class clazz, IClassLoader iClassLoader) {
050: this .clazz = clazz;
051: this .iClassLoader = iClassLoader;
052: }
053:
054: protected IConstructor[] getDeclaredIConstructors2() {
055: Constructor[] constructors = this .clazz
056: .getDeclaredConstructors();
057: IConstructor[] result = new IConstructor[constructors.length];
058: for (int i = 0; i < constructors.length; ++i) {
059: result[i] = new ReflectionIConstructor(constructors[i]);
060: }
061: return result;
062: }
063:
064: protected IMethod[] getDeclaredIMethods2() {
065: Method[] methods = this .clazz.getDeclaredMethods();
066: List iMethods = new ArrayList();
067: for (int i = 0; i < methods.length; ++i) {
068: Method m = methods[i];
069:
070: // Skip JDK 1.5 synthetic methods (e.g. those generated for
071: // covariant return values).
072: if ((m.getModifiers() & Mod.SYNTHETIC) != 0)
073: continue;
074:
075: // Wrap java.reflection.Method in an IMethod.
076: iMethods.add(new ReflectionIMethod(m));
077: }
078: if (methods.length == 0 && this .clazz.isArray()) {
079: iMethods.add(new IMethod() {
080: public String getName() {
081: return "clone";
082: }
083:
084: public IClass getReturnType() throws CompileException {
085: return ReflectionIClass.this .iClassLoader.OBJECT;
086: }
087:
088: public boolean isAbstract() {
089: return false;
090: }
091:
092: public boolean isStatic() {
093: return false;
094: }
095:
096: public Access getAccess() {
097: return Access.PUBLIC;
098: }
099:
100: public IClass[] getParameterTypes()
101: throws CompileException {
102: return new IClass[0];
103: }
104:
105: public IClass[] getThrownExceptions()
106: throws CompileException {
107: return new IClass[0];
108: }
109: });
110: }
111: return (IMethod[]) iMethods
112: .toArray(new IMethod[iMethods.size()]);
113: }
114:
115: protected IField[] getDeclaredIFields2() {
116: Field[] fields = this .clazz.getDeclaredFields();
117: IField[] result = new IField[fields.length];
118: for (int i = 0; i < fields.length; ++i) {
119: result[i] = new ReflectionIField(fields[i]);
120: }
121: return result;
122: }
123:
124: protected IClass[] getDeclaredIClasses2() {
125: return this .classesToIClasses(this .clazz.getDeclaredClasses());
126: }
127:
128: protected IClass getDeclaringIClass2() {
129: Class declaringClass = this .clazz.getDeclaringClass();
130: if (declaringClass == null)
131: return null;
132: return this .classToIClass(declaringClass);
133: }
134:
135: protected IClass getOuterIClass2() throws CompileException {
136: if (Modifier.isStatic(this .clazz.getModifiers()))
137: return null;
138: return this .getDeclaringIClass();
139: }
140:
141: protected IClass getSuperclass2() {
142: Class super class = this .clazz.getSuperclass();
143: return super class == null ? null : this
144: .classToIClass(super class);
145: }
146:
147: protected IClass[] getInterfaces2() {
148: return this .classesToIClasses(this .clazz.getInterfaces());
149: }
150:
151: protected String getDescriptor2() {
152: return Descriptor.fromClassName(this .clazz.getName());
153: }
154:
155: public Access getAccess() {
156: return ReflectionIClass.modifiers2Access(this .clazz
157: .getModifiers());
158: }
159:
160: public boolean isFinal() {
161: return Modifier.isFinal(this .clazz.getModifiers());
162: }
163:
164: public boolean isInterface() {
165: return this .clazz.isInterface();
166: }
167:
168: public boolean isAbstract() {
169: return Modifier.isAbstract(this .clazz.getModifiers());
170: }
171:
172: public boolean isArray() {
173: return this .clazz.isArray();
174: }
175:
176: protected IClass getComponentType2() {
177: Class componentType = this .clazz.getComponentType();
178: return componentType == null ? null : this
179: .classToIClass(componentType);
180: }
181:
182: public boolean isPrimitive() {
183: return this .clazz.isPrimitive();
184: }
185:
186: public boolean isPrimitiveNumeric() {
187: return (this .clazz == byte.class || this .clazz == short.class
188: || this .clazz == int.class || this .clazz == long.class
189: || this .clazz == char.class
190: || this .clazz == float.class || this .clazz == double.class);
191: }
192:
193: /**
194: * @return E.g. "int", "int[][]", "pkg1.pkg2.Outer$Inner[]"
195: */
196: public String toString() {
197: int brackets = 0;
198: Class c = this .clazz;
199: while (c.isArray()) {
200: ++brackets;
201: c = c.getComponentType();
202: }
203: String s = c.getName();
204: while (brackets-- > 0)
205: s += "[]";
206: return s;
207: }
208:
209: private class ReflectionIConstructor extends IConstructor {
210: public ReflectionIConstructor(Constructor constructor) {
211: this .constructor = constructor;
212: }
213:
214: // Implement IMember.
215: public Access getAccess() {
216: int mod = this .constructor.getModifiers();
217: return ReflectionIClass.modifiers2Access(mod);
218: }
219:
220: // Implement "IConstructor".
221: public IClass[] getParameterTypes() throws CompileException {
222: IClass[] parameterTypes = ReflectionIClass.this
223: .classesToIClasses(this .constructor
224: .getParameterTypes());
225:
226: // The JAVADOC of java.lang.reflect.Constructor does not document it, but
227: // "getParameterTypes()" includes the synthetic "enclosing instance" parameter.
228: IClass outerClass = ReflectionIClass.this .getOuterIClass();
229: if (outerClass != null) {
230: if (parameterTypes.length < 1)
231: throw new CompileException(
232: "Constructor \""
233: + this .constructor
234: + "\" lacks synthetic enclosing instance parameter",
235: null);
236: if (parameterTypes[0] != outerClass)
237: throw new CompileException(
238: "Enclosing instance parameter of constructor \""
239: + this .constructor
240: + "\" has wrong type -- \""
241: + parameterTypes[0] + "\" vs. \""
242: + outerClass + "\"", null);
243: IClass[] tmp = new IClass[parameterTypes.length - 1];
244: System.arraycopy(parameterTypes, 1, tmp, 0, tmp.length);
245: parameterTypes = tmp;
246: }
247:
248: return parameterTypes;
249: }
250:
251: public String getDescriptor() {
252: Class[] parameterTypes = this .constructor
253: .getParameterTypes();
254: String[] parameterDescriptors = new String[parameterTypes.length];
255: for (int i = 0; i < parameterDescriptors.length; ++i) {
256: parameterDescriptors[i] = Descriptor
257: .fromClassName(parameterTypes[i].getName());
258: }
259: return new MethodDescriptor(parameterDescriptors,
260: Descriptor.VOID_).toString();
261: }
262:
263: public IClass[] getThrownExceptions() {
264: return ReflectionIClass.this
265: .classesToIClasses(this .constructor
266: .getExceptionTypes());
267: }
268:
269: final Constructor constructor;
270: };
271:
272: private class ReflectionIMethod extends IMethod {
273: public ReflectionIMethod(Method method) {
274: this .method = method;
275: }
276:
277: // Implement IMember.
278: public Access getAccess() {
279: return ReflectionIClass.modifiers2Access(this .method
280: .getModifiers());
281: }
282:
283: // Implement "IMethod".
284: public String getName() {
285: return this .method.getName();
286: }
287:
288: public IClass[] getParameterTypes() {
289: return ReflectionIClass.this .classesToIClasses(this .method
290: .getParameterTypes());
291: }
292:
293: public boolean isStatic() {
294: return Modifier.isStatic(this .method.getModifiers());
295: }
296:
297: public boolean isAbstract() {
298: return Modifier.isAbstract(this .method.getModifiers());
299: }
300:
301: public IClass getReturnType() {
302: return ReflectionIClass.this .classToIClass(this .method
303: .getReturnType());
304: }
305:
306: public IClass[] getThrownExceptions() {
307: return ReflectionIClass.this .classesToIClasses(this .method
308: .getExceptionTypes());
309: }
310:
311: final Method method;
312: };
313:
314: private class ReflectionIField extends IField {
315: public ReflectionIField(Field field) {
316: this .field = field;
317: }
318:
319: // Implement IMember.
320: public Access getAccess() {
321: return ReflectionIClass.modifiers2Access(this .field
322: .getModifiers());
323: }
324:
325: // Implement "IField".
326: public String getName() {
327: return this .field.getName();
328: }
329:
330: public boolean isStatic() {
331: return Modifier.isStatic(this .field.getModifiers());
332: }
333:
334: public IClass getType() {
335: return ReflectionIClass.this .classToIClass(this .field
336: .getType());
337: }
338:
339: public String toString() {
340: return (Descriptor.toString(this .getDeclaringIClass()
341: .getDescriptor())
342: + "." + this .getName());
343: }
344:
345: /**
346: * This implementation of {@link IClass.IField#getConstantValue()} is
347: * not completely correct:
348: * <ul>
349: * <li>
350: * It treats non-static fields as non-constant
351: * <li>
352: * Even fields with a <i>non-constant</i> initializer are identified
353: * as constant. (The value of that field may be different in a
354: * different JVM instance -- the classical example is
355: * {@link java.io.File#separator}.)
356: * </ul>
357: */
358: public Object getConstantValue() throws CompileException {
359: int mod = this .field.getModifiers();
360: Class clazz = this .field.getType();
361: if (Modifier.isStatic(mod) && Modifier.isFinal(mod)
362: && (clazz.isPrimitive() || clazz == String.class)) {
363: try {
364: return this .field.get(null);
365: } catch (IllegalAccessException ex) {
366: throw new CompileException("Field \""
367: + this .field.getName()
368: + "\" is not accessible", (Location) null);
369: }
370: }
371: return null;
372: }
373:
374: final Field field;
375: }
376:
377: /**
378: * Load {@link Class} through {@link IClassLoader} to
379: * ensure unique {@link IClass}es.
380: */
381: private IClass classToIClass(Class c) {
382: IClass iClass;
383: try {
384: iClass = this .iClassLoader.loadIClass(Descriptor
385: .fromClassName(c.getName()));
386: } catch (ClassNotFoundException ex) {
387: throw new RuntimeException("Loading IClass \""
388: + c.getName() + "\": " + ex);
389: }
390: if (iClass == null)
391: throw new RuntimeException("Cannot load class \""
392: + c.getName() + "\" through the given ClassLoader");
393: return iClass;
394: }
395:
396: /**
397: * @see #classToIClass(Class)
398: */
399: private IClass[] classesToIClasses(Class[] cs) {
400: IClass[] result = new IClass[cs.length];
401: for (int i = 0; i < cs.length; ++i)
402: result[i] = this .classToIClass(cs[i]);
403: return result;
404: }
405:
406: private static Access modifiers2Access(int modifiers) {
407: return (Modifier.isPrivate(modifiers) ? Access.PRIVATE
408: : Modifier.isProtected(modifiers) ? Access.PROTECTED
409: : Modifier.isPublic(modifiers) ? Access.PUBLIC
410: : Access.DEFAULT);
411: }
412: }
|