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 java.util.List; 20 21 import javassist.bytecode.AccessFlag; 22 import javassist.bytecode.AnnotationsAttribute; 23 import javassist.bytecode.AttributeInfo; 24 import javassist.bytecode.Bytecode; 25 import javassist.bytecode.ClassFile; 26 import javassist.bytecode.ConstPool; 27 import javassist.bytecode.Descriptor; 28 import javassist.bytecode.FieldInfo; 29 import javassist.bytecode.SignatureAttribute; 30 import javassist.compiler.CompileError; 31 import javassist.compiler.Javac; 32 import javassist.compiler.SymbolTable; 33 import javassist.compiler.ast.ASTree; 34 import javassist.compiler.ast.DoubleConst; 35 import javassist.compiler.ast.IntConst; 36 import javassist.compiler.ast.StringL; 37 38 /** 39 * An instance of CtField represents a field. 40 * 41 * @see CtClass#getDeclaredFields() 42 */ 43 public class CtField extends CtMember { 44 static final String javaLangString = "java.lang.String"; 45 46 protected FieldInfo fieldInfo; 47 48 /** 49 * Creates a <code>CtField</code> object. 50 * The created field must be added to a class 51 * with <code>CtClass.addField()</code>. 52 * An initial value of the field is specified 53 * by a <code>CtField.Initializer</code> object. 54 * 55 * <p>If getter and setter methods are needed, 56 * call <code>CtNewMethod.getter()</code> and 57 * <code>CtNewMethod.setter()</code>. 58 * 59 * @param type field type 60 * @param name field name 61 * @param declaring the class to which the field will be added. 62 * 63 * @see CtClass#addField(CtField) 64 * @see CtNewMethod#getter(String,CtField) 65 * @see CtNewMethod#setter(String,CtField) 66 * @see CtField.Initializer 67 */ CtField(CtClass type, String name, CtClass declaring)68 public CtField(CtClass type, String name, CtClass declaring) 69 throws CannotCompileException 70 { 71 this(Descriptor.of(type), name, declaring); 72 } 73 74 /** 75 * Creates a copy of the given field. 76 * The created field must be added to a class 77 * with <code>CtClass.addField()</code>. 78 * An initial value of the field is specified 79 * by a <code>CtField.Initializer</code> object. 80 * 81 * <p>If getter and setter methods are needed, 82 * call <code>CtNewMethod.getter()</code> and 83 * <code>CtNewMethod.setter()</code>. 84 * 85 * @param src the original field 86 * @param declaring the class to which the field will be added. 87 * @see CtNewMethod#getter(String,CtField) 88 * @see CtNewMethod#setter(String,CtField) 89 * @see CtField.Initializer 90 */ CtField(CtField src, CtClass declaring)91 public CtField(CtField src, CtClass declaring) 92 throws CannotCompileException 93 { 94 this(src.fieldInfo.getDescriptor(), src.fieldInfo.getName(), 95 declaring); 96 FieldInfo fi = fieldInfo; 97 fi.setAccessFlags(src.fieldInfo.getAccessFlags()); 98 ConstPool cp = fi.getConstPool(); 99 List<AttributeInfo> attributes = src.fieldInfo.getAttributes(); 100 for (AttributeInfo ainfo : attributes) 101 fi.addAttribute(ainfo.copy(cp, null)); 102 } 103 CtField(String typeDesc, String name, CtClass clazz)104 private CtField(String typeDesc, String name, CtClass clazz) 105 throws CannotCompileException 106 { 107 super(clazz); 108 ClassFile cf = clazz.getClassFile2(); 109 if (cf == null) 110 throw new CannotCompileException("bad declaring class: " 111 + clazz.getName()); 112 113 fieldInfo = new FieldInfo(cf.getConstPool(), name, typeDesc); 114 } 115 CtField(FieldInfo fi, CtClass clazz)116 CtField(FieldInfo fi, CtClass clazz) { 117 super(clazz); 118 fieldInfo = fi; 119 } 120 121 /** 122 * Returns a String representation of the object. 123 */ 124 @Override toString()125 public String toString() { 126 return getDeclaringClass().getName() + "." + getName() 127 + ":" + fieldInfo.getDescriptor(); 128 } 129 130 @Override extendToString(StringBuffer buffer)131 protected void extendToString(StringBuffer buffer) { 132 buffer.append(' '); 133 buffer.append(getName()); 134 buffer.append(' '); 135 buffer.append(fieldInfo.getDescriptor()); 136 } 137 138 /* Javac.CtFieldWithInit overrides. */ getInitAST()139 protected ASTree getInitAST() { return null; } 140 141 /* Called by CtClassType.addField(). */ getInit()142 Initializer getInit() { 143 ASTree tree = getInitAST(); 144 if (tree == null) 145 return null; 146 return Initializer.byExpr(tree); 147 } 148 149 /** 150 * Compiles the given source code and creates a field. 151 * Examples of the source code are: 152 * 153 * <pre> 154 * "public String name;" 155 * "public int k = 3;"</pre> 156 * 157 * <p>Note that the source code ends with <code>';'</code> 158 * (semicolon). 159 * 160 * @param src the source text. 161 * @param declaring the class to which the created field is added. 162 */ make(String src, CtClass declaring)163 public static CtField make(String src, CtClass declaring) 164 throws CannotCompileException 165 { 166 Javac compiler = new Javac(declaring); 167 try { 168 CtMember obj = compiler.compile(src); 169 if (obj instanceof CtField) 170 return (CtField)obj; // an instance of Javac.CtFieldWithInit 171 } 172 catch (CompileError e) { 173 throw new CannotCompileException(e); 174 } 175 176 throw new CannotCompileException("not a field"); 177 } 178 179 /** 180 * Returns the FieldInfo representing the field in the class file. 181 */ getFieldInfo()182 public FieldInfo getFieldInfo() { 183 declaringClass.checkModify(); 184 return fieldInfo; 185 } 186 187 /** 188 * Returns the FieldInfo representing the field in the class 189 * file (read only). 190 * Normal applications do not need calling this method. Use 191 * <code>getFieldInfo()</code>. 192 * 193 * <p>The <code>FieldInfo</code> object obtained by this method 194 * is read only. Changes to this object might not be reflected 195 * on a class file generated by <code>toBytecode()</code>, 196 * <code>toClass()</code>, etc in <code>CtClass</code>. 197 * 198 * <p>This method is available even if the <code>CtClass</code> 199 * containing this field is frozen. However, if the class is 200 * frozen, the <code>FieldInfo</code> might be also pruned. 201 * 202 * @see #getFieldInfo() 203 * @see CtClass#isFrozen() 204 * @see CtClass#prune() 205 */ getFieldInfo2()206 public FieldInfo getFieldInfo2() { return fieldInfo; } 207 208 /** 209 * Returns the class declaring the field. 210 */ 211 @Override getDeclaringClass()212 public CtClass getDeclaringClass() { 213 // this is redundant but for javadoc. 214 return super.getDeclaringClass(); 215 } 216 217 /** 218 * Returns the name of the field. 219 */ 220 @Override getName()221 public String getName() { 222 return fieldInfo.getName(); 223 } 224 225 /** 226 * Changes the name of the field. 227 */ setName(String newName)228 public void setName(String newName) { 229 declaringClass.checkModify(); 230 fieldInfo.setName(newName); 231 } 232 233 /** 234 * Returns the encoded modifiers of the field. 235 * 236 * @see Modifier 237 */ 238 @Override getModifiers()239 public int getModifiers() { 240 return AccessFlag.toModifier(fieldInfo.getAccessFlags()); 241 } 242 243 /** 244 * Sets the encoded modifiers of the field. 245 * 246 * @see Modifier 247 */ 248 @Override setModifiers(int mod)249 public void setModifiers(int mod) { 250 declaringClass.checkModify(); 251 fieldInfo.setAccessFlags(AccessFlag.of(mod)); 252 } 253 254 /** 255 * Returns true if the class has the specified annotation type. 256 * 257 * @param typeName the name of annotation type. 258 * @return <code>true</code> if the annotation is found, otherwise <code>false</code>. 259 * @since 3.21 260 */ 261 @Override hasAnnotation(String typeName)262 public boolean hasAnnotation(String typeName) { 263 FieldInfo fi = getFieldInfo2(); 264 AnnotationsAttribute ainfo = (AnnotationsAttribute) 265 fi.getAttribute(AnnotationsAttribute.invisibleTag); 266 AnnotationsAttribute ainfo2 = (AnnotationsAttribute) 267 fi.getAttribute(AnnotationsAttribute.visibleTag); 268 return CtClassType.hasAnnotationType(typeName, getDeclaringClass().getClassPool(), 269 ainfo, ainfo2); 270 } 271 272 /** 273 * Returns the annotation if the class has the specified annotation class. 274 * For example, if an annotation <code>@Author</code> is associated 275 * with this field, an <code>Author</code> object is returned. 276 * The member values can be obtained by calling methods on 277 * the <code>Author</code> object. 278 * 279 * @param clz the annotation class. 280 * @return the annotation if found, otherwise <code>null</code>. 281 * @since 3.11 282 */ 283 @Override getAnnotation(Class<?> clz)284 public Object getAnnotation(Class<?> clz) throws ClassNotFoundException { 285 FieldInfo fi = getFieldInfo2(); 286 AnnotationsAttribute ainfo = (AnnotationsAttribute) 287 fi.getAttribute(AnnotationsAttribute.invisibleTag); 288 AnnotationsAttribute ainfo2 = (AnnotationsAttribute) 289 fi.getAttribute(AnnotationsAttribute.visibleTag); 290 return CtClassType.getAnnotationType(clz, getDeclaringClass().getClassPool(), 291 ainfo, ainfo2); 292 } 293 294 /** 295 * Returns the annotations associated with this field. 296 * 297 * @return an array of annotation-type objects. 298 * @see #getAvailableAnnotations() 299 * @since 3.1 300 */ 301 @Override getAnnotations()302 public Object[] getAnnotations() throws ClassNotFoundException { 303 return getAnnotations(false); 304 } 305 306 /** 307 * Returns the annotations associated with this field. 308 * If any annotations are not on the classpath, they are not included 309 * in the returned array. 310 * 311 * @return an array of annotation-type objects. 312 * @see #getAnnotations() 313 * @since 3.3 314 */ 315 @Override getAvailableAnnotations()316 public Object[] getAvailableAnnotations(){ 317 try { 318 return getAnnotations(true); 319 } 320 catch (ClassNotFoundException e) { 321 throw new RuntimeException("Unexpected exception", e); 322 } 323 } 324 getAnnotations(boolean ignoreNotFound)325 private Object[] getAnnotations(boolean ignoreNotFound) throws ClassNotFoundException { 326 FieldInfo fi = getFieldInfo2(); 327 AnnotationsAttribute ainfo = (AnnotationsAttribute) 328 fi.getAttribute(AnnotationsAttribute.invisibleTag); 329 AnnotationsAttribute ainfo2 = (AnnotationsAttribute) 330 fi.getAttribute(AnnotationsAttribute.visibleTag); 331 return CtClassType.toAnnotationType(ignoreNotFound, getDeclaringClass().getClassPool(), 332 ainfo, ainfo2); 333 } 334 335 /** 336 * Returns the character string representing the type of the field. 337 * The field signature is represented by a character string 338 * called a field descriptor, which is defined in the JVM specification. 339 * If two fields have the same type, 340 * <code>getSignature()</code> returns the same string. 341 * 342 * <p>Note that the returned string is not the type signature 343 * contained in the <code>SignatureAttirbute</code>. It is 344 * a descriptor. 345 * 346 * @see javassist.bytecode.Descriptor 347 * @see #getGenericSignature() 348 */ 349 @Override getSignature()350 public String getSignature() { 351 return fieldInfo.getDescriptor(); 352 } 353 354 /** 355 * Returns the generic signature of the field. 356 * It represents a type including type variables. 357 * 358 * @see SignatureAttribute#toFieldSignature(String) 359 * @since 3.17 360 */ 361 @Override getGenericSignature()362 public String getGenericSignature() { 363 SignatureAttribute sa 364 = (SignatureAttribute)fieldInfo.getAttribute(SignatureAttribute.tag); 365 return sa == null ? null : sa.getSignature(); 366 } 367 368 /** 369 * Set the generic signature of the field. 370 * It represents a type including type variables. 371 * See {@link javassist.CtClass#setGenericSignature(String)} 372 * for a code sample. 373 * 374 * @param sig a new generic signature. 375 * @see javassist.bytecode.SignatureAttribute.ObjectType#encode() 376 * @since 3.17 377 */ 378 @Override setGenericSignature(String sig)379 public void setGenericSignature(String sig) { 380 declaringClass.checkModify(); 381 fieldInfo.addAttribute(new SignatureAttribute(fieldInfo.getConstPool(), sig)); 382 } 383 384 /** 385 * Returns the type of the field. 386 */ getType()387 public CtClass getType() throws NotFoundException { 388 return Descriptor.toCtClass(fieldInfo.getDescriptor(), 389 declaringClass.getClassPool()); 390 } 391 392 /** 393 * Sets the type of the field. 394 * 395 * <p>This method does not automatically update method bodies that access 396 * this field. They have to be explicitly updated. For example, 397 * if some method contains an expression {@code t.value} and the type 398 * of the variable {@code t} is changed by {@link #setType(CtClass)} 399 * from {@code int} to {@code double}, then {@code t.value} has to be modified 400 * as well since the bytecode of {@code t.value} contains the type information. 401 * </p> 402 * 403 * @see CodeConverter 404 * @see javassist.expr.ExprEditor 405 */ setType(CtClass clazz)406 public void setType(CtClass clazz) { 407 declaringClass.checkModify(); 408 fieldInfo.setDescriptor(Descriptor.of(clazz)); 409 } 410 411 /** 412 * Returns the value of this field if it is a constant field. 413 * This method works only if the field type is a primitive type 414 * or <code>String</code> type. Otherwise, it returns <code>null</code>. 415 * A constant field is <code>static</code> and <code>final</code>. 416 * 417 * @return a <code>Integer</code>, <code>Long</code>, <code>Float</code>, 418 * <code>Double</code>, <code>Boolean</code>, 419 * or <code>String</code> object 420 * representing the constant value. 421 * <code>null</code> if it is not a constant field 422 * or if the field type is not a primitive type 423 * or <code>String</code>. 424 */ getConstantValue()425 public Object getConstantValue() { 426 // When this method is modified, 427 // see also getConstantFieldValue() in TypeChecker. 428 429 int index = fieldInfo.getConstantValue(); 430 if (index == 0) 431 return null; 432 433 ConstPool cp = fieldInfo.getConstPool(); 434 switch (cp.getTag(index)) { 435 case ConstPool.CONST_Long : 436 return Long.valueOf(cp.getLongInfo(index)); 437 case ConstPool.CONST_Float : 438 return Float.valueOf(cp.getFloatInfo(index)); 439 case ConstPool.CONST_Double : 440 return Double.valueOf(cp.getDoubleInfo(index)); 441 case ConstPool.CONST_Integer : 442 int value = cp.getIntegerInfo(index); 443 // "Z" means boolean type. 444 if ("Z".equals(fieldInfo.getDescriptor())) 445 return Boolean.valueOf(value != 0); 446 return Integer.valueOf(value); 447 case ConstPool.CONST_String : 448 return cp.getStringInfo(index); 449 default : 450 throw new RuntimeException("bad tag: " + cp.getTag(index) 451 + " at " + index); 452 } 453 } 454 455 /** 456 * Obtains an attribute with the given name. 457 * If that attribute is not found in the class file, this 458 * method returns null. 459 * 460 * <p>Note that an attribute is a data block specified by 461 * the class file format. 462 * See {@link javassist.bytecode.AttributeInfo}. 463 * 464 * @param name attribute name 465 */ 466 @Override getAttribute(String name)467 public byte[] getAttribute(String name) { 468 AttributeInfo ai = fieldInfo.getAttribute(name); 469 if (ai == null) 470 return null; 471 return ai.get(); 472 } 473 474 /** 475 * Adds an attribute. The attribute is saved in the class file. 476 * 477 * <p>Note that an attribute is a data block specified by 478 * the class file format. 479 * See {@link javassist.bytecode.AttributeInfo}. 480 * 481 * @param name attribute name 482 * @param data attribute value 483 */ 484 @Override setAttribute(String name, byte[] data)485 public void setAttribute(String name, byte[] data) { 486 declaringClass.checkModify(); 487 fieldInfo.addAttribute(new AttributeInfo(fieldInfo.getConstPool(), 488 name, data)); 489 } 490 491 // inner classes 492 493 /** 494 * Instances of this class specify how to initialize a field. 495 * <code>Initializer</code> is passed to 496 * <code>CtClass.addField()</code> with a <code>CtField</code>. 497 * 498 * <p>This class cannot be instantiated with the <code>new</code> operator. 499 * Factory methods such as <code>byParameter()</code> and 500 * <code>byNew</code> 501 * must be used for the instantiation. They create a new instance with 502 * the given parameters and return it. 503 * 504 * @see CtClass#addField(CtField,CtField.Initializer) 505 */ 506 public static abstract class Initializer { 507 /** 508 * Makes an initializer that assigns a constant integer value. 509 * The field must be integer, short, char, or byte type. 510 */ constant(int i)511 public static Initializer constant(int i) { 512 return new IntInitializer(i); 513 } 514 515 /** 516 * Makes an initializer that assigns a constant boolean value. 517 * The field must be boolean type. 518 */ constant(boolean b)519 public static Initializer constant(boolean b) { 520 return new IntInitializer(b ? 1 : 0); 521 } 522 523 /** 524 * Makes an initializer that assigns a constant long value. 525 * The field must be long type. 526 */ constant(long l)527 public static Initializer constant(long l) { 528 return new LongInitializer(l); 529 } 530 531 /** 532 * Makes an initializer that assigns a constant float value. 533 * The field must be float type. 534 */ constant(float l)535 public static Initializer constant(float l) { 536 return new FloatInitializer(l); 537 } 538 539 /** 540 * Makes an initializer that assigns a constant double value. 541 * The field must be double type. 542 */ constant(double d)543 public static Initializer constant(double d) { 544 return new DoubleInitializer(d); 545 } 546 547 /** 548 * Makes an initializer that assigns a constant string value. 549 * The field must be <code>java.lang.String</code> type. 550 */ constant(String s)551 public static Initializer constant(String s) { 552 return new StringInitializer(s); 553 } 554 555 /** 556 * Makes an initializer using a constructor parameter. 557 * 558 * <p>The initial value is the 559 * N-th parameter given to the constructor of the object including 560 * the field. If the constructor takes less than N parameters, 561 * the field is not initialized. 562 * If the field is static, it is never initialized. 563 * 564 * @param nth the n-th (>= 0) parameter is used as 565 * the initial value. 566 * If nth is 0, then the first parameter is 567 * used. 568 */ byParameter(int nth)569 public static Initializer byParameter(int nth) { 570 ParamInitializer i = new ParamInitializer(); 571 i.nthParam = nth; 572 return i; 573 } 574 575 /** 576 * Makes an initializer creating a new object. 577 * 578 * <p>This initializer creates a new object and uses it as the initial 579 * value of the field. The constructor of the created object receives 580 * the parameter: 581 * 582 * <p><code>Object obj</code> - the object including the field. 583 * 584 * <p>If the initialized field is static, then the constructor does 585 * not receive any parameters. 586 * 587 * @param objectType the class instantiated for the initial value. 588 */ byNew(CtClass objectType)589 public static Initializer byNew(CtClass objectType) { 590 NewInitializer i = new NewInitializer(); 591 i.objectType = objectType; 592 i.stringParams = null; 593 i.withConstructorParams = false; 594 return i; 595 } 596 597 /** 598 * Makes an initializer creating a new object. 599 * 600 * <p>This initializer creates a new object and uses it as the initial 601 * value of the field. The constructor of the created object receives 602 * the parameters: 603 * 604 * <p><code>Object obj</code> - the object including the field.<br> 605 * <code>String[] strs</code> - the character strings specified 606 * by <code>stringParams</code><br> 607 * 608 * <p>If the initialized field is static, then the constructor 609 * receives only <code>strs</code>. 610 * 611 * @param objectType the class instantiated for the initial value. 612 * @param stringParams the array of strings passed to the 613 * constructor. 614 */ byNew(CtClass objectType, String[] stringParams)615 public static Initializer byNew(CtClass objectType, 616 String[] stringParams) { 617 NewInitializer i = new NewInitializer(); 618 i.objectType = objectType; 619 i.stringParams = stringParams; 620 i.withConstructorParams = false; 621 return i; 622 } 623 624 /** 625 * Makes an initializer creating a new object. 626 * 627 * <p>This initializer creates a new object and uses it as the initial 628 * value of the field. The constructor of the created object receives 629 * the parameters: 630 * 631 * <p><code>Object obj</code> - the object including the field.<br> 632 * <code>Object[] args</code> - the parameters passed to the 633 * constructor of the object including the 634 * filed. 635 * 636 * <p>If the initialized field is static, then the constructor does 637 * not receive any parameters. 638 * 639 * @param objectType the class instantiated for the initial value. 640 * 641 * @see javassist.CtField.Initializer#byNewArray(CtClass,int) 642 * @see javassist.CtField.Initializer#byNewArray(CtClass,int[]) 643 */ byNewWithParams(CtClass objectType)644 public static Initializer byNewWithParams(CtClass objectType) { 645 NewInitializer i = new NewInitializer(); 646 i.objectType = objectType; 647 i.stringParams = null; 648 i.withConstructorParams = true; 649 return i; 650 } 651 652 /** 653 * Makes an initializer creating a new object. 654 * 655 * <p>This initializer creates a new object and uses it as the initial 656 * value of the field. The constructor of the created object receives 657 * the parameters: 658 * 659 * <p><code>Object obj</code> - the object including the field.<br> 660 * <code>String[] strs</code> - the character strings specified 661 * by <code>stringParams</code><br> 662 * <code>Object[] args</code> - the parameters passed to the 663 * constructor of the object including the 664 * filed. 665 * 666 * <p>If the initialized field is static, then the constructor receives 667 * only <code>strs</code>. 668 * 669 * @param objectType the class instantiated for the initial value. 670 * @param stringParams the array of strings passed to the 671 * constructor. 672 */ byNewWithParams(CtClass objectType, String[] stringParams)673 public static Initializer byNewWithParams(CtClass objectType, 674 String[] stringParams) { 675 NewInitializer i = new NewInitializer(); 676 i.objectType = objectType; 677 i.stringParams = stringParams; 678 i.withConstructorParams = true; 679 return i; 680 } 681 682 /** 683 * Makes an initializer calling a static method. 684 * 685 * <p>This initializer calls a static method and uses the returned 686 * value as the initial value of the field. 687 * The called method receives the parameters: 688 * 689 * <p><code>Object obj</code> - the object including the field. 690 * 691 * <p>If the initialized field is static, then the method does 692 * not receive any parameters. 693 * 694 * <p>The type of the returned value must be the same as the field 695 * type. 696 * 697 * @param methodClass the class that the static method is 698 * declared in. 699 * @param methodName the name of the satic method. 700 */ byCall(CtClass methodClass, String methodName)701 public static Initializer byCall(CtClass methodClass, 702 String methodName) { 703 MethodInitializer i = new MethodInitializer(); 704 i.objectType = methodClass; 705 i.methodName = methodName; 706 i.stringParams = null; 707 i.withConstructorParams = false; 708 return i; 709 } 710 711 /** 712 * Makes an initializer calling a static method. 713 * 714 * <p>This initializer calls a static method and uses the returned 715 * value as the initial value of the field. The called method 716 * receives the parameters: 717 * 718 * <p><code>Object obj</code> - the object including the field.<br> 719 * <code>String[] strs</code> - the character strings specified 720 * by <code>stringParams</code><br> 721 * 722 * <p>If the initialized field is static, then the method 723 * receive only <code>strs</code>. 724 * 725 * <p>The type of the returned value must be the same as the field 726 * type. 727 * 728 * @param methodClass the class that the static method is 729 * declared in. 730 * @param methodName the name of the satic method. 731 * @param stringParams the array of strings passed to the 732 * static method. 733 */ byCall(CtClass methodClass, String methodName, String[] stringParams)734 public static Initializer byCall(CtClass methodClass, 735 String methodName, 736 String[] stringParams) { 737 MethodInitializer i = new MethodInitializer(); 738 i.objectType = methodClass; 739 i.methodName = methodName; 740 i.stringParams = stringParams; 741 i.withConstructorParams = false; 742 return i; 743 } 744 745 /** 746 * Makes an initializer calling a static method. 747 * 748 * <p>This initializer calls a static method and uses the returned 749 * value as the initial value of the field. The called method 750 * receives the parameters: 751 * 752 * <p><code>Object obj</code> - the object including the field.<br> 753 * <code>Object[] args</code> - the parameters passed to the 754 * constructor of the object including the 755 * filed. 756 * 757 * <p>If the initialized field is static, then the method does 758 * not receive any parameters. 759 * 760 * <p>The type of the returned value must be the same as the field 761 * type. 762 * 763 * @param methodClass the class that the static method is 764 * declared in. 765 * @param methodName the name of the satic method. 766 */ byCallWithParams(CtClass methodClass, String methodName)767 public static Initializer byCallWithParams(CtClass methodClass, 768 String methodName) { 769 MethodInitializer i = new MethodInitializer(); 770 i.objectType = methodClass; 771 i.methodName = methodName; 772 i.stringParams = null; 773 i.withConstructorParams = true; 774 return i; 775 } 776 777 /** 778 * Makes an initializer calling a static method. 779 * 780 * <p>This initializer calls a static method and uses the returned 781 * value as the initial value of the field. The called method 782 * receives the parameters: 783 * 784 * <p><code>Object obj</code> - the object including the field.<br> 785 * <code>String[] strs</code> - the character strings specified 786 * by <code>stringParams</code><br> 787 * <code>Object[] args</code> - the parameters passed to the 788 * constructor of the object including the 789 * filed. 790 * 791 * <p>If the initialized field is static, then the method 792 * receive only <code>strs</code>. 793 * 794 * <p>The type of the returned value must be the same as the field 795 * type. 796 * 797 * @param methodClass the class that the static method is 798 * declared in. 799 * @param methodName the name of the satic method. 800 * @param stringParams the array of strings passed to the 801 * static method. 802 */ byCallWithParams(CtClass methodClass, String methodName, String[] stringParams)803 public static Initializer byCallWithParams(CtClass methodClass, 804 String methodName, String[] stringParams) { 805 MethodInitializer i = new MethodInitializer(); 806 i.objectType = methodClass; 807 i.methodName = methodName; 808 i.stringParams = stringParams; 809 i.withConstructorParams = true; 810 return i; 811 } 812 813 /** 814 * Makes an initializer creating a new array. 815 * 816 * @param type the type of the array. 817 * @param size the size of the array. 818 * @throws NotFoundException if the type of the array components 819 * is not found. 820 */ byNewArray(CtClass type, int size)821 public static Initializer byNewArray(CtClass type, int size) 822 throws NotFoundException 823 { 824 return new ArrayInitializer(type.getComponentType(), size); 825 } 826 827 /** 828 * Makes an initializer creating a new multi-dimensional array. 829 * 830 * @param type the type of the array. 831 * @param sizes an <code>int</code> array of the size in every 832 * dimension. 833 * The first element is the size in the first 834 * dimension. The second is in the second, etc. 835 */ byNewArray(CtClass type, int[] sizes)836 public static Initializer byNewArray(CtClass type, int[] sizes) { 837 return new MultiArrayInitializer(type, sizes); 838 } 839 840 /** 841 * Makes an initializer. 842 * 843 * @param source initializer expression. 844 */ byExpr(String source)845 public static Initializer byExpr(String source) { 846 return new CodeInitializer(source); 847 } 848 byExpr(ASTree source)849 static Initializer byExpr(ASTree source) { 850 return new PtreeInitializer(source); 851 } 852 853 // Check whether this initializer is valid for the field type. 854 // If it is invaild, this method throws an exception. check(String desc)855 void check(String desc) throws CannotCompileException {} 856 857 // produce codes for initialization compile(CtClass type, String name, Bytecode code, CtClass[] parameters, Javac drv)858 abstract int compile(CtClass type, String name, Bytecode code, 859 CtClass[] parameters, Javac drv) 860 throws CannotCompileException; 861 862 // produce codes for initialization compileIfStatic(CtClass type, String name, Bytecode code, Javac drv)863 abstract int compileIfStatic(CtClass type, String name, 864 Bytecode code, Javac drv) throws CannotCompileException; 865 866 // returns the index of CONSTANT_Integer_info etc 867 // if the value is constant. Otherwise, 0. getConstantValue(ConstPool cp, CtClass type)868 int getConstantValue(ConstPool cp, CtClass type) { return 0; } 869 } 870 871 static abstract class CodeInitializer0 extends Initializer { compileExpr(Javac drv)872 abstract void compileExpr(Javac drv) throws CompileError; 873 874 @Override compile(CtClass type, String name, Bytecode code, CtClass[] parameters, Javac drv)875 int compile(CtClass type, String name, Bytecode code, 876 CtClass[] parameters, Javac drv) 877 throws CannotCompileException 878 { 879 try { 880 code.addAload(0); 881 compileExpr(drv); 882 code.addPutfield(Bytecode.THIS, name, Descriptor.of(type)); 883 return code.getMaxStack(); 884 } 885 catch (CompileError e) { 886 throw new CannotCompileException(e); 887 } 888 } 889 890 @Override compileIfStatic(CtClass type, String name, Bytecode code, Javac drv)891 int compileIfStatic(CtClass type, String name, Bytecode code, 892 Javac drv) throws CannotCompileException 893 { 894 try { 895 compileExpr(drv); 896 code.addPutstatic(Bytecode.THIS, name, Descriptor.of(type)); 897 return code.getMaxStack(); 898 } 899 catch (CompileError e) { 900 throw new CannotCompileException(e); 901 } 902 } 903 getConstantValue2(ConstPool cp, CtClass type, ASTree tree)904 int getConstantValue2(ConstPool cp, CtClass type, ASTree tree) { 905 if (type.isPrimitive()) { 906 if (tree instanceof IntConst) { 907 long value = ((IntConst)tree).get(); 908 if (type == CtClass.doubleType) 909 return cp.addDoubleInfo(value); 910 else if (type == CtClass.floatType) 911 return cp.addFloatInfo(value); 912 else if (type == CtClass.longType) 913 return cp.addLongInfo(value); 914 else if (type != CtClass.voidType) 915 return cp.addIntegerInfo((int)value); 916 } 917 else if (tree instanceof DoubleConst) { 918 double value = ((DoubleConst)tree).get(); 919 if (type == CtClass.floatType) 920 return cp.addFloatInfo((float)value); 921 else if (type == CtClass.doubleType) 922 return cp.addDoubleInfo(value); 923 } 924 } 925 else if (tree instanceof StringL 926 && type.getName().equals(javaLangString)) 927 return cp.addStringInfo(((StringL)tree).get()); 928 929 return 0; 930 } 931 } 932 933 static class CodeInitializer extends CodeInitializer0 { 934 private String expression; 935 CodeInitializer(String expr)936 CodeInitializer(String expr) { expression = expr; } 937 938 @Override compileExpr(Javac drv)939 void compileExpr(Javac drv) throws CompileError { 940 drv.compileExpr(expression); 941 } 942 943 @Override getConstantValue(ConstPool cp, CtClass type)944 int getConstantValue(ConstPool cp, CtClass type) { 945 try { 946 ASTree t = Javac.parseExpr(expression, new SymbolTable()); 947 return getConstantValue2(cp, type, t); 948 } 949 catch (CompileError e) { 950 return 0; 951 } 952 } 953 } 954 955 static class PtreeInitializer extends CodeInitializer0 { 956 private ASTree expression; 957 PtreeInitializer(ASTree expr)958 PtreeInitializer(ASTree expr) { expression = expr; } 959 960 @Override compileExpr(Javac drv)961 void compileExpr(Javac drv) throws CompileError { 962 drv.compileExpr(expression); 963 } 964 965 @Override getConstantValue(ConstPool cp, CtClass type)966 int getConstantValue(ConstPool cp, CtClass type) { 967 return getConstantValue2(cp, type, expression); 968 } 969 } 970 971 /** 972 * A field initialized with a parameter passed to the constructor 973 * of the class containing that field. 974 */ 975 static class ParamInitializer extends Initializer { 976 int nthParam; 977 ParamInitializer()978 ParamInitializer() {} 979 980 @Override compile(CtClass type, String name, Bytecode code, CtClass[] parameters, Javac drv)981 int compile(CtClass type, String name, Bytecode code, 982 CtClass[] parameters, Javac drv) 983 throws CannotCompileException 984 { 985 if (parameters != null && nthParam < parameters.length) { 986 code.addAload(0); 987 int nth = nthParamToLocal(nthParam, parameters, false); 988 int s = code.addLoad(nth, type) + 1; 989 code.addPutfield(Bytecode.THIS, name, Descriptor.of(type)); 990 return s; // stack size 991 } 992 return 0; // do not initialize 993 } 994 995 /** 996 * Computes the index of the local variable that the n-th parameter 997 * is assigned to. 998 * 999 * @param nth n-th parameter 1000 * @param params list of parameter types 1001 * @param isStatic true if the method is static. 1002 */ nthParamToLocal(int nth, CtClass[] params, boolean isStatic)1003 static int nthParamToLocal(int nth, CtClass[] params, 1004 boolean isStatic) { 1005 CtClass longType = CtClass.longType; 1006 CtClass doubleType = CtClass.doubleType; 1007 int k; 1008 if (isStatic) 1009 k = 0; 1010 else 1011 k = 1; // 0 is THIS. 1012 1013 for (int i = 0; i < nth; ++i) { 1014 CtClass type = params[i]; 1015 if (type == longType || type == doubleType) 1016 k += 2; 1017 else 1018 ++k; 1019 } 1020 1021 return k; 1022 } 1023 1024 @Override compileIfStatic(CtClass type, String name, Bytecode code, Javac drv)1025 int compileIfStatic(CtClass type, String name, Bytecode code, 1026 Javac drv) throws CannotCompileException 1027 { 1028 return 0; 1029 } 1030 } 1031 1032 /** 1033 * A field initialized with an object created by the new operator. 1034 */ 1035 static class NewInitializer extends Initializer { 1036 CtClass objectType; 1037 String[] stringParams; 1038 boolean withConstructorParams; 1039 NewInitializer()1040 NewInitializer() {} 1041 1042 /** 1043 * Produces codes in which a new object is created and assigned to 1044 * the field as the initial value. 1045 */ 1046 @Override compile(CtClass type, String name, Bytecode code, CtClass[] parameters, Javac drv)1047 int compile(CtClass type, String name, Bytecode code, 1048 CtClass[] parameters, Javac drv) 1049 throws CannotCompileException 1050 { 1051 int stacksize; 1052 1053 code.addAload(0); 1054 code.addNew(objectType); 1055 code.add(Bytecode.DUP); 1056 code.addAload(0); 1057 1058 if (stringParams == null) 1059 stacksize = 4; 1060 else 1061 stacksize = compileStringParameter(code) + 4; 1062 1063 if (withConstructorParams) 1064 stacksize += CtNewWrappedMethod.compileParameterList(code, 1065 parameters, 1); 1066 1067 code.addInvokespecial(objectType, "<init>", getDescriptor()); 1068 code.addPutfield(Bytecode.THIS, name, Descriptor.of(type)); 1069 return stacksize; 1070 } 1071 getDescriptor()1072 private String getDescriptor() { 1073 final String desc3 1074 = "(Ljava/lang/Object;[Ljava/lang/String;[Ljava/lang/Object;)V"; 1075 1076 if (stringParams == null) 1077 if (withConstructorParams) 1078 return "(Ljava/lang/Object;[Ljava/lang/Object;)V"; 1079 else 1080 return "(Ljava/lang/Object;)V"; 1081 1082 if (withConstructorParams) 1083 return desc3; 1084 1085 return "(Ljava/lang/Object;[Ljava/lang/String;)V"; 1086 } 1087 1088 /** 1089 * Produces codes for a static field. 1090 */ 1091 @Override compileIfStatic(CtClass type, String name, Bytecode code, Javac drv)1092 int compileIfStatic(CtClass type, String name, Bytecode code, 1093 Javac drv) throws CannotCompileException 1094 { 1095 String desc; 1096 1097 code.addNew(objectType); 1098 code.add(Bytecode.DUP); 1099 1100 int stacksize = 2; 1101 if (stringParams == null) 1102 desc = "()V"; 1103 else { 1104 desc = "([Ljava/lang/String;)V"; 1105 stacksize += compileStringParameter(code); 1106 } 1107 1108 code.addInvokespecial(objectType, "<init>", desc); 1109 code.addPutstatic(Bytecode.THIS, name, Descriptor.of(type)); 1110 return stacksize; 1111 } 1112 compileStringParameter(Bytecode code)1113 protected final int compileStringParameter(Bytecode code) 1114 throws CannotCompileException 1115 { 1116 int nparam = stringParams.length; 1117 code.addIconst(nparam); 1118 code.addAnewarray(javaLangString); 1119 for (int j = 0; j < nparam; ++j) { 1120 code.add(Bytecode.DUP); // dup 1121 code.addIconst(j); // iconst_<j> 1122 code.addLdc(stringParams[j]); // ldc ... 1123 code.add(Bytecode.AASTORE); // aastore 1124 } 1125 1126 return 4; 1127 } 1128 1129 } 1130 1131 /** 1132 * A field initialized with the result of a static method call. 1133 */ 1134 static class MethodInitializer extends NewInitializer { 1135 String methodName; 1136 // the method class is specified by objectType. 1137 MethodInitializer()1138 MethodInitializer() {} 1139 1140 /** 1141 * Produces codes in which a new object is created and assigned to 1142 * the field as the initial value. 1143 */ 1144 @Override compile(CtClass type, String name, Bytecode code, CtClass[] parameters, Javac drv)1145 int compile(CtClass type, String name, Bytecode code, 1146 CtClass[] parameters, Javac drv) 1147 throws CannotCompileException 1148 { 1149 int stacksize; 1150 1151 code.addAload(0); 1152 code.addAload(0); 1153 1154 if (stringParams == null) 1155 stacksize = 2; 1156 else 1157 stacksize = compileStringParameter(code) + 2; 1158 1159 if (withConstructorParams) 1160 stacksize += CtNewWrappedMethod.compileParameterList(code, 1161 parameters, 1); 1162 1163 String typeDesc = Descriptor.of(type); 1164 String mDesc = getDescriptor() + typeDesc; 1165 code.addInvokestatic(objectType, methodName, mDesc); 1166 code.addPutfield(Bytecode.THIS, name, typeDesc); 1167 return stacksize; 1168 } 1169 getDescriptor()1170 private String getDescriptor() { 1171 final String desc3 1172 = "(Ljava/lang/Object;[Ljava/lang/String;[Ljava/lang/Object;)"; 1173 1174 if (stringParams == null) 1175 if (withConstructorParams) 1176 return "(Ljava/lang/Object;[Ljava/lang/Object;)"; 1177 else 1178 return "(Ljava/lang/Object;)"; 1179 1180 if (withConstructorParams) 1181 return desc3; 1182 1183 return "(Ljava/lang/Object;[Ljava/lang/String;)"; 1184 } 1185 1186 /** 1187 * Produces codes for a static field. 1188 */ 1189 @Override compileIfStatic(CtClass type, String name, Bytecode code, Javac drv)1190 int compileIfStatic(CtClass type, String name, Bytecode code, 1191 Javac drv) throws CannotCompileException 1192 { 1193 String desc; 1194 1195 int stacksize = 1; 1196 if (stringParams == null) 1197 desc = "()"; 1198 else { 1199 desc = "([Ljava/lang/String;)"; 1200 stacksize += compileStringParameter(code); 1201 } 1202 1203 String typeDesc = Descriptor.of(type); 1204 code.addInvokestatic(objectType, methodName, desc + typeDesc); 1205 code.addPutstatic(Bytecode.THIS, name, typeDesc); 1206 return stacksize; 1207 } 1208 } 1209 1210 static class IntInitializer extends Initializer { 1211 int value; 1212 IntInitializer(int v)1213 IntInitializer(int v) { value = v; } 1214 1215 @Override check(String desc)1216 void check(String desc) throws CannotCompileException { 1217 char c = desc.charAt(0); 1218 if (c != 'I' && c != 'S' && c != 'B' && c != 'C' && c != 'Z') 1219 throw new CannotCompileException("type mismatch"); 1220 } 1221 1222 @Override compile(CtClass type, String name, Bytecode code, CtClass[] parameters, Javac drv)1223 int compile(CtClass type, String name, Bytecode code, 1224 CtClass[] parameters, Javac drv) 1225 throws CannotCompileException 1226 { 1227 code.addAload(0); 1228 code.addIconst(value); 1229 code.addPutfield(Bytecode.THIS, name, Descriptor.of(type)); 1230 return 2; // stack size 1231 } 1232 1233 @Override compileIfStatic(CtClass type, String name, Bytecode code, Javac drv)1234 int compileIfStatic(CtClass type, String name, Bytecode code, 1235 Javac drv) throws CannotCompileException 1236 { 1237 code.addIconst(value); 1238 code.addPutstatic(Bytecode.THIS, name, Descriptor.of(type)); 1239 return 1; // stack size 1240 } 1241 1242 @Override getConstantValue(ConstPool cp, CtClass type)1243 int getConstantValue(ConstPool cp, CtClass type) { 1244 return cp.addIntegerInfo(value); 1245 } 1246 } 1247 1248 static class LongInitializer extends Initializer { 1249 long value; 1250 LongInitializer(long v)1251 LongInitializer(long v) { value = v; } 1252 1253 @Override check(String desc)1254 void check(String desc) throws CannotCompileException { 1255 if (!desc.equals("J")) 1256 throw new CannotCompileException("type mismatch"); 1257 } 1258 1259 @Override compile(CtClass type, String name, Bytecode code, CtClass[] parameters, Javac drv)1260 int compile(CtClass type, String name, Bytecode code, 1261 CtClass[] parameters, Javac drv) 1262 throws CannotCompileException 1263 { 1264 code.addAload(0); 1265 code.addLdc2w(value); 1266 code.addPutfield(Bytecode.THIS, name, Descriptor.of(type)); 1267 return 3; // stack size 1268 } 1269 1270 @Override compileIfStatic(CtClass type, String name, Bytecode code, Javac drv)1271 int compileIfStatic(CtClass type, String name, Bytecode code, 1272 Javac drv) throws CannotCompileException 1273 { 1274 code.addLdc2w(value); 1275 code.addPutstatic(Bytecode.THIS, name, Descriptor.of(type)); 1276 return 2; // stack size 1277 } 1278 1279 @Override getConstantValue(ConstPool cp, CtClass type)1280 int getConstantValue(ConstPool cp, CtClass type) { 1281 if (type == CtClass.longType) 1282 return cp.addLongInfo(value); 1283 return 0; 1284 } 1285 } 1286 1287 static class FloatInitializer extends Initializer { 1288 float value; 1289 FloatInitializer(float v)1290 FloatInitializer(float v) { value = v; } 1291 1292 @Override check(String desc)1293 void check(String desc) throws CannotCompileException { 1294 if (!desc.equals("F")) 1295 throw new CannotCompileException("type mismatch"); 1296 } 1297 1298 @Override compile(CtClass type, String name, Bytecode code, CtClass[] parameters, Javac drv)1299 int compile(CtClass type, String name, Bytecode code, 1300 CtClass[] parameters, Javac drv) 1301 throws CannotCompileException 1302 { 1303 code.addAload(0); 1304 code.addFconst(value); 1305 code.addPutfield(Bytecode.THIS, name, Descriptor.of(type)); 1306 return 3; // stack size 1307 } 1308 1309 @Override compileIfStatic(CtClass type, String name, Bytecode code, Javac drv)1310 int compileIfStatic(CtClass type, String name, Bytecode code, 1311 Javac drv) throws CannotCompileException 1312 { 1313 code.addFconst(value); 1314 code.addPutstatic(Bytecode.THIS, name, Descriptor.of(type)); 1315 return 2; // stack size 1316 } 1317 1318 @Override getConstantValue(ConstPool cp, CtClass type)1319 int getConstantValue(ConstPool cp, CtClass type) { 1320 if (type == CtClass.floatType) 1321 return cp.addFloatInfo(value); 1322 return 0; 1323 } 1324 } 1325 1326 static class DoubleInitializer extends Initializer { 1327 double value; 1328 DoubleInitializer(double v)1329 DoubleInitializer(double v) { value = v; } 1330 1331 @Override check(String desc)1332 void check(String desc) throws CannotCompileException { 1333 if (!desc.equals("D")) 1334 throw new CannotCompileException("type mismatch"); 1335 } 1336 1337 @Override compile(CtClass type, String name, Bytecode code, CtClass[] parameters, Javac drv)1338 int compile(CtClass type, String name, Bytecode code, 1339 CtClass[] parameters, Javac drv) 1340 throws CannotCompileException 1341 { 1342 code.addAload(0); 1343 code.addLdc2w(value); 1344 code.addPutfield(Bytecode.THIS, name, Descriptor.of(type)); 1345 return 3; // stack size 1346 } 1347 1348 @Override compileIfStatic(CtClass type, String name, Bytecode code, Javac drv)1349 int compileIfStatic(CtClass type, String name, Bytecode code, 1350 Javac drv) throws CannotCompileException 1351 { 1352 code.addLdc2w(value); 1353 code.addPutstatic(Bytecode.THIS, name, Descriptor.of(type)); 1354 return 2; // stack size 1355 } 1356 1357 @Override getConstantValue(ConstPool cp, CtClass type)1358 int getConstantValue(ConstPool cp, CtClass type) { 1359 if (type == CtClass.doubleType) 1360 return cp.addDoubleInfo(value); 1361 return 0; 1362 } 1363 } 1364 1365 static class StringInitializer extends Initializer { 1366 String value; 1367 StringInitializer(String v)1368 StringInitializer(String v) { value = v; } 1369 1370 @Override compile(CtClass type, String name, Bytecode code, CtClass[] parameters, Javac drv)1371 int compile(CtClass type, String name, Bytecode code, 1372 CtClass[] parameters, Javac drv) 1373 throws CannotCompileException 1374 { 1375 code.addAload(0); 1376 code.addLdc(value); 1377 code.addPutfield(Bytecode.THIS, name, Descriptor.of(type)); 1378 return 2; // stack size 1379 } 1380 1381 @Override compileIfStatic(CtClass type, String name, Bytecode code, Javac drv)1382 int compileIfStatic(CtClass type, String name, Bytecode code, 1383 Javac drv) throws CannotCompileException 1384 { 1385 code.addLdc(value); 1386 code.addPutstatic(Bytecode.THIS, name, Descriptor.of(type)); 1387 return 1; // stack size 1388 } 1389 1390 @Override getConstantValue(ConstPool cp, CtClass type)1391 int getConstantValue(ConstPool cp, CtClass type) { 1392 if (type.getName().equals(javaLangString)) 1393 return cp.addStringInfo(value); 1394 return 0; 1395 } 1396 } 1397 1398 static class ArrayInitializer extends Initializer { 1399 CtClass type; 1400 int size; 1401 ArrayInitializer(CtClass t, int s)1402 ArrayInitializer(CtClass t, int s) { type = t; size = s; } 1403 addNewarray(Bytecode code)1404 private void addNewarray(Bytecode code) { 1405 if (type.isPrimitive()) 1406 code.addNewarray(((CtPrimitiveType)type).getArrayType(), 1407 size); 1408 else 1409 code.addAnewarray(type, size); 1410 } 1411 1412 @Override compile(CtClass type, String name, Bytecode code, CtClass[] parameters, Javac drv)1413 int compile(CtClass type, String name, Bytecode code, 1414 CtClass[] parameters, Javac drv) 1415 throws CannotCompileException 1416 { 1417 code.addAload(0); 1418 addNewarray(code); 1419 code.addPutfield(Bytecode.THIS, name, Descriptor.of(type)); 1420 return 2; // stack size 1421 } 1422 1423 @Override compileIfStatic(CtClass type, String name, Bytecode code, Javac drv)1424 int compileIfStatic(CtClass type, String name, Bytecode code, 1425 Javac drv) throws CannotCompileException 1426 { 1427 addNewarray(code); 1428 code.addPutstatic(Bytecode.THIS, name, Descriptor.of(type)); 1429 return 1; // stack size 1430 } 1431 } 1432 1433 static class MultiArrayInitializer extends Initializer { 1434 CtClass type; 1435 int[] dim; 1436 MultiArrayInitializer(CtClass t, int[] d)1437 MultiArrayInitializer(CtClass t, int[] d) { type = t; dim = d; } 1438 1439 @Override check(String desc)1440 void check(String desc) throws CannotCompileException { 1441 if (desc.charAt(0) != '[') 1442 throw new CannotCompileException("type mismatch"); 1443 } 1444 1445 @Override compile(CtClass type, String name, Bytecode code, CtClass[] parameters, Javac drv)1446 int compile(CtClass type, String name, Bytecode code, 1447 CtClass[] parameters, Javac drv) 1448 throws CannotCompileException 1449 { 1450 code.addAload(0); 1451 int s = code.addMultiNewarray(type, dim); 1452 code.addPutfield(Bytecode.THIS, name, Descriptor.of(type)); 1453 return s + 1; // stack size 1454 } 1455 1456 @Override compileIfStatic(CtClass type, String name, Bytecode code, Javac drv)1457 int compileIfStatic(CtClass type, String name, Bytecode code, 1458 Javac drv) throws CannotCompileException 1459 { 1460 int s = code.addMultiNewarray(type, dim); 1461 code.addPutstatic(Bytecode.THIS, name, Descriptor.of(type)); 1462 return s; // stack size 1463 } 1464 } 1465 } 1466