001: package jsint;
002:
003: import java.lang.reflect.*;
004: import java.util.Hashtable;
005:
006: /**
007: * Provides dynamic field access.
008:
009: If the field is static (or a Class is given) we cache the Field.
010: Otherwise, we cache a class-> field map.
011: * @author Peter Norvig, Copyright 1998, peter@norvig.com, <a href="license.txt">license</a>
012: * subsequently modified by Jscheme project members
013: * licensed under zlib licence (see license.txt)
014: **/
015:
016: public class JavaField extends Reflector {
017:
018: /** Maps field name -> Class -> Field **/
019: static final Hashtable fieldTable = new Hashtable(20);
020: static final Hashtable fieldTablePriv = new Hashtable(20);
021:
022: static Hashtable fieldTable0(boolean isPrivileged) {
023: if (isPrivileged)
024: return fieldTablePriv;
025: else
026: return fieldTable;
027: }
028:
029: /**
030: Return the field named <tt>name</tt> in Class <tt>c</tt>.
031: Priviledged fields are made accessible if the JVM allows it.
032: <p>Memoized.
033: **/
034: public static Field getField(Class c, String name,
035: boolean isPrivileged) {
036: try {
037: return isPrivileged ? getDeclaredField(c, name) : c
038: .getField(name);
039: } catch (NoSuchFieldException e2) {
040: return ((Field) E.error("no such field: " + c + "." + name));
041: } catch (Exception e) {
042: return ((Field) E.error("error accessing field: " + c + "."
043: + name + " is " + e));
044: }
045: }
046:
047: private static Hashtable getFieldClassTable(String name,
048: boolean isPrivileged) {
049: Hashtable ft = fieldTable0(isPrivileged);
050: Hashtable table = ((Hashtable) ft.get(name));
051: if (table == null) {
052: table = new Hashtable(3);
053: ft.put(name, table);
054: }
055: return table;
056: }
057:
058: /** Wander over the declared fields, returning the first named
059: <tt>name</tt> **/
060: private static Field getDeclaredField(Class c, String name)
061: throws NoSuchFieldException {
062: try {
063: Field[] fs = ((Field[]) Invoke.makeAccessible(c
064: .getDeclaredFields()));
065: for (int i = 0; i < fs.length; i++)
066: if (fs[i].getName().equals(name))
067: return fs[i];
068: Class s = c.getSuperclass();
069: if (s != null)
070: return getDeclaredField(s, name);
071: else
072: return ((Field) E.error("\n\nERROR: no field: \""
073: + name + "\" for class \"" + c + "\""));
074: } catch (Exception e) {
075: return c.getField(name);
076: }
077: }
078:
079: String className;
080: transient Field f;
081: boolean isStatic = false;
082: /** Map Class -> Field **/
083: transient Hashtable classTable;
084:
085: public JavaField(String name, Class c) {
086: this (name, c, false);
087: }
088:
089: public JavaField(String name, Class c, boolean isPrivileged) {
090: this .name = name;
091: this .isPrivileged = isPrivileged;
092: if (c != null)
093: this .className = c.getName();
094: reset();
095: }
096:
097: protected synchronized void reset() {
098: Class c = (className == null) ? null : Import
099: .classNamed(className);
100: if (c != null) {
101: f = getField(c, name, isPrivileged);
102: isStatic = Modifier.isStatic(f.getModifiers());
103: minArgs = (isStatic) ? 0 : 1;
104: maxArgs = (Modifier.isFinal(f.getModifiers())) ? minArgs
105: : minArgs + 1;
106: } else {
107: classTable = getFieldClassTable(name, isPrivileged);
108: minArgs = 1;
109: maxArgs = 2;
110: }
111: }
112:
113: public Object[] makeArgArray(Object[] code, Evaluator eval,
114: LexicalEnvironment lexenv) {
115: int L = code.length - 1;
116: if (L == 0 && isStatic)
117: return StaticReflector.args0;
118: else if (L == 1)
119: return new Object[] { eval.execute(code[1], lexenv) };
120: else if (L == 2 && !isStatic)
121: return new Object[] { eval.execute(code[1], lexenv),
122: eval.execute(code[2], lexenv) };
123: else
124: return ((Object[]) E
125: .error("Wrong number of arguments to field " + this
126: + " " + U.stringify(code)));
127: }
128:
129: public Object[] makeArgArray(Pair args) {
130: int L = args.length();
131: if (L == 0 && isStatic)
132: return StaticReflector.args0;
133: else if (L == 1)
134: return new Object[] { args.first() };
135: else if (L == 2 && !isStatic)
136: return new Object[] { args.first(), args.second() };
137: else
138: return ((Object[]) E
139: .error("Wrong number of arguments to field " + this
140: + " " + U.stringify(args)));
141: }
142:
143: public Object apply(Object[] args) {
144: int L = args.length;
145: if (isStatic) {
146: if (L == 1)
147: return setStaticFieldValue(f, args[0]);
148: else
149: return getStaticFieldValue(f);
150: } else {
151: if (L == 1)
152: return getFieldValue(args[0], getTargetField(args[0]));
153: else
154: return setFieldValue(args[0], getTargetField(args[0]),
155: args[1]);
156: }
157: }
158:
159: public Field getTargetField(Object target) {
160: if (f != null)
161: return f;
162: Class c = target.getClass();
163: Field it = ((Field) classTable.get(c));
164: if (it != null)
165: return it;
166: it = getField(c, this .name, this .isPrivileged);
167: if (it == null)
168: return (Field) E.error(U.stringify(target)
169: + " does not have a field " + this .name);
170: classTable.put(c, it);
171: return it;
172: }
173:
174: public Object getFieldValue(Object target, Field f) {
175: try {
176: return f.get(target);
177: } catch (IllegalAccessException e) {
178: return ((Object) E.error("Illegal Access to field: " + f
179: + " in " + U.stringify(target)));
180: }
181: }
182:
183: public Object setFieldValue(Object target, Field f, Object value) {
184: try {
185: Object old = f.get(target);
186: f.set(target, value);
187: return old;
188: } catch (IllegalAccessException e) {
189: return null; // Sorry.
190: }
191: }
192:
193: public Object getStaticFieldValue(Field f) {
194: try {
195: return f.get(null);
196: } catch (IllegalAccessException e) {
197: return null; // Sorry.
198: }
199: }
200:
201: public Object setStaticFieldValue(Field f, Object value) {
202: try {
203: Object old = f.get(null);
204: f.set(null, value);
205: return old;
206: } catch (IllegalAccessException e) {
207: return null; // Sorry.
208: }
209: }
210: }
|