KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > objectweb > jac > core > rtti > MethodItem


1 /*
2   Copyright (C) 2001-2003 Renaud Pawlak <renaud@aopsys.com>,
3                           Laurent Martelli <laurent@aopsys.com>
4   
5   This program is free software; you can redistribute it and/or modify
6   it under the terms of the GNU Lesser General Public License as
7   published by the Free Software Foundation; either version 2 of the
8   License, or (at your option) any later version.
9
10   This program is distributed in the hope that it will be useful,
11   but WITHOUT ANY WARRANTY; without even the implied warranty of
12   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13   GNU Lesser General Public License for more details.
14
15   You should have received a copy of the GNU Lesser General Public License
16   along with this program; if not, write to the Free Software
17   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */

18
19 package org.objectweb.jac.core.rtti;
20
21 import java.lang.NoSuchMethodException JavaDoc;
22 import java.lang.reflect.InvocationTargetException JavaDoc;
23 import java.lang.reflect.Method JavaDoc;
24 import java.util.Arrays JavaDoc;
25 import java.util.Vector JavaDoc;
26 import org.apache.log4j.Logger;
27 import org.objectweb.jac.core.Wrappee;
28 import org.objectweb.jac.util.Strings;
29 import org.objectweb.jac.util.WrappedThrowableException;
30
31 /**
32  * This class defines a meta item that corresponds to the
33  * <code>java.lang.reflect.Method</code> meta element.
34  *
35  * <p>In addition to the <code>java.lang.reflect</code> classical
36  * features, this RTTI method element is able to tell if a method is a
37  * setter, a getter, or more generally speaking, a state modifier for
38  * a given field of the object it belongs to. And, if this field is a
39  * collection (an array, a list or a map), then this meta element is
40  * able to tell if the method it represents adds or removes elements
41  * to or from this collection.
42  *
43  * <p>It also provides to introspection features for references on Jac
44  * objects.
45  *
46  * <p>For the moment, default meta informations are setted by the
47  * <code>ClassRepository</code> class using some naming
48  * conventions. In a close future, these informations will be deduced
49  * from the class bytecodes analysis at load-time.
50  *
51  * @see java.lang.reflect.Method
52  * @see #getWrittenFields()
53  * @see #getAccessedFields()
54  * @see #getAddedCollections()
55  * @see #getRemovedCollections()
56  * @see #isModifier()
57  * @see #hasAccessedReferences()
58  *
59  * @author Renaud Pawlak
60  * @author Laurent Martelli
61  */

62
63 public class MethodItem extends AbstractMethodItem {
64     static Logger logger = Logger.getLogger("rtti.method");
65
66     /**
67      * Transforms a method items array into a methods array containing
68      * the <code>java.lang.reflect</code> methods wrapped by the method
69      * items.<p>
70      *
71      * @param methodItems the method items
72      * @return the actual methods in <code>java.lang.reflect</code>
73      */

74
75     public static Method JavaDoc[] toMethods( MethodItem[] methodItems ) {
76         Method JavaDoc[] res = new Method JavaDoc[methodItems.length];
77         for ( int i = 0; i < methodItems.length; i++ ) {
78             if ( methodItems[i] == null ) {
79                 res[i] = null;
80             } else {
81                 res[i] = methodItems[i].getActualMethod();
82             }
83         }
84         return res;
85     }
86
87     /**
88      * Default contructor to create a new method item object.<p>
89      *
90      * @param delegate the <code>java.lang.reflect.Method</code> actual
91      * meta item */

92
93     public MethodItem(Method JavaDoc delegate, ClassItem parent)
94         throws InvalidDelegateException
95     {
96         super(delegate,parent);
97         Class JavaDoc cl = delegate.getDeclaringClass();
98         if (Wrappee.class.isAssignableFrom(cl)) {
99             String JavaDoc orgName = "_org_"+delegate.getName()+
100                 (isStatic?"":"_"+Strings.getShortClassName(cl));
101             try {
102                 orgMethod =
103                     cl.getDeclaredMethod(orgName,delegate.getParameterTypes());
104                 orgMethod.setAccessible(true);
105             } catch(NoSuchMethodException JavaDoc e) {
106                 //Log.warning("No _org_ method "+orgName+" found for "+delegate);
107
}
108         }
109     }
110
111     Method JavaDoc orgMethod;
112
113     public final Method JavaDoc getOrgMethod() {
114         return orgMethod;
115     }
116
117     /**
118      * Tells if this method accesses any references of the class it
119      * belongs to.
120      *
121      * @return true if one or more references are accessed */

122    
123     public final boolean hasAccessedReferences() {
124         ((ClassItem)parent).buildFieldInfo();
125         return numAccessedReferences>0;
126     }
127
128     FieldItem returnedField;
129     /**
130      * Returns the field item corresponding to the field value returned
131      * by this method, if any.
132      * @see #setReturnedField(FieldItem)
133      */

134     public final FieldItem getReturnedField() {
135         return returnedField;
136     }
137     /**
138      * Sets the field returned by the method.
139      * @see #getReturnedField()
140      */

141     public void setReturnedField(FieldItem returnedField) {
142         if (this.returnedField!=null &&
143             !(returnedField.isCalculated() && this.returnedField.isCalculated())) {
144             logger.warn("overriding returned field "+this.returnedField.getName()+
145                         " for "+getParent().getName()+"."+getName()+
146                         " with "+returnedField.getName());
147         }
148         this.returnedField = returnedField;
149     }
150
151     FieldItem setField;
152     /**
153      * Returns <em>the</em> field set by this method, if any. In other
154      * words, the field for which the method is <em>the</em> setter. A
155      * method is <em>the</em>setter of a field if it assigns this field
156      * directly with one of its argument.
157      * @see #setReturnedField(FieldItem) */

158     public final FieldItem getSetField() {
159         return setField;
160     }
161     /**
162      * Sets <em>the</em> field set by the method. This method should
163      * not be called more than once for a gievn field.
164      * @see #getSetField() */

165     public void setSetField(FieldItem setField) {
166         if (this.setField!=null && this.setField!=setField) {
167             logger.warn("overriding set field "+this.setField.getName()+
168                         " for "+getParent().getName()+"."+getName()+
169                         " with "+setField.getName());
170         }
171         this.setField = setField;
172     }
173
174     /** Store the collections that are added by this method.<p> */
175     CollectionItem[] addedCollections = null;
176    
177
178     /**
179      * Get the value of the collections that are added by this
180      * method.<p>
181      *
182      * @return value of addedCollections. */

183
184     public final CollectionItem[] getAddedCollections() {
185         ((ClassItem)parent).buildFieldInfo();
186         return addedCollections;
187     }
188
189     /**
190      * Returns true if the method has at least one added collection
191      */

192     public final boolean hasAddedCollections() {
193         ((ClassItem)parent).buildFieldInfo();
194         return addedCollections!=null && addedCollections.length>0;
195     }
196
197     /**
198      * Sets the value of the collections that are added by this method.<p>
199      *
200      * @param addedCollections value to assign to addedCollections
201      * @see #addAddedCollection(CollectionItem)
202      */

203
204     public final void setAddedCollections(CollectionItem[] addedCollections) {
205         this.addedCollections = addedCollections;
206     }
207
208     /**
209      * Adds a new added collection for this method.<p>
210      *
211      * @param addedCollection the collection to add
212      * @see #removeAddedCollection(CollectionItem)
213      */

214
215     public final void addAddedCollection(CollectionItem addedCollection) {
216         if (addedCollections == null) {
217             addedCollections = new CollectionItem[] { addedCollection };
218         } else {
219             CollectionItem[] tmp = new CollectionItem[addedCollections.length + 1];
220             System.arraycopy(addedCollections, 0, tmp, 0, addedCollections.length);
221             tmp[addedCollections.length] = addedCollection;
222             addedCollections = tmp;
223         }
224     }
225
226     /**
227      * Removes an existing added collection for this method.<p>
228      *
229      * @param collection the collection to add
230      * @see #addAddedCollection(CollectionItem)
231      */

232     public final void removeAddedCollection(CollectionItem collection) {
233         if (addedCollections != null) {
234             Vector JavaDoc v = new Vector JavaDoc(Arrays.asList(addedCollections));
235             v.remove(collection);
236             addedCollections = new CollectionItem[v.size()];
237             System.arraycopy(v.toArray(),0,addedCollections,0,v.size());
238         }
239     }
240
241     /**
242      * Gets the method represented by this method item.<p>
243      *
244      * @return the actual method
245      */

246
247     public final Method JavaDoc getActualMethod() {
248         return (Method JavaDoc)delegate;
249     }
250
251     public final String JavaDoc getName() {
252         return ((Method JavaDoc)delegate).getName();
253     }
254
255     public final Class JavaDoc getType() {
256         return ((Method JavaDoc)delegate).getReturnType();
257     }
258
259     public Class JavaDoc[] getParameterTypes() {
260         return ((Method JavaDoc)delegate).getParameterTypes();
261     }
262
263     int collectionIndexArgument = -1;
264     /**
265      * Returns the number of the argument which is the index of a
266      * modified collection if any, -1 otherwise.
267      */

268     public int getCollectionIndexArgument() {
269         return collectionIndexArgument;
270     }
271     /**
272      * Sets collectionIndexArgument
273      * @see #getCollectionIndexArgument()
274      */

275     public void setCollectionIndexArgument(int collectionIndexArgument) {
276         this.collectionIndexArgument = collectionIndexArgument;
277     }
278
279     int collectionItemArgument = -1;
280     /**
281      * Returns the number of the argument which is the item that will be added
282      * to a collection if any, -1 otherwise.
283      */

284     public int getCollectionItemArgument() {
285         return collectionItemArgument;
286     }
287     /**
288      * Sets collectionItemArgument
289      * @see #getCollectionItemArgument()
290      */

291     public void setCollectionItemArgument(int collectionItemArgument) {
292         this.collectionItemArgument = collectionItemArgument;
293     }
294    
295     public void addAccessedField(FieldItem accessedField) {
296         super.addAccessedField(accessedField);
297         if (getType()!=void.class)
298             accessedField.addDependentMethod(this);
299     }
300
301     /**
302      * Invokes this method on the given object and with the given
303      * parameters values.
304      *
305      * @param object a class this method belongs to intance
306      * @param parameters the values of the parameters to invoke this
307      * method with
308      */

309     public Object JavaDoc invoke(Object JavaDoc object, Object JavaDoc[] parameters)
310     {
311         logger.debug(toString()+" invoke("+object+","+Arrays.asList(parameters)+")");
312         if (!isStatic() && object==null)
313             throw new NullPointerException JavaDoc(
314                 "Invoking instance method "+
315                 parent.getName()+"."+this+" on null");
316         try {
317             return ((Method JavaDoc)delegate).invoke(object,parameters);
318         } catch (IllegalArgumentException JavaDoc e) {
319             Class JavaDoc cl = (Class JavaDoc)getParent().getDelegate();
320             if (!cl.isAssignableFrom(object.getClass())) {
321                 throw new IllegalArgumentException JavaDoc(
322                     getLongName()+": called object "+Strings.hex(object)+
323                     " is not an instance of "+cl.getName());
324             }
325             if (parameters.length == getParameterCount()) {
326                 checkParameters(parameters);
327             }
328             throw e;
329         } catch (Exception JavaDoc e) {
330             logger.info("caught exception "+e);
331             throw new WrappedThrowableException(e);
332         }
333     }
334
335     /**
336      * Checks the type of parameters
337      *
338      * @param parameters parameters to check
339      */

340     void checkParameters(Object JavaDoc[] parameters) {
341         Class JavaDoc[] types = getParameterTypes();
342         for (int i=0; i<types.length; i++) {
343             if (!types[i].isAssignableFrom(parameters[i].getClass()))
344                 throw new IllegalArgumentException JavaDoc(
345                     getLongName()+", argument n°"+(i+1)+":"+
346                     parameters[i].getClass().getName()+
347                     " cannot be converted to "+types[i].getName());
348         }
349     }
350
351     /**
352      * Invokes this static method with the given parameters values.
353      *
354      * @param parameters the values of the parameters to invoke this
355      * method with */

356
357     public final Object JavaDoc invokeStatic(Object JavaDoc[] parameters)
358     {
359         if (!isStatic())
360             throw new RuntimeException JavaDoc("Cannot invokeStatic a non static method: "+getLongName());
361         // logger.debug(toString()+" invoke("+object+","+Arrays.asList(parameters)+")");
362
try {
363             return ((Method JavaDoc)delegate).invoke(null,parameters);
364         } catch (IllegalArgumentException JavaDoc e) {
365             if (parameters.length == getParameterCount()) {
366                 checkParameters(parameters);
367             }
368             throw e;
369         } catch (Exception JavaDoc e) {
370             logger.info("Caught exception in "+getFullName(),e);
371             throw new WrappedThrowableException(e);
372         }
373     }
374
375     /**
376      * Invokes a method with uninitialized parameters.
377      *
378      * <p>The parameters array is initialized before the invocation
379      * with default values.
380      *
381      * @param object the target object
382      * @param parameters the maybe initialized values of the parameters
383      * to invoke this method with (primitive parameters can be null) */

384
385     public final Object JavaDoc invokeWithInit(Object JavaDoc object,
386                                        Object JavaDoc[] parameters)
387         throws IllegalAccessException JavaDoc, InvocationTargetException JavaDoc
388     {
389       
390         Class JavaDoc[] paramTypes = getParameterTypes();
391         for (int i=0; i< parameters.length; i++) {
392             if (parameters[i]==null) {
393                 if (paramTypes[i] == float.class) {
394                     parameters[i] = new Float JavaDoc(0.0);
395                 } else if (paramTypes[i] == long.class) {
396                     parameters[i] = new Long JavaDoc(0);
397                 } else if (paramTypes[i] == double.class) {
398                     parameters[i] = new Double JavaDoc(0.0);
399                 } else if (paramTypes[i] == byte.class) {
400                     parameters[i] = new Byte JavaDoc((byte)0);
401                 } else if (paramTypes[i] == char.class) {
402                     parameters[i] = new Character JavaDoc(' ');
403                 } else if (paramTypes[i] == short.class) {
404                     parameters[i] = new Short JavaDoc((short)0);
405                 } else if (paramTypes[i] == int.class) {
406                     parameters[i] = new Integer JavaDoc(0);
407                 } else if (paramTypes[i] == boolean.class) {
408                     parameters[i] = Boolean.FALSE;
409                 }
410             }
411         }
412         return ((Method JavaDoc)delegate).invoke(object,parameters);
413     }
414
415     /** Tells wether the method returns the value of a field */
416     public final boolean isGetter() {
417         ((ClassItem)parent).buildFieldInfo();
418         return returnedField!=null;
419     }
420
421     public final boolean isCollectionGetter() {
422         ((ClassItem)parent).buildFieldInfo();
423         return returnedField!=null && (returnedField instanceof CollectionItem);
424     }
425
426     /** Tells wether the method is <em>the</em> setter of a field */
427     public final boolean isSetter() {
428         ((ClassItem)parent).buildFieldInfo();
429         return setField!=null;
430     }
431
432     /** Tells wether the method is an adder of a collection */
433     public final boolean isAdder() {
434         ((ClassItem)parent).buildFieldInfo();
435         return addedCollections!=null && addedCollections.length>0;
436     }
437
438
439     /** Stores the collections that are removed by this method.<p> */
440     CollectionItem[] removedCollections = null;
441    
442     /**
443      * Gets the value of the collections that are removed by this
444      * method.<p>
445      *
446      * @return value of removedCollections. */

447
448     public final CollectionItem[] getRemovedCollections() {
449         ((ClassItem)parent).buildFieldInfo();
450         return removedCollections;
451     }
452
453     public final CollectionItem getRemovedCollection() {
454         CollectionItem[] colls = getRemovedCollections();
455         return ((colls != null) ? colls[0] : null);
456     }
457    
458     /**
459      * Returns true if the method has at least one removed collection
460      */

461
462     public final boolean hasRemovedCollections() {
463         ((ClassItem)parent).buildFieldInfo();
464         return removedCollections!=null && removedCollections.length>0;
465     }
466
467     /**
468      * Sets the value of the collections that are removed by this method.<p>
469      *
470      * @param removedCollections value to assign to removedCollections
471      * @see #addRemovedCollection(CollectionItem)
472      */

473
474     public final void setRemovedCollections(CollectionItem[] removedCollections) {
475         this.removedCollections = removedCollections;
476     }
477
478     /**
479      * Adds a new removed collection for this method.<p>
480      *
481      * @param removedCollection the collection to add
482      * @see #setRemovedCollections(CollectionItem[])
483      * @see #removeRemovedCollection(CollectionItem)
484      */

485
486     public final void addRemovedCollection(CollectionItem removedCollection) {
487         if (removedCollections == null) {
488             removedCollections = new CollectionItem[] { removedCollection };
489         } else {
490             CollectionItem[] tmp = new CollectionItem[removedCollections.length+1];
491             System.arraycopy(removedCollections, 0, tmp, 0,
492                              removedCollections.length);
493             tmp[removedCollections.length] = removedCollection;
494             removedCollections = tmp;
495         }
496     }
497
498     /**
499      * Removes an existing removed collection for this method.<p>
500      *
501      * @param collection the collection to remove
502      * @see #addRemovedCollection(CollectionItem)
503      */

504     public final void removeRemovedCollection(CollectionItem collection) {
505         if (removedCollections != null) {
506             Vector JavaDoc v = new Vector JavaDoc(Arrays.asList(removedCollections));
507             v.remove(collection);
508             removedCollections = new CollectionItem[v.size()];
509             System.arraycopy(v.toArray(),0,removedCollections,0,v.size());
510         }
511     }
512
513     /** Tells wether the method is a remover of a collection */
514     public final boolean isRemover() {
515         ((ClassItem)parent).buildFieldInfo();
516         return removedCollections!=null && removedCollections.length>0;
517     }
518
519     public final boolean isAccessor() {
520         ((ClassItem)parent).buildFieldInfo();
521         return accessedFields!=null && accessedFields.length>0;
522     }
523
524     public final boolean isWriter() {
525         ((ClassItem)parent).buildFieldInfo();
526         return hasWrittenFields();
527     }
528
529     public final boolean isCollectionAccessor() {
530         ((ClassItem)parent).buildFieldInfo();
531         if (accessedFields!=null) {
532             for (int i=0; i<accessedFields.length; i++) {
533                 if (accessedFields[i] instanceof CollectionItem) {
534                     return true;
535                 }
536             }
537         }
538         return false;
539     }
540
541     public final boolean isReferenceAccessor() {
542         ((ClassItem)parent).buildFieldInfo();
543         if (accessedFields!=null) {
544             for (int i=0; i<accessedFields.length; i++) {
545                 if (accessedFields[i].isReference()) {
546                     return true;
547                 }
548             }
549         }
550         return false;
551     }
552
553     public final boolean isCollectionSetter() {
554         ((ClassItem)parent).buildFieldInfo();
555         return setField instanceof CollectionItem;
556     }
557
558     public final boolean isFieldSetter() {
559         ((ClassItem)parent).buildFieldInfo();
560         return setField!=null && setField.isPrimitive();
561     }
562
563     public final boolean isReferenceSetter() {
564         ((ClassItem)parent).buildFieldInfo();
565         return setField!=null && setField.isReference();
566     }
567
568     public final boolean isFieldGetter() {
569         ((ClassItem)parent).buildFieldInfo();
570         return !(returnedField instanceof CollectionItem)
571             && returnedField.isPrimitive();
572     }
573
574     public final boolean isReferenceGetter() {
575         ((ClassItem)parent).buildFieldInfo();
576         return returnedField!=null && returnedField.isReference();
577     }
578
579     /** Tells wether the method was introduced by JAC */
580     public final boolean isJacMethod() {
581         return ClassRepository.isJacMethod(getName());
582     }
583
584     public final static MethodItem[] emptyArray = new MethodItem[0];
585 }// MethodItem
586
Popular Tags