001: /*
002: * Janino - An embedded Java[TM] compiler
003: *
004: * Copyright (c) 2006, 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: return (IMethod[]) iMethods
079: .toArray(new IMethod[iMethods.size()]);
080: }
081:
082: protected IField[] getDeclaredIFields2() {
083: Field[] fields = this .clazz.getDeclaredFields();
084: IField[] result = new IField[fields.length];
085: for (int i = 0; i < fields.length; ++i) {
086: result[i] = new ReflectionIField(fields[i]);
087: }
088: return result;
089: }
090:
091: protected IClass[] getDeclaredIClasses2() {
092: return this .classesToIClasses(this .clazz.getDeclaredClasses());
093: }
094:
095: protected IClass getDeclaringIClass2() {
096: Class declaringClass = this .clazz.getDeclaringClass();
097: if (declaringClass == null)
098: return null;
099: return this .classToIClass(declaringClass);
100: }
101:
102: protected IClass getOuterIClass2() throws CompileException {
103: if (Modifier.isStatic(this .clazz.getModifiers()))
104: return null;
105: return this .getDeclaringIClass();
106: }
107:
108: protected IClass getSuperclass2() {
109: Class super class = this .clazz.getSuperclass();
110: return super class == null ? null : this
111: .classToIClass(super class);
112: }
113:
114: protected IClass[] getInterfaces2() {
115: return this .classesToIClasses(this .clazz.getInterfaces());
116: }
117:
118: protected String getDescriptor2() {
119: return Descriptor.fromClassName(this .clazz.getName());
120: }
121:
122: public Access getAccess() {
123: return ReflectionIClass.modifiers2Access(this .clazz
124: .getModifiers());
125: }
126:
127: public boolean isFinal() {
128: return Modifier.isFinal(this .clazz.getModifiers());
129: }
130:
131: public boolean isInterface() {
132: return this .clazz.isInterface();
133: }
134:
135: public boolean isAbstract() {
136: return Modifier.isAbstract(this .clazz.getModifiers());
137: }
138:
139: public boolean isArray() {
140: return this .clazz.isArray();
141: }
142:
143: protected IClass getComponentType2() {
144: Class componentType = this .clazz.getComponentType();
145: return componentType == null ? null : this
146: .classToIClass(componentType);
147: }
148:
149: public boolean isPrimitive() {
150: return this .clazz.isPrimitive();
151: }
152:
153: public boolean isPrimitiveNumeric() {
154: return (this .clazz == byte.class || this .clazz == short.class
155: || this .clazz == int.class || this .clazz == long.class
156: || this .clazz == char.class
157: || this .clazz == float.class || this .clazz == double.class);
158: }
159:
160: /**
161: * @return E.g. "int", "int[][]", "pkg1.pkg2.Outer$Inner[]"
162: */
163: public String toString() {
164: int brackets = 0;
165: Class c = this .clazz;
166: while (c.isArray()) {
167: ++brackets;
168: c = c.getComponentType();
169: }
170: String s = c.getName();
171: while (brackets-- > 0)
172: s += "[]";
173: return s;
174: }
175:
176: private class ReflectionIConstructor extends IConstructor {
177: public ReflectionIConstructor(Constructor constructor) {
178: this .constructor = constructor;
179: }
180:
181: // Implement IMember.
182: public Access getAccess() {
183: int mod = this .constructor.getModifiers();
184: return ReflectionIClass.modifiers2Access(mod);
185: }
186:
187: // Implement "IConstructor".
188: public IClass[] getParameterTypes() throws CompileException {
189: IClass[] parameterTypes = ReflectionIClass.this
190: .classesToIClasses(this .constructor
191: .getParameterTypes());
192:
193: // The JAVADOC of java.lang.reflect.Constructor does not document it, but
194: // "getParameterTypes()" includes the synthetic "enclosing instance" parameter.
195: IClass outerClass = ReflectionIClass.this .getOuterIClass();
196: if (outerClass != null) {
197: if (parameterTypes.length < 1)
198: throw new CompileException(
199: "Constructor \""
200: + this .constructor
201: + "\" lacks synthetic enclosing instance parameter",
202: null);
203: if (parameterTypes[0] != outerClass)
204: throw new CompileException(
205: "Enclosing instance parameter of constructor \""
206: + this .constructor
207: + "\" has wrong type -- \""
208: + parameterTypes[0] + "\" vs. \""
209: + outerClass + "\"", null);
210: IClass[] tmp = new IClass[parameterTypes.length - 1];
211: System.arraycopy(parameterTypes, 1, tmp, 0, tmp.length);
212: parameterTypes = tmp;
213: }
214:
215: return parameterTypes;
216: }
217:
218: public String getDescriptor() {
219: Class[] parameterTypes = this .constructor
220: .getParameterTypes();
221: String[] parameterDescriptors = new String[parameterTypes.length];
222: for (int i = 0; i < parameterDescriptors.length; ++i) {
223: parameterDescriptors[i] = Descriptor
224: .fromClassName(parameterTypes[i].getName());
225: }
226: return new MethodDescriptor(parameterDescriptors,
227: Descriptor.VOID).toString();
228: }
229:
230: public IClass[] getThrownExceptions() {
231: return ReflectionIClass.this
232: .classesToIClasses(this .constructor
233: .getExceptionTypes());
234: }
235:
236: final Constructor constructor;
237: };
238:
239: private class ReflectionIMethod extends IMethod {
240: public ReflectionIMethod(Method method) {
241: this .method = method;
242: }
243:
244: // Implement IMember.
245: public Access getAccess() {
246: return ReflectionIClass.modifiers2Access(this .method
247: .getModifiers());
248: }
249:
250: // Implement "IMethod".
251: public String getName() {
252: return this .method.getName();
253: }
254:
255: public IClass[] getParameterTypes() {
256: return ReflectionIClass.this .classesToIClasses(this .method
257: .getParameterTypes());
258: }
259:
260: public boolean isStatic() {
261: return Modifier.isStatic(this .method.getModifiers());
262: }
263:
264: public boolean isAbstract() {
265: return Modifier.isAbstract(this .method.getModifiers());
266: }
267:
268: public IClass getReturnType() {
269: return ReflectionIClass.this .classToIClass(this .method
270: .getReturnType());
271: }
272:
273: public IClass[] getThrownExceptions() {
274: return ReflectionIClass.this .classesToIClasses(this .method
275: .getExceptionTypes());
276: }
277:
278: final Method method;
279: };
280:
281: private class ReflectionIField extends IField {
282: public ReflectionIField(Field field) {
283: this .field = field;
284: }
285:
286: // Implement IMember.
287: public Access getAccess() {
288: return ReflectionIClass.modifiers2Access(this .field
289: .getModifiers());
290: }
291:
292: // Implement "IField".
293: public String getName() {
294: return this .field.getName();
295: }
296:
297: public boolean isStatic() {
298: return Modifier.isStatic(this .field.getModifiers());
299: }
300:
301: public IClass getType() {
302: return ReflectionIClass.this .classToIClass(this .field
303: .getType());
304: }
305:
306: public String toString() {
307: return (Descriptor.toString(this .getDeclaringIClass()
308: .getDescriptor())
309: + "." + this .getName());
310: }
311:
312: /**
313: * This implementation of {@link IClass.IField#getConstantValue()} is
314: * not completely correct:
315: * <ul>
316: * <li>
317: * It treats non-static fields as non-constant
318: * <li>
319: * Even fields with a <i>non-constant</i> initializer are identified
320: * as constant. (The value of that field may be different in a
321: * different JVM instance -- the classical example is
322: * {@link java.io.File#separator}.)
323: * </ul>
324: */
325: public Object getConstantValue() throws CompileException {
326: int mod = this .field.getModifiers();
327: Class clazz = this .field.getType();
328: if (Modifier.isStatic(mod) && Modifier.isFinal(mod)
329: && (clazz.isPrimitive() || clazz == String.class)) {
330: try {
331: return this .field.get(null);
332: } catch (IllegalAccessException ex) {
333: throw new CompileException("Field \""
334: + this .field.getName()
335: + "\" is not accessible", (Location) null);
336: }
337: }
338: return null;
339: }
340:
341: final Field field;
342: }
343:
344: /**
345: * Load {@link Class} through {@link IClassLoader} to
346: * ensure unique {@link IClass}es.
347: */
348: private IClass classToIClass(Class c) {
349: IClass iClass;
350: try {
351: iClass = this .iClassLoader.loadIClass(Descriptor
352: .fromClassName(c.getName()));
353: } catch (ClassNotFoundException ex) {
354: throw new RuntimeException("Loading IClass \""
355: + c.getName() + "\": " + ex);
356: }
357: if (iClass == null)
358: throw new RuntimeException("Cannot load class \""
359: + c.getName() + "\" through the given ClassLoader");
360: return iClass;
361: }
362:
363: /**
364: * @see #classToIClass(Class)
365: */
366: private IClass[] classesToIClasses(Class[] cs) {
367: IClass[] result = new IClass[cs.length];
368: for (int i = 0; i < cs.length; ++i)
369: result[i] = this .classToIClass(cs[i]);
370: return result;
371: }
372:
373: private static Access modifiers2Access(int modifiers) {
374: return (Modifier.isPrivate(modifiers) ? Access.PRIVATE
375: : Modifier.isProtected(modifiers) ? Access.PROTECTED
376: : Modifier.isPublic(modifiers) ? Access.PUBLIC
377: : Access.DEFAULT);
378: }
379: }
|