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