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 
16 package javassist;
17 
18 import javassist.bytecode.*;
19 import 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  */
49 public 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      */
replaceNew(CtClass newClass, CtClass calledClass, String calledMethod)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      */
replaceNew(CtClass oldClass, CtClass newClass)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      */
redirectFieldAccess(CtField field, CtClass newClass, String newFieldname)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      */
replaceFieldRead(CtField field, CtClass calledClass, String calledMethod)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      */
replaceFieldWrite(CtField field, CtClass calledClass, String calledMethod)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      */
replaceArrayAccess(CtClass calledClass, ArrayAccessReplacementMethodNames names)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      */
redirectMethodCall(CtMethod origMethod, CtMethod substMethod)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      */
redirectMethodCall(String oldMethodName, CtMethod newMethod)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      */
insertBeforeMethod(CtMethod origMethod, CtMethod beforeMethod)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      */
insertAfterMethod(CtMethod origMethod, CtMethod afterMethod)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      */
doit(CtClass clazz, MethodInfo minfo, ConstPool cp)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         */
byteOrBooleanRead()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         */
byteOrBooleanWrite()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         */
charRead()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         */
charWrite()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         */
doubleRead()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         */
doubleWrite()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         */
floatRead()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         */
floatWrite()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         */
intRead()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         */
intWrite()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         */
longRead()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         */
longWrite()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         */
objectRead()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         */
objectWrite()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         */
shortRead()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         */
shortWrite()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         */
byteOrBooleanRead()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         */
byteOrBooleanWrite()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         */
charRead()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         */
charWrite()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         */
doubleRead()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         */
doubleWrite()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         */
floatRead()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         */
floatWrite()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         */
intRead()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         */
intWrite()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         */
longRead()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         */
longWrite()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         */
objectRead()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         */
objectWrite()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         */
shortRead()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         */
shortWrite()794        public String shortWrite()
795        {
796           return "arrayWriteShort";
797        }
798     }
799 }
800