1/*
2 * Javassist, a Java-bytecode translator toolkit.
3 * Copyright (C) 1999-2007 Shigeru Chiba. All Rights Reserved.
4 *
5 * The contents of this file are subject to the Mozilla Public License Version
6 * 1.1 (the "License"); you may not use this file except in compliance with
7 * the License.  Alternatively, the contents of this file may be used under
8 * the terms of the GNU Lesser General Public License Version 2.1 or later.
9 *
10 * Software distributed under the License is distributed on an "AS IS" basis,
11 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12 * for the specific language governing rights and limitations under the
13 * License.
14 */
15
16package javassist;
17
18import javassist.bytecode.*;
19import javassist.convert.*;
20
21/**
22 * Simple translator of method bodies
23 * (also see the <code>javassist.expr</code> package).
24 *
25 * <p>Instances of this class specifies how to instrument of the
26 * bytecodes representing a method body.  They are passed to
27 * <code>CtClass.instrument()</code> or
28 * <code>CtMethod.instrument()</code> as a parameter.
29 *
30 * <p>Example:
31 * <ul><pre>
32 * ClassPool cp = ClassPool.getDefault();
33 * CtClass point = cp.get("Point");
34 * CtClass singleton = cp.get("Singleton");
35 * CtClass client = cp.get("Client");
36 * CodeConverter conv = new CodeConverter();
37 * conv.replaceNew(point, singleton, "makePoint");
38 * client.instrument(conv);
39 * </pre></ul>
40 *
41 * <p>This program substitutes "<code>Singleton.makePoint()</code>"
42 * for all occurrences of "<code>new Point()</code>"
43 * appearing in methods declared in a <code>Client</code> class.
44 *
45 * @see javassist.CtClass#instrument(CodeConverter)
46 * @see javassist.CtMethod#instrument(CodeConverter)
47 * @see javassist.expr.ExprEditor
48 */
49public class CodeConverter {
50    protected Transformer transformers = null;
51
52    /**
53     * Modify a method body so that instantiation of the specified class
54     * is replaced with a call to the specified static method.  For example,
55     * <code>replaceNew(ctPoint, ctSingleton, "createPoint")</code>
56     * (where <code>ctPoint</code> and <code>ctSingleton</code> are
57     * compile-time classes for class <code>Point</code> and class
58     * <code>Singleton</code>, respectively)
59     * replaces all occurrences of:
60     *
61     * <ul><code>new Point(x, y)</code></ul>
62     *
63     * in the method body with:
64     *
65     * <ul><code>Singleton.createPoint(x, y)</code></ul>
66     *
67     * <p>This enables to intercept instantiation of <code>Point</code>
68     * and change the samentics.  For example, the following
69     * <code>createPoint()</code> implements the singleton pattern:
70     *
71     * <ul><pre>public static Point createPoint(int x, int y) {
72     *     if (aPoint == null)
73     *         aPoint = new Point(x, y);
74     *     return aPoint;
75     * }
76     * </pre></ul>
77     *
78     * <p>The static method call substituted for the original <code>new</code>
79     * expression must be
80     * able to receive the same set of parameters as the original
81     * constructor.  If there are multiple constructors with different
82     * parameter types, then there must be multiple static methods
83     * with the same name but different parameter types.
84     *
85     * <p>The return type of the substituted static method must be
86     * the exactly same as the type of the instantiated class specified by
87     * <code>newClass</code>.
88     *
89     * @param newClass          the instantiated class.
90     * @param calledClass       the class in which the static method is
91     *                          declared.
92     * @param calledMethod      the name of the static method.
93     */
94    public void replaceNew(CtClass newClass,
95                           CtClass calledClass, String calledMethod) {
96        transformers = new TransformNew(transformers, newClass.getName(),
97                                        calledClass.getName(), calledMethod);
98    }
99
100    /**
101     * Modify a method body so that instantiation of the class
102     * specified by <code>oldClass</code>
103     * is replaced with instantiation of another class <code>newClass</code>.
104     * For example,
105     * <code>replaceNew(ctPoint, ctPoint2)</code>
106     * (where <code>ctPoint</code> and <code>ctPoint2</code> are
107     * compile-time classes for class <code>Point</code> and class
108     * <code>Point2</code>, respectively)
109     * replaces all occurrences of:
110     *
111     * <ul><code>new Point(x, y)</code></ul>
112     *
113     * in the method body with:
114     *
115     * <ul><code>new Point2(x, y)</code></ul>
116     *
117     * <p>Note that <code>Point2</code> must be type-compatible with <code>Point</code>.
118     * It must have the same set of methods, fields, and constructors as the
119     * replaced class.
120     */
121    public void replaceNew(CtClass oldClass, CtClass newClass) {
122        transformers = new TransformNewClass(transformers, oldClass.getName(),
123                                             newClass.getName());
124    }
125
126    /**
127     * Modify a method body so that field read/write expressions access
128     * a different field from the original one.
129     *
130     * <p>Note that this method changes only the filed name and the class
131     * declaring the field; the type of the target object does not change.
132     * Therefore, the substituted field must be declared in the same class
133     * or a superclass of the original class.
134     *
135     * <p>Also, <code>clazz</code> and <code>newClass</code> must specify
136     * the class directly declaring the field.  They must not specify
137     * a subclass of that class.
138     *
139     * @param field             the originally accessed field.
140     * @param newClass  the class declaring the substituted field.
141     * @param newFieldname      the name of the substituted field.
142     */
143    public void redirectFieldAccess(CtField field,
144                                    CtClass newClass, String newFieldname) {
145        transformers = new TransformFieldAccess(transformers, field,
146                                                newClass.getName(),
147                                                newFieldname);
148    }
149
150    /**
151     * Modify a method body so that an expression reading the specified
152     * field is replaced with a call to the specified <i>static</i> method.
153     * This static method receives the target object of the original
154     * read expression as a parameter.  It must return a value of
155     * the same type as the field.
156     *
157     * <p>For example, the program below
158     *
159     * <ul><pre>Point p = new Point();
160     * int newX = p.x + 3;</pre></ul>
161     *
162     * <p>can be translated into:
163     *
164     * <ul><pre>Point p = new Point();
165     * int newX = Accessor.readX(p) + 3;</pre></ul>
166     *
167     * <p>where
168     *
169     * <ul><pre>public class Accessor {
170     *     public static int readX(Object target) { ... }
171     * }</pre></ul>
172     *
173     * <p>The type of the parameter of <code>readX()</code> must
174     * be <code>java.lang.Object</code> independently of the actual
175     * type of <code>target</code>.  The return type must be the same
176     * as the field type.
177     *
178     * @param field             the field.
179     * @param calledClass       the class in which the static method is
180     *                          declared.
181     * @param calledMethod      the name of the static method.
182     */
183    public void replaceFieldRead(CtField field,
184                                 CtClass calledClass, String calledMethod) {
185        transformers = new TransformReadField(transformers, field,
186                                              calledClass.getName(),
187                                              calledMethod);
188    }
189
190    /**
191     * Modify a method body so that an expression writing the specified
192     * field is replaced with a call to the specified static method.
193     * This static method receives two parameters: the target object of
194     * the original
195     * write expression and the assigned value.  The return type of the
196     * static method is <code>void</code>.
197     *
198     * <p>For example, the program below
199     *
200     * <ul><pre>Point p = new Point();
201     * p.x = 3;</pre></ul>
202     *
203     * <p>can be translated into:
204     *
205     * <ul><pre>Point p = new Point();
206     * Accessor.writeX(3);</pre></ul>
207     *
208     * <p>where
209     *
210     * <ul><pre>public class Accessor {
211     *     public static void writeX(Object target, int value) { ... }
212     * }</pre></ul>
213     *
214     * <p>The type of the first parameter of <code>writeX()</code> must
215     * be <code>java.lang.Object</code> independently of the actual
216     * type of <code>target</code>.  The type of the second parameter
217     * is the same as the field type.
218     *
219     * @param field             the field.
220     * @param calledClass       the class in which the static method is
221     *                          declared.
222     * @param calledMethod      the name of the static method.
223     */
224    public void replaceFieldWrite(CtField field,
225                                  CtClass calledClass, String calledMethod) {
226        transformers = new TransformWriteField(transformers, field,
227                                               calledClass.getName(),
228                                               calledMethod);
229    }
230
231    /**
232     * Modify a method body, so that ALL accesses to an array are replaced with
233     * calls to static methods within another class. In the case of reading an
234     * element from the array, this is replaced with a call to a static method with
235     * the array and the index as arguments, the return value is the value read from
236     * the array. If writing to an array, this is replaced with a call to a static
237     * method with the array, index and new value as parameters, the return value of
238     * the static method is <code>void</code>.
239     *
240     * <p>The <code>calledClass</code> parameter is the class containing the static methods to be used
241     * for array replacement. The <code>names</code> parameter points to an implementation of
242     * <code>ArrayAccessReplacementMethodNames</code> which specifies the names of the method to be
243     * used for access for each type of array.  For example reading from an <code>int[]</code> will
244     * require a different method than if writing to an <code>int[]</code>, and writing to a <code>long[]</code>
245     * will require a different method than if writing to a <code>byte[]</code>. If the implementation
246     * of <code>ArrayAccessReplacementMethodNames</code> does not contain the name for access for a
247     * type of array, that access is not replaced.
248     *
249     * <p>A default implementation of <code>ArrayAccessReplacementMethodNames</code> called
250     * <code>DefaultArrayAccessReplacementMethodNames</code> has been provided and is what is used in the
251     * following example. This also assumes that <code>'foo.ArrayAdvisor'</code> is the name of the
252     * <code>CtClass</code> passed in.
253     *
254     * <p>If we have the following class:
255     * <pre>class POJO{
256     *    int[] ints = new int[]{1, 2, 3, 4, 5};
257     *    long[] longs = new int[]{10, 20, 30};
258     *    Object objects = new Object[]{true, false};
259     *    Integer[] integers = new Integer[]{new Integer(10)};
260     * }
261     * </pre>
262     * and this is accessed as:
263     * <pre>POJO p = new POJO();
264     *
265     * //Write to int array
266     * p.ints[2] = 7;
267     *
268     * //Read from int array
269     * int i = p.ints[2];
270     *
271     * //Write to long array
272     * p.longs[2] = 1000L;
273     *
274     * //Read from long array
275     * long l = p.longs[2];
276     *
277     * //Write to Object array
278     * p.objects[2] = "Hello";
279     *
280     * //Read from Object array
281     * Object o = p.objects[2];
282     *
283     * //Write to Integer array
284     * Integer integer = new Integer(5);
285     * p.integers[0] = integer;
286     *
287     * //Read from Object array
288     * integer = p.integers[0];
289     * </pre>
290     *
291     * Following instrumentation we will have
292     * <pre>POJO p = new POJO();
293     *
294     * //Write to int array
295     * ArrayAdvisor.arrayWriteInt(p.ints, 2, 7);
296     *
297     * //Read from int array
298     * int i = ArrayAdvisor.arrayReadInt(p.ints, 2);
299     *
300     * //Write to long array
301     * ArrayAdvisor.arrayWriteLong(p.longs, 2, 1000L);
302     *
303     * //Read from long array
304     * long l = ArrayAdvisor.arrayReadLong(p.longs, 2);
305     *
306     * //Write to Object array
307     * ArrayAdvisor.arrayWriteObject(p.objects, 2, "Hello");
308     *
309     * //Read from Object array
310     * Object o = ArrayAdvisor.arrayReadObject(p.objects, 2);
311     *
312     * //Write to Integer array
313     * Integer integer = new Integer(5);
314     * ArrayAdvisor.arrayWriteObject(p.integers, 0, integer);
315     *
316     * //Read from Object array
317     * integer = ArrayAdvisor.arrayWriteObject(p.integers, 0);
318     * </pre>
319     *
320     * @see DefaultArrayAccessReplacementMethodNames
321     *
322     * @param calledClass        the class containing the static methods.
323     * @param names              contains the names of the methods to replace
324     *                           the different kinds of array access with.
325     */
326    public void replaceArrayAccess(CtClass calledClass, ArrayAccessReplacementMethodNames names)
327        throws NotFoundException
328    {
329       transformers = new TransformAccessArrayField(transformers, calledClass.getName(), names);
330    }
331
332    /**
333     * Modify method invocations in a method body so that a different
334     * method will be invoked.
335     *
336     * <p>Note that the target object, the parameters, or
337     * the type of invocation
338     * (static method call, interface call, or private method call)
339     * are not modified.  Only the method name is changed.  The substituted
340     * method must have the same signature that the original one has.
341     * If the original method is a static method, the substituted method
342     * must be static.
343     *
344     * @param origMethod        original method
345     * @param substMethod       substituted method
346     */
347    public void redirectMethodCall(CtMethod origMethod,
348                                   CtMethod substMethod)
349        throws CannotCompileException
350    {
351        String d1 = origMethod.getMethodInfo2().getDescriptor();
352        String d2 = substMethod.getMethodInfo2().getDescriptor();
353        if (!d1.equals(d2))
354            throw new CannotCompileException("signature mismatch: "
355                                             + substMethod.getLongName());
356
357        int mod1 = origMethod.getModifiers();
358        int mod2 = substMethod.getModifiers();
359        if (Modifier.isStatic(mod1) != Modifier.isStatic(mod2)
360            || (Modifier.isPrivate(mod1) && !Modifier.isPrivate(mod2))
361            || origMethod.getDeclaringClass().isInterface()
362               != substMethod.getDeclaringClass().isInterface())
363            throw new CannotCompileException("invoke-type mismatch "
364                                             + substMethod.getLongName());
365
366        transformers = new TransformCall(transformers, origMethod,
367                                         substMethod);
368    }
369
370    /**
371     * Correct invocations to a method that has been renamed.
372     * If a method is renamed, calls to that method must be also
373     * modified so that the method with the new name will be called.
374     *
375     * <p>The method must be declared in the same class before and
376     * after it is renamed.
377     *
378     * <p>Note that the target object, the parameters, or
379     * the type of invocation
380     * (static method call, interface call, or private method call)
381     * are not modified.  Only the method name is changed.
382     *
383     * @param oldMethodName        the old name of the method.
384     * @param newMethod            the method with the new name.
385     * @see javassist.CtMethod#setName(String)
386     */
387    public void redirectMethodCall(String oldMethodName,
388                                   CtMethod newMethod)
389        throws CannotCompileException
390    {
391        transformers
392            = new TransformCall(transformers, oldMethodName, newMethod);
393    }
394
395    /**
396     * Insert a call to another method before an existing method call.
397     * That "before" method must be static.  The return type must be
398     * <code>void</code>.  As parameters, the before method receives
399     * the target object and all the parameters to the originally invoked
400     * method.  For example, if the originally invoked method is
401     * <code>move()</code>:
402     *
403     * <ul><pre>class Point {
404     *     Point move(int x, int y) { ... }
405     * }</pre></ul>
406     *
407     * <p>Then the before method must be something like this:
408     *
409     * <ul><pre>class Verbose {
410     *     static void print(Point target, int x, int y) { ... }
411     * }</pre></ul>
412     *
413     * <p>The <code>CodeConverter</code> would translate bytecode
414     * equivalent to:
415     *
416     * <ul><pre>Point p2 = p.move(x + y, 0);</pre></ul>
417     *
418     * <p>into the bytecode equivalent to:
419     *
420     * <ul><pre>int tmp1 = x + y;
421     * int tmp2 = 0;
422     * Verbose.print(p, tmp1, tmp2);
423     * Point p2 = p.move(tmp1, tmp2);</pre></ul>
424     *
425     * @param origMethod        the method originally invoked.
426     * @param beforeMethod      the method invoked before
427     *                          <code>origMethod</code>.
428     */
429    public void insertBeforeMethod(CtMethod origMethod,
430                                   CtMethod beforeMethod)
431        throws CannotCompileException
432    {
433        try {
434            transformers = new TransformBefore(transformers, origMethod,
435                                               beforeMethod);
436        }
437        catch (NotFoundException e) {
438            throw new CannotCompileException(e);
439        }
440    }
441
442    /**
443     * Inserts a call to another method after an existing method call.
444     * That "after" method must be static.  The return type must be
445     * <code>void</code>.  As parameters, the after method receives
446     * the target object and all the parameters to the originally invoked
447     * method.  For example, if the originally invoked method is
448     * <code>move()</code>:
449     *
450     * <ul><pre>class Point {
451     *     Point move(int x, int y) { ... }
452     * }</pre></ul>
453     *
454     * <p>Then the after method must be something like this:
455     *
456     * <ul><pre>class Verbose {
457     *     static void print(Point target, int x, int y) { ... }
458     * }</pre></ul>
459     *
460     * <p>The <code>CodeConverter</code> would translate bytecode
461     * equivalent to:
462     *
463     * <ul><pre>Point p2 = p.move(x + y, 0);</pre></ul>
464     *
465     * <p>into the bytecode equivalent to:
466     *
467     * <ul><pre>int tmp1 = x + y;
468     * int tmp2 = 0;
469     * Point p2 = p.move(tmp1, tmp2);
470     * Verbose.print(p, tmp1, tmp2);</pre></ul>
471     *
472     * @param origMethod        the method originally invoked.
473     * @param afterMethod       the method invoked after
474     *                          <code>origMethod</code>.
475     */
476    public void insertAfterMethod(CtMethod origMethod,
477                                  CtMethod afterMethod)
478        throws CannotCompileException
479    {
480        try {
481            transformers = new TransformAfter(transformers, origMethod,
482                                               afterMethod);
483        }
484        catch (NotFoundException e) {
485            throw new CannotCompileException(e);
486        }
487    }
488
489    /**
490     * Performs code conversion.
491     */
492    protected void doit(CtClass clazz, MethodInfo minfo, ConstPool cp)
493        throws CannotCompileException
494    {
495       Transformer t;
496        CodeAttribute codeAttr = minfo.getCodeAttribute();
497        if (codeAttr == null || transformers == null)
498            return;
499        for (t = transformers; t != null; t = t.getNext())
500            t.initialize(cp, clazz, minfo);
501
502        CodeIterator iterator = codeAttr.iterator();
503        while (iterator.hasNext()) {
504            try {
505                int pos = iterator.next();
506                for (t = transformers; t != null; t = t.getNext())
507                    pos = t.transform(clazz, pos, iterator, cp);
508            }
509            catch (BadBytecode e) {
510                throw new CannotCompileException(e);
511            }
512        }
513
514        int locals = 0;
515        int stack = 0;
516        for (t = transformers; t != null; t = t.getNext()) {
517            int s = t.extraLocals();
518            if (s > locals)
519                locals = s;
520
521            s = t.extraStack();
522            if (s > stack)
523                stack = s;
524        }
525
526        for (t = transformers; t != null; t = t.getNext())
527            t.clean();
528
529        if (locals > 0)
530            codeAttr.setMaxLocals(codeAttr.getMaxLocals() + locals);
531
532        if (stack > 0)
533            codeAttr.setMaxStack(codeAttr.getMaxStack() + stack);
534    }
535
536    /**
537     * Interface containing the method names to be used
538     * as array access replacements.
539     *
540     * @author <a href="kabir.khan@jboss.com">Kabir Khan</a>
541     * @version $Revision: 1.16 $
542     */
543    public interface ArrayAccessReplacementMethodNames
544    {
545       /**
546        * Returns the name of a static method with the signature
547        * <code>(Ljava/lang/Object;I)B</code> to replace reading from a byte[].
548        */
549       String byteOrBooleanRead();
550
551       /**
552        * Returns the name of a static method with the signature
553        * <code>(Ljava/lang/Object;IB)V</code> to replace writing to a byte[].
554        */
555       String byteOrBooleanWrite();
556
557       /**
558        * @return the name of a static method with the signature
559        * <code>(Ljava/lang/Object;I)C</code> to replace reading from a char[].
560        */
561       String charRead();
562
563       /**
564        * Returns the name of a static method with the signature
565        * <code>(Ljava/lang/Object;IC)V</code> to replace writing to a byte[].
566        */
567       String charWrite();
568
569       /**
570        * Returns the name of a static method with the signature
571        * <code>(Ljava/lang/Object;I)D</code> to replace reading from a double[].
572        */
573       String doubleRead();
574
575       /**
576        * Returns the name of a static method with the signature
577        * <code>(Ljava/lang/Object;ID)V</code> to replace writing to a double[].
578        */
579       String doubleWrite();
580
581       /**
582        * Returns the name of a static method with the signature
583        * <code>(Ljava/lang/Object;I)F</code> to replace reading from a float[].
584        */
585       String floatRead();
586
587       /**
588        * Returns the name of a static method with the signature
589        * <code>(Ljava/lang/Object;IF)V</code> to replace writing to a float[].
590        */
591       String floatWrite();
592
593       /**
594        * Returns the name of a static method with the signature
595        * <code>(Ljava/lang/Object;I)I</code> to replace reading from a int[].
596        */
597       String intRead();
598
599       /**
600        * Returns the name of a static method with the signature
601        * <code>(Ljava/lang/Object;II)V</code> to replace writing to a int[].
602        */
603       String intWrite();
604
605       /**
606        * Returns the name of a static method with the signature
607        * <code>(Ljava/lang/Object;I)J</code> to replace reading from a long[].
608        */
609       String longRead();
610
611       /**
612        * Returns the name of a static method with the signature
613        * <code>(Ljava/lang/Object;IJ)V</code> to replace writing to a long[].
614        */
615       String longWrite();
616
617       /**
618        * Returns the name of a static method with the signature
619        * <code>(Ljava/lang/Object;I)Ljava/lang/Object;</code>
620        * to replace reading from a Object[] (or any subclass of object).
621        */
622       String objectRead();
623
624       /**
625        * Returns the name of a static method with the signature
626        * <code>(Ljava/lang/Object;ILjava/lang/Object;)V</code>
627        * to replace writing to a Object[] (or any subclass of object).
628        */
629       String objectWrite();
630
631       /**
632        * Returns the name of a static method with the signature
633        * <code>(Ljava/lang/Object;I)S</code> to replace reading from a short[].
634        */
635       String shortRead();
636
637       /**
638        * Returns the name of a static method with the signature
639        * <code>(Ljava/lang/Object;IS)V</code> to replace writing to a short[].
640        */
641       String shortWrite();
642    }
643
644    /**
645     * Default implementation of the <code>ArrayAccessReplacementMethodNames</code>
646     * interface giving default values for method names to be used for replacing
647     * accesses to array elements.
648     *
649     * @author <a href="kabir.khan@jboss.com">Kabir Khan</a>
650     * @version $Revision: 1.16 $
651     */
652    public static class DefaultArrayAccessReplacementMethodNames
653        implements ArrayAccessReplacementMethodNames
654    {
655       /**
656        * Returns "arrayReadByteOrBoolean" as the name of the static method with the signature
657        * (Ljava/lang/Object;I)B to replace reading from a byte[].
658        */
659       public String byteOrBooleanRead()
660       {
661          return "arrayReadByteOrBoolean";
662       }
663
664       /**
665        * Returns "arrayWriteByteOrBoolean" as the name of the static method with the signature
666        * (Ljava/lang/Object;IB)V  to replace writing to a byte[].
667        */
668       public String byteOrBooleanWrite()
669       {
670          return "arrayWriteByteOrBoolean";
671       }
672
673       /**
674        * Returns "arrayReadChar" as the name of the static method with the signature
675        * (Ljava/lang/Object;I)C  to replace reading from a char[].
676        */
677       public String charRead()
678       {
679          return "arrayReadChar";
680       }
681
682       /**
683        * Returns "arrayWriteChar" as the name of the static method with the signature
684        * (Ljava/lang/Object;IC)V to replace writing to a byte[].
685        */
686       public String charWrite()
687       {
688          return "arrayWriteChar";
689       }
690
691       /**
692        * Returns "arrayReadDouble" as the name of the static method with the signature
693        * (Ljava/lang/Object;I)D to replace reading from a double[].
694        */
695       public String doubleRead()
696       {
697          return "arrayReadDouble";
698       }
699
700       /**
701        * Returns "arrayWriteDouble" as the name of the static method with the signature
702        * (Ljava/lang/Object;ID)V to replace writing to a double[].
703        */
704       public String doubleWrite()
705       {
706          return "arrayWriteDouble";
707       }
708
709       /**
710        * Returns "arrayReadFloat" as the name of the static method with the signature
711        * (Ljava/lang/Object;I)F  to replace reading from a float[].
712        */
713       public String floatRead()
714       {
715          return "arrayReadFloat";
716       }
717
718       /**
719        * Returns "arrayWriteFloat" as the name of the static method with the signature
720        * (Ljava/lang/Object;IF)V  to replace writing to a float[].
721        */
722       public String floatWrite()
723       {
724          return "arrayWriteFloat";
725       }
726
727       /**
728        * Returns "arrayReadInt" as the name of the static method with the signature
729        * (Ljava/lang/Object;I)I to replace reading from a int[].
730        */
731       public String intRead()
732       {
733          return "arrayReadInt";
734       }
735
736       /**
737        * Returns "arrayWriteInt" as the name of the static method with the signature
738        * (Ljava/lang/Object;II)V to replace writing to a int[].
739        */
740       public String intWrite()
741       {
742          return "arrayWriteInt";
743       }
744
745       /**
746        * Returns "arrayReadLong" as the name of the static method with the signature
747        * (Ljava/lang/Object;I)J to replace reading from a long[].
748        */
749       public String longRead()
750       {
751          return "arrayReadLong";
752       }
753
754       /**
755        * Returns "arrayWriteLong" as the name of the static method with the signature
756        * (Ljava/lang/Object;IJ)V to replace writing to a long[].
757        */
758       public String longWrite()
759       {
760          return "arrayWriteLong";
761       }
762
763       /**
764        * Returns "arrayReadObject" as the name of the static method with the signature
765        * (Ljava/lang/Object;I)Ljava/lang/Object;  to replace reading from a Object[] (or any subclass of object).
766        */
767       public String objectRead()
768       {
769          return "arrayReadObject";
770       }
771
772       /**
773        * Returns "arrayWriteObject" as the name of the static method with the signature
774        * (Ljava/lang/Object;ILjava/lang/Object;)V  to replace writing to a Object[] (or any subclass of object).
775        */
776       public String objectWrite()
777       {
778          return "arrayWriteObject";
779       }
780
781       /**
782        * Returns "arrayReadShort" as the name of the static method with the signature
783        * (Ljava/lang/Object;I)S to replace reading from a short[].
784        */
785       public String shortRead()
786       {
787          return "arrayReadShort";
788       }
789
790       /**
791        * Returns "arrayWriteShort" as the name of the static method with the signature
792        * (Ljava/lang/Object;IS)V to replace writing to a short[].
793        */
794       public String shortWrite()
795       {
796          return "arrayWriteShort";
797       }
798    }
799}
800