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