aboutsummaryrefslogtreecommitdiffstats
path: root/src/main/javassist/CodeConverter.java
blob: bbc5c77d05eb51abbd92fdb51fc273195f99530f (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
/*
 * Javassist, a Java-bytecode translator toolkit.
 * Copyright (C) 1999- Shigeru Chiba. All Rights Reserved.
 *
 * The contents of this file are subject to the Mozilla Public License Version
 * 1.1 (the "License"); you may not use this file except in compliance with
 * the License.  Alternatively, the contents of this file may be used under
 * the terms of the GNU Lesser General Public License Version 2.1 or later,
 * or the Apache License Version 2.0.
 *
 * Software distributed under the License is distributed on an "AS IS" basis,
 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
 * for the specific language governing rights and limitations under the
 * License.
 */

package javassist;

import javassist.bytecode.*;
import javassist.convert.*;

/**
 * Simple translator of method bodies
 * (also see the <code>javassist.expr</code> package).
 *
 * <p>Instances of this class specifies how to instrument of the
 * bytecodes representing a method body.  They are passed to
 * <code>CtClass.instrument()</code> or
 * <code>CtMethod.instrument()</code> as a parameter.
 *
 * <p>Example:
 * <pre>
 * ClassPool cp = ClassPool.getDefault();
 * CtClass point = cp.get("Point");
 * CtClass singleton = cp.get("Singleton");
 * CtClass client = cp.get("Client");
 * CodeConverter conv = new CodeConverter();
 * conv.replaceNew(point, singleton, "makePoint");
 * client.instrument(conv);
 * </pre>
 *
 * <p>This program substitutes "<code>Singleton.makePoint()</code>"
 * for all occurrences of "<code>new Point()</code>"
 * appearing in methods declared in a <code>Client</code> class.
 *
 * @see javassist.CtClass#instrument(CodeConverter)
 * @see javassist.CtMethod#instrument(CodeConverter)
 * @see javassist.expr.ExprEditor
 */
public class CodeConverter {
    protected Transformer transformers = null;

    /**
     * Modify a method body so that instantiation of the specified class
     * is replaced with a call to the specified static method.  For example,
     * <code>replaceNew(ctPoint, ctSingleton, "createPoint")</code>
     * (where <code>ctPoint</code> and <code>ctSingleton</code> are
     * compile-time classes for class <code>Point</code> and class
     * <code>Singleton</code>, respectively)
     * replaces all occurrences of:
     *
     * <pre>new Point(x, y)</pre>
     *
     * in the method body with:
     *
     * <pre>Singleton.createPoint(x, y)</pre>
     *
     * <p>This enables to intercept instantiation of <code>Point</code>
     * and change the samentics.  For example, the following
     * <code>createPoint()</code> implements the singleton pattern:
     *
     * <pre>public static Point createPoint(int x, int y) {
     *     if (aPoint == null)
     *         aPoint = new Point(x, y);
     *     return aPoint;
     * }
     * </pre>
     *
     * <p>The static method call substituted for the original <code>new</code>
     * expression must be
     * able to receive the same set of parameters as the original
     * constructor.  If there are multiple constructors with different
     * parameter types, then there must be multiple static methods
     * with the same name but different parameter types.
     *
     * <p>The return type of the substituted static method must be
     * the exactly same as the type of the instantiated class specified by
     * <code>newClass</code>.
     *
     * @param newClass          the instantiated class.
     * @param calledClass       the class in which the static method is
     *                          declared.
     * @param calledMethod      the name of the static method.
     */
    public void replaceNew(CtClass newClass,
                           CtClass calledClass, String calledMethod) {
        transformers = new TransformNew(transformers, newClass.getName(),
                                        calledClass.getName(), calledMethod);
    }

    /**
     * Modify a method body so that instantiation of the class
     * specified by <code>oldClass</code>
     * is replaced with instantiation of another class <code>newClass</code>.
     * For example,
     * <code>replaceNew(ctPoint, ctPoint2)</code>
     * (where <code>ctPoint</code> and <code>ctPoint2</code> are
     * compile-time classes for class <code>Point</code> and class
     * <code>Point2</code>, respectively)
     * replaces all occurrences of:
     *
     * <pre>new Point(x, y)</pre>
     *
     * in the method body with:
     *
     * <pre>new Point2(x, y)</pre>
     *
     * <p>Note that <code>Point2</code> must be type-compatible with <code>Point</code>.
     * It must have the same set of methods, fields, and constructors as the
     * replaced class. 
     */
    public void replaceNew(CtClass oldClass, CtClass newClass) {
        transformers = new TransformNewClass(transformers, oldClass.getName(),
                                             newClass.getName());
    }

    /**
     * Modify a method body so that field read/write expressions access
     * a different field from the original one.
     *
     * <p>Note that this method changes only the filed name and the class
     * declaring the field; the type of the target object does not change.
     * Therefore, the substituted field must be declared in the same class
     * or a superclass of the original class.
     *
     * <p>Also, <code>clazz</code> and <code>newClass</code> must specify
     * the class directly declaring the field.  They must not specify
     * a subclass of that class.
     *
     * @param field             the originally accessed field.
     * @param newClass  the class declaring the substituted field.
     * @param newFieldname      the name of the substituted field.
     */
    public void redirectFieldAccess(CtField field,
                                    CtClass newClass, String newFieldname) {
        transformers = new TransformFieldAccess(transformers, field,
                                                newClass.getName(),
                                                newFieldname);
    }

    /**
     * Modify a method body so that an expression reading the specified
     * field is replaced with a call to the specified <i>static</i> method.
     * This static method receives the target object of the original
     * read expression as a parameter.  It must return a value of
     * the same type as the field.
     *
     * <p>For example, the program below
     *
     * <pre>Point p = new Point();
     * int newX = p.x + 3;</pre>
     *
     * <p>can be translated into:
     *
     * <pre>Point p = new Point();
     * int newX = Accessor.readX(p) + 3;</pre>
     *
     * <p>where
     *
     * <pre>public class Accessor {
     *     public static int readX(Object target) { ... }
     * }</pre>
     *
     * <p>The type of the parameter of <code>readX()</code> must
     * be <code>java.lang.Object</code> independently of the actual
     * type of <code>target</code>.  The return type must be the same
     * as the field type.
     *
     * @param field             the field.
     * @param calledClass       the class in which the static method is
     *                          declared.
     * @param calledMethod      the name of the static method.
     */
    public void replaceFieldRead(CtField field,
                                 CtClass calledClass, String calledMethod) {
        transformers = new TransformReadField(transformers, field,
                                              calledClass.getName(),
                                              calledMethod);
    }

    /**
     * Modify a method body so that an expression writing the specified
     * field is replaced with a call to the specified static method.
     * This static method receives two parameters: the target object of
     * the original
     * write expression and the assigned value.  The return type of the
     * static method is <code>void</code>.
     *
     * <p>For example, the program below
     *
     * <pre>Point p = new Point();
     * p.x = 3;</pre>
     *
     * <p>can be translated into:
     *
     * <pre>Point p = new Point();
     * Accessor.writeX(3);</pre>
     *
     * <p>where
     *
     * <pre>public class Accessor {
     *     public static void writeX(Object target, int value) { ... }
     * }</pre>
     *
     * <p>The type of the first parameter of <code>writeX()</code> must
     * be <code>java.lang.Object</code> independently of the actual
     * type of <code>target</code>.  The type of the second parameter
     * is the same as the field type.
     *
     * @param field             the field.
     * @param calledClass       the class in which the static method is
     *                          declared.
     * @param calledMethod      the name of the static method.
     */
    public void replaceFieldWrite(CtField field,
                                  CtClass calledClass, String calledMethod) {
        transformers = new TransformWriteField(transformers, field,
                                               calledClass.getName(),
                                               calledMethod);
    }

    /**
     * Modify a method body, so that ALL accesses to an array are replaced with 
     * calls to static methods within another class. In the case of reading an 
     * element from the array, this is replaced with a call to a static method with 
     * the array and the index as arguments, the return value is the value read from 
     * the array. If writing to an array, this is replaced with a call to a static 
     * method with the array, index and new value as parameters, the return value of 
     * the static method is <code>void</code>.
     * 
     * <p>The <code>calledClass</code> parameter is the class containing the static methods to be used 
     * for array replacement. The <code>names</code> parameter points to an implementation of 
     * <code>ArrayAccessReplacementMethodNames</code> which specifies the names of the method to be 
     * used for access for each type of array.  For example reading from an <code>int[]</code> will 
     * require a different method than if writing to an <code>int[]</code>, and writing to a <code>long[]</code> 
     * will require a different method than if writing to a <code>byte[]</code>. If the implementation 
     * of <code>ArrayAccessReplacementMethodNames</code> does not contain the name for access for a 
     * type of array, that access is not replaced.
     * 
     * <p>A default implementation of <code>ArrayAccessReplacementMethodNames</code> called 
     * <code>DefaultArrayAccessReplacementMethodNames</code> has been provided and is what is used in the 
     * following example. This also assumes that <code>'foo.ArrayAdvisor'</code> is the name of the 
     * <code>CtClass</code> passed in.
     * 
     * <p>If we have the following class:
     * <pre>class POJO{
     *    int[] ints = new int[]{1, 2, 3, 4, 5};
     *    long[] longs = new int[]{10, 20, 30};
     *    Object objects = new Object[]{true, false};
     *    Integer[] integers = new Integer[]{new Integer(10)};
     * }
     * </pre>
     * and this is accessed as:
     * <pre>POJO p = new POJO();
     * 
     * //Write to int array
     * p.ints[2] = 7;
     * 
     * //Read from int array
     * int i = p.ints[2];
     * 
     * //Write to long array
     * p.longs[2] = 1000L;
     * 
     * //Read from long array
     * long l = p.longs[2];
     * 
     * //Write to Object array
     * p.objects[2] = "Hello";
     * 
     * //Read from Object array
     * Object o = p.objects[2];
     * 
     * //Write to Integer array
     * Integer integer = new Integer(5);
     * p.integers[0] = integer;
     * 
     * //Read from Object array
     * integer = p.integers[0];
     * </pre>
     * 
     * Following instrumentation we will have
     * <pre>POJO p = new POJO();
     * 
     * //Write to int array
     * ArrayAdvisor.arrayWriteInt(p.ints, 2, 7);
     * 
     * //Read from int array
     * int i = ArrayAdvisor.arrayReadInt(p.ints, 2);
     * 
     * //Write to long array
     * ArrayAdvisor.arrayWriteLong(p.longs, 2, 1000L);
     * 
     * //Read from long array
     * long l = ArrayAdvisor.arrayReadLong(p.longs, 2);
     * 
     * //Write to Object array
     * ArrayAdvisor.arrayWriteObject(p.objects, 2, "Hello");
     * 
     * //Read from Object array
     * Object o = ArrayAdvisor.arrayReadObject(p.objects, 2);
     * 
     * //Write to Integer array
     * Integer integer = new Integer(5);
     * ArrayAdvisor.arrayWriteObject(p.integers, 0, integer);
     * 
     * //Read from Object array
     * integer = ArrayAdvisor.arrayWriteObject(p.integers, 0);
     * </pre>
     * 
     * @see DefaultArrayAccessReplacementMethodNames
     * 
     * @param calledClass        the class containing the static methods.
     * @param names              contains the names of the methods to replace
     *                           the different kinds of array access with.
     */
    public void replaceArrayAccess(CtClass calledClass, ArrayAccessReplacementMethodNames names)
        throws NotFoundException
    {
       transformers = new TransformAccessArrayField(transformers, calledClass.getName(), names);
    }

    /**
     * Modify method invocations in a method body so that a different
     * method will be invoked.
     *
     * <p>Note that the target object, the parameters, or
     * the type of invocation
     * (static method call, interface call, or private method call)
     * are not modified.  Only the method name is changed.  The substituted
     * method must have the same signature that the original one has.
     * If the original method is a static method, the substituted method
     * must be static.
     *
     * @param origMethod        original method
     * @param substMethod       substituted method
     */
    public void redirectMethodCall(CtMethod origMethod,
                                   CtMethod substMethod)
        throws CannotCompileException
    {
        String d1 = origMethod.getMethodInfo2().getDescriptor();
        String d2 = substMethod.getMethodInfo2().getDescriptor();
        if (!d1.equals(d2))
            throw new CannotCompileException("signature mismatch: "
                                             + substMethod.getLongName());

        int mod1 = origMethod.getModifiers();
        int mod2 = substMethod.getModifiers();
        if (Modifier.isStatic(mod1) != Modifier.isStatic(mod2)
            || (Modifier.isPrivate(mod1) && !Modifier.isPrivate(mod2))
            || origMethod.getDeclaringClass().isInterface()
               != substMethod.getDeclaringClass().isInterface())
            throw new CannotCompileException("invoke-type mismatch "
                                             + substMethod.getLongName());

        transformers = new TransformCall(transformers, origMethod,
                                         substMethod);
    }

    /**
     * Correct invocations to a method that has been renamed.
     * If a method is renamed, calls to that method must be also
     * modified so that the method with the new name will be called.
     *
     * <p>The method must be declared in the same class before and
     * after it is renamed.
     *
     * <p>Note that the target object, the parameters, or
     * the type of invocation
     * (static method call, interface call, or private method call)
     * are not modified.  Only the method name is changed.
     *
     * @param oldMethodName        the old name of the method.
     * @param newMethod            the method with the new name.
     * @see javassist.CtMethod#setName(String)
     */
    public void redirectMethodCall(String oldMethodName,
                                   CtMethod newMethod)
        throws CannotCompileException
    {
        transformers
            = new TransformCall(transformers, oldMethodName, newMethod);
    }

    /**
     * Insert a call to another method before an existing method call.
     * That "before" method must be static.  The return type must be
     * <code>void</code>.  As parameters, the before method receives
     * the target object and all the parameters to the originally invoked
     * method.  For example, if the originally invoked method is
     * <code>move()</code>:
     *
     * <pre>class Point {
     *     Point move(int x, int y) { ... }
     * }</pre>
     *
     * <p>Then the before method must be something like this:
     *
     * <pre>class Verbose {
     *     static void print(Point target, int x, int y) { ... }
     * }</pre>
     *
     * <p>The <code>CodeConverter</code> would translate bytecode
     * equivalent to:
     *
     * <pre>Point p2 = p.move(x + y, 0);</pre>
     *
     * <p>into the bytecode equivalent to:
     *
     * <pre>int tmp1 = x + y;
     * int tmp2 = 0;
     * Verbose.print(p, tmp1, tmp2);
     * Point p2 = p.move(tmp1, tmp2);</pre>
     *
     * @param origMethod        the method originally invoked.
     * @param beforeMethod      the method invoked before
     *                          <code>origMethod</code>.
     */
    public void insertBeforeMethod(CtMethod origMethod,
                                   CtMethod beforeMethod)
        throws CannotCompileException
    {
        try {
            transformers = new TransformBefore(transformers, origMethod,
                                               beforeMethod);
        }
        catch (NotFoundException e) {
            throw new CannotCompileException(e);
        }
    }

    /**
     * Inserts a call to another method after an existing method call.
     * That "after" method must be static.  The return type must be
     * <code>void</code>.  As parameters, the after method receives
     * the target object and all the parameters to the originally invoked
     * method.  For example, if the originally invoked method is
     * <code>move()</code>:
     *
     * <pre>class Point {
     *     Point move(int x, int y) { ... }
     * }</pre>
     *
     * <p>Then the after method must be something like this:
     *
     * <pre>class Verbose {
     *     static void print(Point target, int x, int y) { ... }
     * }</pre>
     *
     * <p>The <code>CodeConverter</code> would translate bytecode
     * equivalent to:
     *
     * <pre>Point p2 = p.move(x + y, 0);</pre>
     *
     * <p>into the bytecode equivalent to:
     *
     * <pre>
     * int tmp1 = x + y;
     * int tmp2 = 0;
     * Point p2 = p.move(tmp1, tmp2);
     * Verbose.print(p, tmp1, tmp2);</pre>
     *
     * @param origMethod        the method originally invoked.
     * @param afterMethod       the method invoked after
     *                          <code>origMethod</code>.
     */
    public void insertAfterMethod(CtMethod origMethod,
                                  CtMethod afterMethod)
        throws CannotCompileException
    {
        try {
            transformers = new TransformAfter(transformers, origMethod,
                                               afterMethod);
        }
        catch (NotFoundException e) {
            throw new CannotCompileException(e);
        }
    }

    /**
     * Performs code conversion.
     */
    protected void doit(CtClass clazz, MethodInfo minfo, ConstPool cp)
        throws CannotCompileException
    {
       Transformer t;
        CodeAttribute codeAttr = minfo.getCodeAttribute();
        if (codeAttr == null || transformers == null)
            return;
        for (t = transformers; t != null; t = t.getNext())
            t.initialize(cp, clazz, minfo);

        CodeIterator iterator = codeAttr.iterator();
        while (iterator.hasNext()) {
            try {
                int pos = iterator.next();
                for (t = transformers; t != null; t = t.getNext())
                    pos = t.transform(clazz, pos, iterator, cp);
            }
            catch (BadBytecode e) {
                throw new CannotCompileException(e);
            }
        }

        int locals = 0;
        int stack = 0;
        for (t = transformers; t != null; t = t.getNext()) {
            int s = t.extraLocals();
            if (s > locals)
                locals = s;

            s = t.extraStack();
            if (s > stack)
                stack = s;
        }

        for (t = transformers; t != null; t = t.getNext())
            t.clean();

        if (locals > 0)
            codeAttr.setMaxLocals(codeAttr.getMaxLocals() + locals);

        if (stack > 0)
            codeAttr.setMaxStack(codeAttr.getMaxStack() + stack);

        try {
        	minfo.rebuildStackMapIf6(clazz.getClassPool(),
                                     clazz.getClassFile2());
        }
        catch (BadBytecode b) {
            throw new CannotCompileException(b.getMessage(), b);
        }
    }

    /**
     * Interface containing the method names to be used
     * as array access replacements.
     *
     * @author <a href="kabir.khan@jboss.com">Kabir Khan</a>
     * @version $Revision: 1.16 $
     */
    public interface ArrayAccessReplacementMethodNames
    {
       /**
        * Returns the name of a static method with the signature
        * <code>(Ljava/lang/Object;I)B</code> to replace reading from a byte[].
        */
       String byteOrBooleanRead();

       /**
        * Returns the name of a static method with the signature
        * <code>(Ljava/lang/Object;IB)V</code> to replace writing to a byte[].
        */
       String byteOrBooleanWrite();

       /**
        * @return the name of a static method with the signature
        * <code>(Ljava/lang/Object;I)C</code> to replace reading from a char[].
        */
       String charRead();

       /**
        * Returns the name of a static method with the signature
        * <code>(Ljava/lang/Object;IC)V</code> to replace writing to a byte[].
        */
       String charWrite();

       /**
        * Returns the name of a static method with the signature
        * <code>(Ljava/lang/Object;I)D</code> to replace reading from a double[].
        */
       String doubleRead();

       /**
        * Returns the name of a static method with the signature
        * <code>(Ljava/lang/Object;ID)V</code> to replace writing to a double[].
        */
       String doubleWrite();

       /**
        * Returns the name of a static method with the signature
        * <code>(Ljava/lang/Object;I)F</code> to replace reading from a float[].
        */
       String floatRead();

       /**
        * Returns the name of a static method with the signature
        * <code>(Ljava/lang/Object;IF)V</code> to replace writing to a float[].
        */
       String floatWrite();

       /**
        * Returns the name of a static method with the signature
        * <code>(Ljava/lang/Object;I)I</code> to replace reading from a int[].
        */
       String intRead();

       /**
        * Returns the name of a static method with the signature
        * <code>(Ljava/lang/Object;II)V</code> to replace writing to a int[].
        */
       String intWrite();

       /**
        * Returns the name of a static method with the signature
        * <code>(Ljava/lang/Object;I)J</code> to replace reading from a long[].
        */
       String longRead();

       /**
        * Returns the name of a static method with the signature
        * <code>(Ljava/lang/Object;IJ)V</code> to replace writing to a long[].
        */
       String longWrite();

       /**
        * Returns the name of a static method with the signature
        * <code>(Ljava/lang/Object;I)Ljava/lang/Object;</code>
        * to replace reading from a Object[] (or any subclass of object).
        */
       String objectRead();

       /**
        * Returns the name of a static method with the signature
        * <code>(Ljava/lang/Object;ILjava/lang/Object;)V</code>
        * to replace writing to a Object[] (or any subclass of object).
        */
       String objectWrite();

       /**
        * Returns the name of a static method with the signature
        * <code>(Ljava/lang/Object;I)S</code> to replace reading from a short[].
        */
       String shortRead();

       /**
        * Returns the name of a static method with the signature
        * <code>(Ljava/lang/Object;IS)V</code> to replace writing to a short[].
        */
       String shortWrite();
    }

    /**
     * Default implementation of the <code>ArrayAccessReplacementMethodNames</code>
     * interface giving default values for method names to be used for replacing
     * accesses to array elements.
     *
     * @author <a href="kabir.khan@jboss.com">Kabir Khan</a>
     * @version $Revision: 1.16 $
     */
    public static class DefaultArrayAccessReplacementMethodNames
        implements ArrayAccessReplacementMethodNames
    {
       /**
        * Returns "arrayReadByteOrBoolean" as the name of the static method with the signature
        * (Ljava/lang/Object;I)B to replace reading from a byte[].
        */
       public String byteOrBooleanRead()
       {
          return "arrayReadByteOrBoolean";
       }

       /**
        * Returns "arrayWriteByteOrBoolean" as the name of the static method with the signature
        * (Ljava/lang/Object;IB)V  to replace writing to a byte[].
        */
       public String byteOrBooleanWrite()
       {
          return "arrayWriteByteOrBoolean";
       }

       /**
        * Returns "arrayReadChar" as the name of the static method with the signature
        * (Ljava/lang/Object;I)C  to replace reading from a char[].
        */
       public String charRead()
       {
          return "arrayReadChar";
       }

       /**
        * Returns "arrayWriteChar" as the name of the static method with the signature
        * (Ljava/lang/Object;IC)V to replace writing to a byte[].
        */
       public String charWrite()
       {
          return "arrayWriteChar";
       }

       /**
        * Returns "arrayReadDouble" as the name of the static method with the signature
        * (Ljava/lang/Object;I)D to replace reading from a double[].
        */
       public String doubleRead()
       {
          return "arrayReadDouble";
       }

       /**
        * Returns "arrayWriteDouble" as the name of the static method with the signature
        * (Ljava/lang/Object;ID)V to replace writing to a double[].
        */
       public String doubleWrite()
       {
          return "arrayWriteDouble";
       }

       /**
        * Returns "arrayReadFloat" as the name of the static method with the signature
        * (Ljava/lang/Object;I)F  to replace reading from a float[].
        */
       public String floatRead()
       {
          return "arrayReadFloat";
       }

       /**
        * Returns "arrayWriteFloat" as the name of the static method with the signature
        * (Ljava/lang/Object;IF)V  to replace writing to a float[].
        */
       public String floatWrite()
       {
          return "arrayWriteFloat";
       }

       /**
        * Returns "arrayReadInt" as the name of the static method with the signature
        * (Ljava/lang/Object;I)I to replace reading from a int[].
        */
       public String intRead()
       {
          return "arrayReadInt";
       }

       /**
        * Returns "arrayWriteInt" as the name of the static method with the signature
        * (Ljava/lang/Object;II)V to replace writing to a int[].
        */
       public String intWrite()
       {
          return "arrayWriteInt";
       }

       /**
        * Returns "arrayReadLong" as the name of the static method with the signature
        * (Ljava/lang/Object;I)J to replace reading from a long[].
        */
       public String longRead()
       {
          return "arrayReadLong";
       }

       /**
        * Returns "arrayWriteLong" as the name of the static method with the signature
        * (Ljava/lang/Object;IJ)V to replace writing to a long[].
        */
       public String longWrite()
       {
          return "arrayWriteLong";
       }

       /**
        * Returns "arrayReadObject" as the name of the static method with the signature
        * (Ljava/lang/Object;I)Ljava/lang/Object;  to replace reading from a Object[] (or any subclass of object).
        */
       public String objectRead()
       {
          return "arrayReadObject";
       }

       /**
        * Returns "arrayWriteObject" as the name of the static method with the signature
        * (Ljava/lang/Object;ILjava/lang/Object;)V  to replace writing to a Object[] (or any subclass of object).
        */
       public String objectWrite()
       {
          return "arrayWriteObject";
       }

       /**
        * Returns "arrayReadShort" as the name of the static method with the signature
        * (Ljava/lang/Object;I)S to replace reading from a short[].
        */
       public String shortRead()
       {
          return "arrayReadShort";
       }

       /**
        * Returns "arrayWriteShort" as the name of the static method with the signature
        * (Ljava/lang/Object;IS)V to replace writing to a short[].
        */
       public String shortWrite()
       {
          return "arrayWriteShort";
       }
    }
}