1 package gnu.kawa.reflect; 2 import gnu.mapping.*; 3 import gnu.bytecode.*; 4 import gnu.mapping.Location; // As opposed to gnu.bytecode.Location. 5 import gnu.expr.*; 6 7 /** A Location whose value is that of a named field/method of an object. 8 * The object is used as the owning Location's value. 9 * (For now, only fields are supported.) 10 */ 11 12 public abstract class ClassMemberLocation<T> extends Location<T> 13 { 14 Object instance; 15 private String cname; 16 private ClassType type; 17 /** Member (method or field) name. */ 18 String mname; 19 java.lang.reflect.Field rfield; 20 getInstance()21 public final Object getInstance () { return instance; } setInstance(Object obj)22 public final void setInstance (Object obj) { instance = obj; } 23 ClassMemberLocation(Object instance, String cname, String mname)24 public ClassMemberLocation(Object instance, String cname, String mname) 25 { 26 this.instance = instance; 27 this.cname = cname; 28 this.mname = mname; 29 } 30 ClassMemberLocation(Object instance, ClassType type, String mname)31 public ClassMemberLocation(Object instance, ClassType type, String mname) 32 { 33 this.instance = instance; 34 this.type = type; 35 this.mname = mname; 36 } 37 ClassMemberLocation(Object instance, Class clas, String mname)38 public ClassMemberLocation(Object instance, Class clas, String mname) 39 { 40 this.instance = instance; 41 this.type = (ClassType) Type.make(clas); 42 this.mname = mname; 43 } 44 ClassMemberLocation(Object instance, java.lang.reflect.Field field)45 public ClassMemberLocation(Object instance, java.lang.reflect.Field field) 46 { 47 this.instance = instance; 48 this.rfield = field; 49 type = (ClassType) Type.make(field.getDeclaringClass()); 50 this.mname = field.getName(); 51 } 52 getMemberName()53 public String getMemberName() 54 { 55 return mname; 56 } 57 getDeclaringClass()58 public ClassType getDeclaringClass() { 59 if (type == null) 60 type = ClassType.make(cname); 61 return type; 62 } getDeclaringClassname()63 public String getDeclaringClassname() { 64 return cname != null ? cname : type == null ? "()" : type.getName(); 65 } 66 setup()67 void setup () 68 { 69 if (rfield == null) 70 { 71 Class clas; 72 try 73 { 74 clas = getDeclaringClass().getReflectClass(); 75 } 76 catch (RuntimeException ex) 77 { 78 RuntimeException uex 79 = new UnboundLocationException(null, "Unbound location - " 80 + ex.toString()); 81 /* #ifdef use:java.lang.Throwable.getCause */ 82 uex.initCause(ex); 83 /* #endif */ 84 throw uex; 85 } 86 try 87 { 88 rfield = clas.getField(mname); 89 } 90 catch (java.lang.NoSuchFieldException ex) 91 { 92 RuntimeException uex 93 = new UnboundLocationException(null, "Unbound location " 94 + " - no field " + mname 95 + " in " + type.getName()); 96 /* #ifdef use:java.lang.Throwable.getCause */ 97 uex.initCause(ex); 98 /* #endif */ 99 throw uex; 100 } 101 } 102 } 103 getRField()104 public java.lang.reflect.Field getRField () 105 { 106 java.lang.reflect.Field rfld = this.rfield; 107 if (rfld == null) 108 { 109 Class clas 110 = null; 111 try 112 { 113 clas = getDeclaringClass().getReflectClass(); 114 rfld = clas.getField(mname); 115 this.rfield = rfld; 116 } 117 catch (Exception ex) 118 { 119 return null; 120 } 121 } 122 return rfld; 123 } 124 125 /** Return the {@code Class} this member is in. */ 126 getRClass()127 public Class getRClass () 128 { 129 java.lang.reflect.Field rfld = this.rfield; 130 if (rfld != null) 131 return rfld.getDeclaringClass(); 132 try 133 { 134 return getDeclaringClass().getReflectClass(); 135 } 136 catch (Exception ex) 137 { 138 return null; 139 } 140 } 141 get(T defaultValue)142 public T get (T defaultValue) 143 { 144 java.lang.reflect.Field rfld = getRField(); 145 if (rfld == null) 146 return defaultValue; 147 148 try 149 { 150 return (T) rfld.get(instance); 151 } 152 catch (IllegalAccessException ex) 153 { 154 throw WrappedException.wrapIfNeeded(ex); 155 } 156 } 157 isConstant()158 public boolean isConstant () 159 { 160 java.lang.reflect.Field rfld = getRField(); 161 return rfld != null && (rfield.getModifiers() & Access.FINAL) != 0; 162 } 163 isBound()164 public boolean isBound () 165 { 166 java.lang.reflect.Field rfld = getRField(); 167 return rfld != null; 168 } 169 set(T value)170 public void set (T value) 171 { 172 setup(); 173 try 174 { 175 rfield.set(instance, value); 176 return; 177 } 178 catch (IllegalAccessException ex) 179 { 180 throw WrappedException.wrapIfNeeded(ex); 181 } 182 // This is a bit of a kludge FIXME. 183 //setLocation(loc, new TrivialLocation(getEnvironment(loc))); 184 //setValue(loc, value); 185 } 186 187 static final ClassType typeProcedure 188 = ClassType.make("gnu.mapping.Procedure"); 189 static final ClassType typeLocation 190 = ClassType.make("gnu.mapping.Location"); 191 define(Object instance, java.lang.reflect.Field rfield, String uri, Language language, Environment env)192 public static void define (Object instance, java.lang.reflect.Field rfield, 193 String uri, Language language, Environment env) 194 throws IllegalAccessException 195 { 196 Object fvalue = rfield.get(instance); 197 Type ftype = Type.make(rfield.getType()); 198 boolean isAlias = ftype.isSubtype(typeLocation); 199 boolean isProcedure = ftype.isSubtype(typeProcedure); 200 int rModifiers = rfield.getModifiers(); 201 boolean isFinal = (rModifiers & Access.FINAL) != 0; 202 Object fdname = (isFinal && (fvalue instanceof Named && ! isAlias) 203 ? ((Named) fvalue).getSymbol() 204 : Mangling.demangleField(rfield.getName())); 205 try { 206 SourceName sourceName = rfield.getAnnotation(SourceName.class); 207 if (sourceName != null) { 208 fdname = Symbol.valueOf(sourceName.name(), sourceName.uri(), sourceName.prefix()); 209 } 210 } catch (Exception ex) { 211 } 212 Symbol sym; 213 if (fdname instanceof Symbol) 214 sym = (Symbol) fdname; 215 else 216 { 217 sym = Symbol.make(uri == null ? "" : uri, 218 fdname.toString().intern()); 219 } 220 Location loc; 221 Object property = null; 222 if (isAlias && isFinal) 223 { 224 loc = (Location) fvalue; 225 } 226 else 227 { 228 if (isFinal) 229 property = language.getEnvPropertyFor(rfield, fvalue); 230 boolean isStatic = (rModifiers & Access.STATIC) != 0; 231 if (isStatic) 232 loc = new StaticFieldLocation(rfield); 233 else 234 loc = new FieldLocation(instance, rfield); 235 236 } 237 env.addLocation(sym, property, loc); 238 } 239 240 /** Import all the public fields of an object. */ defineAll(Object instance, Language language, Environment env)241 public static void defineAll (Object instance, Language language, Environment env) 242 throws IllegalAccessException 243 { 244 Class clas; 245 if (instance instanceof Class) { 246 clas = (Class) instance; 247 instance = null; 248 } else { 249 clas = instance.getClass(); 250 } 251 java.lang.reflect.Field[] fields = clas.getFields(); 252 for (int i = fields.length; --i >= 0; ) 253 { 254 java.lang.reflect.Field field = fields[i]; 255 String fname = field.getName(); 256 if (fname.startsWith(Declaration.PRIVATE_PREFIX) 257 || fname.endsWith("$instance")) 258 continue; 259 define(instance, field, null, language, env); 260 } 261 } 262 } 263