Docjar: A Java Source and Docuemnt Enginecom.*    java.*    javax.*    org.*    all    new    plug-in

Quick Search    Search Deep

Source code: com/techtrader/modules/tools/bytecode/BCMethod.java


1   package com.techtrader.modules.tools.bytecode;
2   
3   
4   import java.io.IOException;
5   import java.io.DataInput;
6   import java.io.DataOutput;
7   
8   import com.techtrader.modules.tools.bytecode.lowlevel.ConstantPool;
9   import com.techtrader.modules.tools.bytecode.lowlevel.MethodEntry;
10  import com.techtrader.modules.tools.bytecode.lowlevel.InterfaceMethodEntry;
11  import com.techtrader.modules.tools.bytecode.visitor.BCVisitor;
12  
13  
14  /**
15   *  Representation of a bytecode method of a class; a BCMethod can only
16   *  be obtained from a BCClass.  Note that this class has method to manipulate
17   *  its declared excptions and code for convenience only; they can be
18   *  manipulated directly through the ATTR_EXCEPTIONS and ATTR_CODE attributes.
19   *  
20   *  @author    Abe White
21   */
22  public class BCMethod
23    extends BCEntity
24    implements Constants
25  {
26    private BCClass  _owner        = null;
27    private int   _access       = ACCESS_PUBLIC;
28    private int    _nameIndex      = 0;
29    private int    _descriptorIndex   = 0;
30  
31  
32    /**
33     *  Protected constructor.
34     */
35    protected BCMethod (BCClass owner)
36    {
37      _owner = owner;
38    }
39  
40  
41    /**
42     *  Used when this field is deleted from its class.
43     */
44    protected void invalidate ()
45    {
46      _owner = null;
47    }
48  
49  
50    /**
51     *  Get the BCClass that owns this method.
52     */
53    public BCClass getOwner ()
54    {
55      return _owner;
56    }
57  
58  
59    /**
60     *  Return the access flags for this class as a bit array of 
61      *  ACCESS_XXX constants.  This can be used to transfer access flags
62     *  between methods without getting/setting each possible access flag.
63     */
64    public int getAccessFlags ()
65    {
66      return _access;
67    }
68  
69  
70    /**
71     *  Set the access flags for this class as a bit array of 
72      *  ACCESS_XXX constants.  This can be used to transfer access flags
73     *  between methods without getting/setting each possible access flag.
74     */
75    public void setAccessFlags (int access)
76    {
77      _access = access;  
78    }
79  
80  
81    /**
82     *  Manipulate the method access flags.
83     */
84    public boolean isPublic ()
85    {
86      return BCHelper.hasFlag (_access, ACCESS_PUBLIC);
87    }
88  
89  
90    /**
91     *  Manipulate the method access flags.
92     */
93    public void makePublic ()
94    {
95      _access = BCHelper.setFlag (_access, ACCESS_PUBLIC, true);
96      _access = BCHelper.setFlag (_access, ACCESS_PRIVATE, false);
97      _access = BCHelper.setFlag (_access, ACCESS_PROTECTED, false);
98    }
99  
100 
101   /**
102    *  Manipulate the method access flags.
103    */
104   public boolean isProtected ()
105   {
106     return BCHelper.hasFlag (_access, ACCESS_PROTECTED);
107   }
108 
109 
110   /**
111    *  Manipulate the method access flags.
112    */
113   public void makeProtected ()
114   {
115     _access = BCHelper.setFlag (_access, ACCESS_PUBLIC, false);
116     _access = BCHelper.setFlag (_access, ACCESS_PRIVATE, false);
117     _access = BCHelper.setFlag (_access, ACCESS_PROTECTED, true);
118   }
119 
120 
121   /**
122    *  Manipulate the method access flags.
123    */
124   public boolean isPrivate ()
125   {
126     return BCHelper.hasFlag (_access, ACCESS_PRIVATE);
127   }
128 
129 
130   /**
131    *  Manipulate the method access flags.
132    */
133   public void makePrivate ()
134   {
135     _access = BCHelper.setFlag (_access, ACCESS_PUBLIC, false);
136     _access = BCHelper.setFlag (_access, ACCESS_PRIVATE, true);
137     _access = BCHelper.setFlag (_access, ACCESS_PROTECTED, false);
138   }
139 
140 
141   /**
142    *  Manipulate the method access flags.
143    */
144   public boolean isPackage ()
145   {
146     boolean hasAccess = false;
147     hasAccess = hasAccess ||  BCHelper.hasFlag (_access, ACCESS_PRIVATE);
148     hasAccess = hasAccess ||  BCHelper.hasFlag (_access, ACCESS_PROTECTED);
149     hasAccess = hasAccess ||  BCHelper.hasFlag (_access, ACCESS_PUBLIC);
150 
151     return !hasAccess;
152   }
153 
154 
155   /**
156    *  Manipulate the method access flags.
157    */
158   public void makePackage ()
159   {
160     _access = BCHelper.setFlag (_access, ACCESS_PUBLIC, false);
161     _access = BCHelper.setFlag (_access, ACCESS_PRIVATE, false);
162     _access = BCHelper.setFlag (_access, ACCESS_PROTECTED, false);
163   }
164 
165 
166   /**
167    *  Manipulate the method access flags.
168    */
169   public boolean isFinal ()
170   {
171     return BCHelper.hasFlag (_access, ACCESS_FINAL);
172   }
173 
174 
175   /**
176    *  Manipulate the method access flags.
177    */
178   public void setFinal (boolean on)
179   {
180     _access = BCHelper.setFlag (_access, ACCESS_FINAL, on);
181   }
182 
183 
184   /**
185    *  Manipulate the method access flags.
186    */
187   public boolean isStatic ()
188   {
189     return BCHelper.hasFlag (_access, ACCESS_STATIC);
190   }
191 
192 
193   /**
194    *  Manipulate the method access flags.
195    */
196   public void setStatic (boolean on)
197   {
198     _access = BCHelper.setFlag (_access, ACCESS_STATIC, on);
199   }
200 
201 
202   /**
203    *  Manipulate the method access flags.
204    */
205   public boolean isSynchronized ()
206   {
207     return BCHelper.hasFlag (_access, ACCESS_SYNCHRONIZED);
208   }
209 
210 
211   /**
212    *  Manipulate the method access flags.
213    */
214   public void setSynchronized (boolean on)
215   {
216     _access = BCHelper.setFlag (_access, ACCESS_SYNCHRONIZED, on);
217   }
218 
219 
220   /**
221    *  Manipulate the method access flags.
222    */
223   public boolean isNative ()
224   {
225     return BCHelper.hasFlag (_access, ACCESS_NATIVE);
226   }
227 
228 
229   /**
230    *  Manipulate the method access flags.
231    */
232   public void setNative (boolean on)
233   {
234     _access = BCHelper.setFlag (_access, ACCESS_NATIVE, on);
235   }
236 
237 
238   /**
239    *  Manipulate the method access flags.
240    */
241   public boolean isAbstract ()
242   {
243     return BCHelper.hasFlag (_access, ACCESS_ABSTRACT);
244   }
245 
246 
247   /**
248    *  Manipulate the method access flags.
249    */
250   public void setAbstract (boolean on)
251   {
252     _access = BCHelper.setFlag (_access, ACCESS_ABSTRACT, on);
253   }
254 
255 
256   /**
257    *  Manipulate the method access flags.
258    */
259   public boolean isStrict ()
260   {
261     return BCHelper.hasFlag (_access, ACCESS_STRICT);
262   }
263 
264 
265   /**
266    *  Manipulate the method access flags.
267    */
268   public void setStrict (boolean on)
269   {
270     _access = BCHelper.setFlag (_access, ACCESS_STRICT, on);
271   }
272 
273 
274   /**
275    *  Get the index in the constant pool of the UTF entry holding the name
276    *  of this method.
277    */
278   public int getNameIndex ()
279   {
280     return _nameIndex;
281   }
282 
283 
284   /**
285    *  Set the index in the constant pool of the UTF entry holding the name
286    *  of this method.
287    */
288   public void setNameIndex (int index)
289   {
290     _nameIndex = index;
291   }
292 
293 
294   /**
295    *  Get the index in the constant pool of the UTF entry holding the 
296    *  descriptor of this method.
297    */
298   public int getDescriptorIndex ()
299   {
300     return _descriptorIndex;
301   }
302 
303 
304   /**
305    *  Set the index in the constant pool of the UTF entry holding the 
306    *  descriptor of this method.
307    */
308   public void setDescriptorIndex (int index)
309   {
310     _descriptorIndex = index;
311   }
312 
313 
314   /**
315    *  Get the name of this method.
316    */
317   public String getName ()
318   {
319     return getPool ().getUTF (_nameIndex);
320   }
321 
322 
323   /**
324    *  Set the name of this method.
325    */
326   public void setName (String name)
327   {
328     String origName = getName ();
329 
330     // reset the name
331     _nameIndex = getPool ().setUTF (0, name);
332 
333     // find the ComplexEntry matching this field, if any
334     String internalDesc = getPool ().getUTF (_descriptorIndex);
335     String internalOwner = getPool ().getClassName (_owner.getIndex ());
336 
337     Class entry = MethodEntry.class;
338     if (_owner.isInterface ())
339       entry = InterfaceMethodEntry.class;
340 
341     int index = getPool ().getComplexIndex
342       (origName, internalDesc, internalOwner, entry);
343 
344     // change the ComplexEntry to match the new name; this is dones so
345     // that refs to the method in code will still be valid after the name
346     // change, without changing any other constants that happened to match
347     // the old method name
348     if (index != 0)
349       getPool ().setComplex (index, name, 
350         internalDesc, internalOwner, entry);
351   }
352 
353 
354 
355   /**
356    *  Get the name of the class type returned by this method.
357    */
358   public String getReturnTypeName ()
359   {
360     return BCHelper.getExternalForm (BCHelper.getReturnType 
361       (getPool ().getUTF (_descriptorIndex)), true);
362   }
363 
364 
365   /**
366    *  Get the Class of the return type of this method.
367    */
368   public Class getReturnType ()
369     throws ClassNotFoundException
370   {
371     return BCHelper.classForName (BCHelper.getReturnType 
372       (getPool ().getUTF (_descriptorIndex)));
373   }
374 
375 
376   /**
377    *  Get the names of all the parameter types for this method.
378    */
379   public String[] getParamTypeNames ()
380   {
381     // get the parameter types from the descriptor
382     String[] params = BCHelper.getParamTypes
383       (getPool ().getUTF (_descriptorIndex));
384 
385     // convert them to external form
386     for (int i = 0; i < params.length; i++)
387       params[i] = BCHelper.getExternalForm (params[i], true);
388 
389     return params;
390   }
391 
392 
393   /**
394    *  Get the types of parameters this method takes.
395    */
396   public Class[] getParamTypes ()
397     throws ClassNotFoundException
398   {
399     // get the parameter types from the descriptor
400     String[] params = BCHelper.getParamTypes 
401       (getPool ().getUTF (_descriptorIndex));
402 
403     // convert them
404     Class[] externalParams = new Class[params.length];
405     for (int i = 0; i < params.length; i++)
406       externalParams[i] = BCHelper.classForName (params[i]);
407 
408     return externalParams;
409   }
410 
411 
412   /**  
413     *  Set the return type of this method.
414    */
415   public void setReturnTypeName (String name)
416   {
417     setDescriptorInternal (BCHelper.getInternalForm (name, true), 
418       BCHelper.getParamTypes (getPool ().getUTF (_descriptorIndex)));
419   }
420 
421 
422   /**
423    *  Set the return type of this method.
424    */
425   public void setReturnType (Class type)
426   {
427     setReturnTypeName (type.getName ());
428   }
429 
430 
431   /**  
432     *  Set the parameter types of this method.
433    */
434   public void setParamTypeNames (String[] names)
435   {
436     String returnName = BCHelper.getReturnType 
437       (getPool ().getUTF (_descriptorIndex));
438     if (returnName.length () == 0)
439       returnName = "V";
440 
441     if (names == null)
442       names = new String[0];
443     else
444       for (int i = 0; i < names.length; i++)
445         names[i] = BCHelper.getInternalForm (names[i], true);
446 
447     setDescriptorInternal (returnName, names);
448   }
449 
450 
451   /**
452    *  Set the parameter type of this method.
453    */
454   public void setParamTypes (Class[] types)
455   {
456     if (types == null)
457       setParamTypeNames (null);
458 
459     String[] names = new String[types.length];
460     for (int i = 0; i < types.length; i++)
461       names[i] = types[i].getName ();
462 
463     setParamTypeNames (names);
464   }
465 
466 
467   /**
468    *  Add a parameter type to this method.
469    */
470   public void addParamTypeName (String name)
471   {
472     String[] params = getParamTypeNames ();
473     String[] newParams = new String[params.length + 1];
474 
475     for (int i = 0; i < params.length; i++)
476       newParams[i] = params[i];
477     newParams[params.length] = name;
478 
479     setParamTypeNames (newParams);
480   }
481 
482 
483   /**
484    *  Remove a parameter from this method.
485    */
486   public boolean removeParamTypeName (String name)
487   {
488     String[] names = getParamTypeNames ();
489     if (names.length == 0)
490       return false;
491 
492     String[] newNames = new String[names.length - 1];
493 
494     boolean skip = false;
495     for (int i = 0, count = 0; count < newNames.length; i++)
496     {
497       if (names[i].equals (name))
498         skip = true;
499       else
500         newNames[count++] = names[i];
501     }
502 
503     if (!skip && newNames.length > 0)
504       return false;
505 
506     setParamTypeNames (newNames);
507     return true;
508   }
509 
510 
511   /**
512    *  Remove a parameter from this method.
513    */
514   public boolean removeParamType (Class type)
515   {
516     return removeParamTypeName (type.getName ());
517   }
518 
519 
520   /**
521    *  Add a parameter type to this method.
522    */
523   public void addParamType (Class type)
524   {
525     addParamTypeName (type.getName ());
526   }
527 
528 
529   /**
530    *  Set this method descriptor; using this method is much more
531    *  efficient than setting the return type and param types separately.
532    */
533   public void setDescriptor (String returnType, String[] paramTypes)
534   {
535     returnType = BCHelper.getInternalForm (returnType, true);
536     if (paramTypes == null)
537       paramTypes = new String[0];
538     else
539       for (int i = 0; i < paramTypes.length; i++)
540         paramTypes[i] = BCHelper.getInternalForm (paramTypes[i], true);
541 
542     setDescriptorInternal (returnType, paramTypes);
543   }
544 
545 
546   /**
547    *  Set this method descriptor; using this method is much more
548    *  efficient than setting the return type and param types separately.
549    */
550   public void setDescriptor (Class returnType, Class[] paramTypes)
551   {
552     String returnStr = BCHelper.getInternalForm 
553       (returnType.getName (), true);
554 
555     String[] paramStr;
556     if (paramTypes == null)
557       paramStr = new String[0];
558     else
559     {
560       paramStr = new String[paramTypes.length];
561       for (int i = 0; i < paramTypes.length; i++)
562         paramStr[i] = BCHelper.getInternalForm 
563           (paramTypes[i].getName (), true);
564     }
565 
566     setDescriptorInternal (returnStr, paramStr);
567   }
568 
569 
570   /**
571    *  Internal helper method to set the descriptor of this method,
572    *  using the internal form of the method return type and params
573    */
574   private void setDescriptorInternal (String returnType, String[] paramTypes)
575   {
576     String origDesc = getPool ().getUTF (_descriptorIndex);
577 
578     // reset the descriptor
579     String internalDesc = BCHelper.getDescriptor (returnType, paramTypes);
580     _descriptorIndex = getPool ().setUTF (0, internalDesc);
581 
582     // find the ComplexEntry matching this method, if any
583     String internalOwner = getPool ().getClassName (_owner.getIndex ());
584 
585     Class entry = MethodEntry.class;
586     if (_owner.isInterface ())
587       entry = InterfaceMethodEntry.class;
588 
589     int index = getPool ().getComplexIndex 
590       (getName (), origDesc, internalOwner, entry);
591 
592     // change the ComplexEntry to match the new type; this is dones so
593     // that refs to the method in code will still be valid after the type
594     // change, without changing any other constants that happened to match
595     // the old method type
596     if (index != 0)
597       getPool ().setComplex (index, getName (), 
598         internalDesc, internalOwner, entry);
599   }
600 
601 
602   /**
603    *  Get the exception types thrown by this method.
604    */
605   public String[] getExceptionTypeNames ()
606   {
607     ExceptionsAttribute exceptionTable = (ExceptionsAttribute)
608       getAttribute (ATTR_EXCEPTIONS);
609     if (exceptionTable == null)
610       return new String[0];
611 
612     return exceptionTable.getExceptionTypeNames ();
613   }
614 
615 
616   /**
617    *  Get the exception types thrown by this method.
618    */
619   public Class[] getExceptionTypes ()
620     throws ClassNotFoundException
621   {
622     ExceptionsAttribute exceptionTable = (ExceptionsAttribute)
623       getAttribute (ATTR_EXCEPTIONS);
624     if (exceptionTable == null)
625       return new Class[0];
626 
627     return exceptionTable.getExceptionTypes ();
628   }
629 
630 
631   /**
632    *  Remove all declared exceptions from this method.
633    */
634   public void clearExceptionTypes ()
635   {
636     removeAttribute (ATTR_EXCEPTIONS);
637   }
638 
639 
640   /**
641    *  Remove the given exception type from those that this method 
642    *  declares in its throws clause.
643    */
644   public boolean removeExceptionTypeName (String name)
645   {
646     ExceptionsAttribute exceptionTable = (ExceptionsAttribute)
647       getAttribute (ATTR_EXCEPTIONS);
648     if (exceptionTable == null)
649       return false;
650 
651     return exceptionTable.removeExceptionTypeName (name);
652   }
653 
654 
655   /**
656    *  Remove the given exception type from those that this method 
657    *  declares in its throws clause.
658    */
659   public boolean removeExceptionType (Class type)
660   {
661     return removeExceptionTypeName (type.getName ());
662   }
663 
664 
665   /**
666    *  Set the exception types for this method.
667    */
668   public void setExceptionTypeNames (String[] types)
669   {
670     if (types == null || types.length == 0)
671       removeAttribute (ATTR_EXCEPTIONS);
672     else
673     {
674       ExceptionsAttribute exceptionTable = (ExceptionsAttribute)
675         getAttribute (ATTR_EXCEPTIONS);
676       if (exceptionTable == null)
677         exceptionTable = (ExceptionsAttribute) addAttribute 
678           (ATTR_EXCEPTIONS);
679 
680       exceptionTable.setExceptionTypeNames (types);
681     }
682   }
683 
684 
685   /**
686    *  Set the exception types for this method.
687    */
688   public void setExceptionTypes (Class[] types)
689   {
690     if (types == null)
691       setExceptionTypeNames ((String[]) null);
692     else
693     {
694       String[] names = new String[types.length];
695       for (int i = 0; i < names.length; i++)
696         names[i] = types[i].getName ();
697       
698       setExceptionTypeNames (names);
699     }
700   }
701 
702 
703   /**  
704     *  Add an exception to those declared by this method.
705    */
706   public void addExceptionTypeName (String name)
707   {
708     ExceptionsAttribute exceptionTable = (ExceptionsAttribute)
709       getAttribute (ATTR_EXCEPTIONS);
710     if (exceptionTable == null)
711       exceptionTable = (ExceptionsAttribute) addAttribute 
712         (ATTR_EXCEPTIONS);
713 
714     exceptionTable.addExceptionTypeName (name);
715   }
716 
717 
718   /**  
719     *  Add an exception to those declared by this method.
720    */
721   public void addExceptionType (Class type)
722   {
723     addExceptionTypeName (type.getName ());
724   }
725 
726 
727   /**
728      *  Get the code for this method; returns null if none.
729    *  Note that each time the code is fetched, the position of the code
730    *  iterator is reset to before the first opcode.
731      */ 
732     public Code getCode ()   
733   {
734         Code code = (Code) getAttribute (ATTR_CODE);
735     if (code != null)
736       code.beforeFirst ();
737 
738     return code;
739   }
740 
741 
742   /**
743    *  Add a code block to this method; replaces the old block if it exists.
744    */
745   public Code addCode ()
746   {
747     removeAttribute (ATTR_CODE);
748     return (Code) addAttribute (ATTR_CODE);
749   }
750 
751 
752   /**
753    *  Remove the code from this method; note that this actually removes the
754    *  Code attribute completely; if you want to make an empty code block use
755    *  the Code.clear() method.
756    */
757   public boolean removeCode ()
758   {
759     return removeAttribute (ATTR_CODE);
760   }
761 
762 
763   /**
764    *  Import a code block from another method.  The given method can be of
765    *  this class or a different one.  This will cause the code of this method
766    *  to become an exact duplicate of the given code block.
767    */
768   public Code importCode (Code code)
769   {
770     removeAttribute (ATTR_CODE);
771     return (Code) importAttribute (code);
772   }
773 
774 
775   /**
776    *  Get the class constant pool; this method delegates to the
777     *  owning class.
778    */
779   public ConstantPool getPool ()
780   {
781     return getOwner ().getPool ();
782   }
783 
784 
785   protected void readData (DataInput in)
786     throws IOException
787   {
788     setAccessFlags (in.readUnsignedShort ());  
789     setNameIndex (in.readUnsignedShort ());  
790     setDescriptorIndex (in.readUnsignedShort ());  
791 
792     readAttributes (in);
793   }
794 
795 
796   protected void writeData (DataOutput out)
797     throws IOException
798   {
799     out.writeShort (getAccessFlags ());
800     out.writeShort (getNameIndex ());
801     out.writeShort (getDescriptorIndex ());
802 
803     writeAttributes (out);
804   }
805 
806 
807   public void acceptVisit (BCVisitor visit)
808   {
809     visit.enterBCMethod (this);
810     visitAttributes (visit);
811     visit.exitBCMethod (this);
812   }
813 }