KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > josql > internal > Setter


1 package org.josql.internal;
2
3 import java.util.List JavaDoc;
4 import java.util.ArrayList JavaDoc;
5 import java.util.TreeMap JavaDoc;
6
7 import java.lang.reflect.Method JavaDoc;
8 import java.lang.reflect.Modifier JavaDoc;
9 import java.lang.reflect.Field JavaDoc;
10 import java.lang.reflect.InvocationTargetException JavaDoc;
11
12 import java.util.StringTokenizer JavaDoc;
13
14 import com.gentlyweb.utils.Getter;
15
16 /**
17  * This class is used to perform access into a Java object using a
18  * String value with a specific notation.
19  * <p>
20  * The Accessor uses a dot notation such as <b>field1.method1.method2</b> to
21  * perform the access on an object. Each value in the notation refers to
22  * a field or method (a no argument method) of the type of the previous
23  * value.
24  * For instance if you have the following class structure:
25  * </p>
26  * <pre>
27  * public class A
28  * {
29  * public B = new B ();
30  * }
31  *
32  * public class B
33  * {
34  * public C = new C ();
35  * }
36  *
37  * public class C
38  * {
39  * String d = "";
40  * }
41  * </pre>
42  * <p>
43  * You would then use the notation: <b>B.C.d</b> to get access to
44  * field <b>d</b> in Class C.
45  * <br /><br />
46  * The Accessor also supports a <b>[ ]</b> notation for accessing
47  * into Lists/Maps and Arrays. If the value between the <b>[ ]</b>
48  * is an integer then we look for the associated type to be either
49  * an array or a List, we then index into it with the integer. If
50  * the value is <b>NOT</b> an integer then we use assume the
51  * type is a Map and use it as a key into the Map.
52  * <br /><br />
53  * For instance changing the example above:
54  * </p>
55  * <pre>
56  * public class A
57  * {
58  * public List vals = new ArrayList ();
59  * }
60  * </pre>
61  * <p> Method[] methods = c.getMethods ();
62
63     for (int i = 0; i < methods.length; i++)
64     {
65
66         if ((methods[i].getName ().equals (getMethod.toString ()))
67         &&
68         (methods[i].getParameterTypes ().length == 0)
69            )
70         {
71
72         // This is the one...
73         return methods[i];
74
75         }
76
77     }
78
79     return null;
80
81  * Now we could use: <b>vals[X]</b> where <b>X</b> is a positive integer.
82  * Or changing again:
83  * </p>
84  * <pre>
85  * public class A
86  * {
87  * public Map vals = new HashMap ();
88  * }
89  * </pre>
90  * <p>
91  * We could use: <b>vals[VALUE]</b> where <b>VALUE</b> would then be
92  * used as a Key into the vals HashMap.
93  * <br /><br />
94  * Note: The Accessor is <b>NOT</b> designed to be an all purpose
95  * method of gaining access to a class. It has specific uses and for
96  * most will be of no use at all. It should be used for general purpose
97  * applications where you want to access specific fields of an object
98  * without having to know the exact type. One such application is in
99  * the {@link GeneralComparator}, in that case arbitrary Objects can
100  * be sorted without having to write complex Comparators or implementing
101  * the Comparable interface AND it gives the flexibility that sorting
102  * can be changed ad-hoc.
103  * <br /><br />
104  * The Accessor looks for in the following order:
105  * <ul>
106  * <li>Public fields with the specified name.</li>
107  * <li>If no field is found then the name is converted to a "JavaBeans"
108  * <b>get</b> method, so a field name of <b>value</b> would be converted
109  * to <b>getValue</b> and that method is looked for. The method must take
110  * no arguments.</li>
111  * <li>If we don't find the <b>get*</b> method then we look for a method with
112  * the specified name. So a field name of <b>value</b> would mean that
113  * a method (that again takes no arguments) is looked for.</li>
114  * </ul>
115  * <p>
116  * Note: we have had to add the 3rd type to allow for methods that don't follow
117  * JavaBeans conventions (there are loads in the standard Java APIs which makes
118  * accessing impossible otherwise).
119  */

120 public class Setter
121 {
122
123     private Getter getter = null;
124     private Object JavaDoc setter = null;
125     private Class JavaDoc clazz = null;
126
127     /**
128      * @param ref The reference for the setter.
129      * @param clazz The Class to get the field from.
130      */

131     public Setter (String JavaDoc ref,
132            Class JavaDoc clazz,
133            Class JavaDoc[] parmTypes)
134                throws IllegalArgumentException JavaDoc,
135                        NoSuchMethodException JavaDoc
136     {
137
138     this.clazz = clazz;
139
140     StringTokenizer JavaDoc t = new StringTokenizer JavaDoc (ref,
141                          ".");
142
143     StringBuffer JavaDoc getRef = new StringBuffer JavaDoc ();
144
145     if (t.countTokens () > 1)
146     {
147
148         // Get everything up to the last part.
149
while (t.hasMoreTokens ())
150         {
151         
152         getRef.append (t.nextToken ());
153
154         if (t.countTokens () > 1)
155         {
156
157             getRef.append ('.');
158
159         }
160
161         if (t.countTokens () == 1)
162         {
163
164             // Now get the Getter.
165
this.getter = new Getter (getRef.toString (),
166                           clazz);
167
168             // Get the return type from the getter.
169
clazz = this.getter.getType ();
170
171             break;
172
173         }
174
175         }
176
177     }
178
179     // Now for the final part this is the setter.
180
String JavaDoc set = t.nextToken ();
181
182     // Get the Fields.
183
Field JavaDoc[] fields = clazz.getFields ();
184     
185     Field JavaDoc f = null;
186     
187     // See if the token matches...
188
for (int i = 0; i < fields.length; i++)
189     {
190         
191         if (fields[i].getName ().equals (set))
192         {
193         
194         // Found it...
195
f = fields[i];
196         
197         this.setter = f;
198         
199         return;
200         
201         }
202         
203     }
204     
205     // If we are here then it's not a public field.
206

207     // Now convert it to a method name and use the
208
// JavaBeans convention...
209

210     // Now get the method...
211
StringBuffer JavaDoc name = new StringBuffer JavaDoc (set);
212
213     name.setCharAt (0,
214             Character.toUpperCase (name.charAt (0)));
215
216     name.insert (0,
217              "set");
218
219     String JavaDoc nName = name.toString ();
220
221     List JavaDoc meths = new ArrayList JavaDoc ();
222
223     Utilities.getMethods (clazz,
224                   nName,
225                   Modifier.PUBLIC,
226                   meths);
227
228     TreeMap JavaDoc sm = new TreeMap JavaDoc ();
229
230     // Now compare the parm types.
231
for (int i = 0; i < meths.size (); i++)
232     {
233
234         Method JavaDoc m = (Method JavaDoc) meths.get (i);
235
236         Class JavaDoc[] mpts = m.getParameterTypes ();
237
238         int score = Utilities.matchMethodArgs (mpts,
239                            parmTypes);
240
241         if (score > 0)
242         {
243
244         sm.put (new Integer JavaDoc (score),
245             m);
246
247         }
248
249     }
250
251     // Get the last key
252
if (sm.size () > 0)
253     {
254
255         this.setter = (Method JavaDoc) sm.get (sm.lastKey ());
256
257     }
258
259     if (this.setter == null)
260     {
261
262         meths = new ArrayList JavaDoc ();
263
264         Utilities.getMethods (clazz,
265                   set,
266                   Modifier.PUBLIC,
267                   meths);
268
269         sm = new TreeMap JavaDoc ();
270
271         // Now compare the parm types.
272
for (int i = 0; i < meths.size (); i++)
273         {
274
275         Method JavaDoc m = (Method JavaDoc) meths.get (i);
276
277         Class JavaDoc[] mpts = m.getParameterTypes ();
278         
279         int score = Utilities.matchMethodArgs (mpts,
280                                parmTypes);
281
282         if (score > 0)
283         {
284
285             sm.put (new Integer JavaDoc (score),
286                 m);
287
288         }
289
290         }
291
292         // Get the last key
293
if (sm.size () > 0)
294         {
295
296         this.setter = (Method JavaDoc) sm.get (sm.lastKey ());
297
298         }
299
300     }
301
302     if (this.setter == null)
303     {
304
305         throw new IllegalArgumentException JavaDoc ("Unable to find required method: " +
306                         nName +
307                         " or: " +
308                         set +
309                         " in class: " +
310                         clazz.getName () +
311                         " taking parms: " +
312                         parmTypes);
313
314     }
315     
316     }
317
318     public Class JavaDoc getBaseClass ()
319     {
320
321     return this.clazz;
322
323     }
324
325     public void setValue (Object JavaDoc target,
326               Object JavaDoc value)
327                           throws IllegalAccessException JavaDoc,
328                              InvocationTargetException JavaDoc,
329                                  IllegalArgumentException JavaDoc
330     {
331
332     Object JavaDoc[] vals = {value};
333     
334     this.setValue (target,
335                vals);
336
337     }
338
339     public void setValue (Object JavaDoc target,
340               Object JavaDoc[] values)
341                           throws IllegalAccessException JavaDoc,
342                                InvocationTargetException JavaDoc,
343                                    IllegalArgumentException JavaDoc
344     {
345
346     // Get the object to set on from the getter.
347
if (this.getter != null)
348     {
349
350         target = this.getter.getValue (target);
351
352     }
353
354     // Now call our accessor on the obj and set the value.
355
if (this.setter instanceof Field JavaDoc)
356     {
357
358         Field JavaDoc f = (Field JavaDoc) this.setter;
359
360         f.set (target,
361            values[0]);
362
363         return;
364
365     }
366     
367     if (this.setter instanceof Method JavaDoc)
368     {
369
370         Method JavaDoc m = (Method JavaDoc) this.setter;
371
372         m.invoke (target,
373               Utilities.convertArgs (values,
374                          m.getParameterTypes ()));
375
376     }
377
378     }
379
380     /**
381      * Get the class of the type of object we expect in the {@link #setValue(Object,Object)}
382      * method.
383      *
384      * @return The class.
385      */

386     public Class JavaDoc getType ()
387     {
388
389     // See what type the accessor is...
390
if (this.setter instanceof Method JavaDoc)
391     {
392         
393         Method JavaDoc m = (Method JavaDoc) this.setter;
394         
395         Class JavaDoc[] parms = m.getParameterTypes ();
396
397         return parms[0];
398
399     }
400         
401     if (this.setter instanceof Field JavaDoc)
402     {
403         
404         // It's a field...so...
405
Field JavaDoc f = (Field JavaDoc) this.setter;
406
407         return f.getType ();
408
409     }
410
411     return null;
412
413     }
414
415 }
416
Popular Tags