0001: /*
0002: * Javassist, a Java-bytecode translator toolkit.
0003: * Copyright (C) 1999-2006 Shigeru Chiba. All Rights Reserved.
0004: *
0005: * The contents of this file are subject to the Mozilla Public License Version
0006: * 1.1 (the "License"); you may not use this file except in compliance with
0007: * the License. Alternatively, the contents of this file may be used under
0008: * the terms of the GNU Lesser General Public License Version 2.1 or later.
0009: *
0010: * Software distributed under the License is distributed on an "AS IS" basis,
0011: * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
0012: * for the specific language governing rights and limitations under the
0013: * License.
0014: */
0015:
0016: package javassist;
0017:
0018: import javassist.bytecode.*;
0019: import javassist.compiler.Javac;
0020: import javassist.compiler.SymbolTable;
0021: import javassist.compiler.CompileError;
0022: import javassist.compiler.ast.ASTree;
0023: import javassist.compiler.ast.IntConst;
0024: import javassist.compiler.ast.DoubleConst;
0025: import javassist.compiler.ast.StringL;
0026:
0027: /**
0028: * An instance of CtField represents a field.
0029: *
0030: * @see CtClass#getDeclaredFields()
0031: */
0032: public class CtField extends CtMember {
0033: static final String javaLangString = "java.lang.String";
0034:
0035: protected FieldInfo fieldInfo;
0036:
0037: /**
0038: * Creates a <code>CtField</code> object.
0039: * The created field must be added to a class
0040: * with <code>CtClass.addField()</code>.
0041: * An initial value of the field is specified
0042: * by a <code>CtField.Initializer</code> object.
0043: *
0044: * <p>If getter and setter methods are needed,
0045: * call <code>CtNewMethod.getter()</code> and
0046: * <code>CtNewMethod.setter()</code>.
0047: *
0048: * @param type field type
0049: * @param name field name
0050: * @param declaring the class to which the field will be added.
0051: *
0052: * @see CtClass#addField(CtField)
0053: * @see CtNewMethod#getter(String,CtField)
0054: * @see CtNewMethod#setter(String,CtField)
0055: * @see CtField.Initializer
0056: */
0057: public CtField(CtClass type, String name, CtClass declaring)
0058: throws CannotCompileException {
0059: this (Descriptor.of(type), name, declaring);
0060: }
0061:
0062: /**
0063: * Creates a copy of the given field.
0064: * The created field must be added to a class
0065: * with <code>CtClass.addField()</code>.
0066: * An initial value of the field is specified
0067: * by a <code>CtField.Initializer</code> object.
0068: *
0069: * <p>If getter and setter methods are needed,
0070: * call <code>CtNewMethod.getter()</code> and
0071: * <code>CtNewMethod.setter()</code>.
0072: *
0073: * @param src the original field
0074: * @param declaring the class to which the field will be added.
0075: * @see CtNewMethod#getter(String,CtField)
0076: * @see CtNewMethod#setter(String,CtField)
0077: * @see CtField.Initializer
0078: */
0079: public CtField(CtField src, CtClass declaring)
0080: throws CannotCompileException {
0081: this (src.fieldInfo.getDescriptor(), src.fieldInfo.getName(),
0082: declaring);
0083: java.util.ListIterator iterator = src.fieldInfo.getAttributes()
0084: .listIterator();
0085: FieldInfo fi = fieldInfo;
0086: fi.setAccessFlags(src.fieldInfo.getAccessFlags());
0087: ConstPool cp = fi.getConstPool();
0088: while (iterator.hasNext()) {
0089: AttributeInfo ainfo = (AttributeInfo) iterator.next();
0090: fi.addAttribute(ainfo.copy(cp, null));
0091: }
0092: }
0093:
0094: private CtField(String typeDesc, String name, CtClass clazz)
0095: throws CannotCompileException {
0096: super (clazz);
0097: next = null;
0098: ClassFile cf = clazz.getClassFile2();
0099: if (cf == null)
0100: throw new CannotCompileException("bad declaring class: "
0101: + clazz.getName());
0102:
0103: fieldInfo = new FieldInfo(cf.getConstPool(), name, typeDesc);
0104: }
0105:
0106: CtField(FieldInfo fi, CtClass clazz) {
0107: super (clazz);
0108: fieldInfo = fi;
0109: next = null;
0110: }
0111:
0112: /**
0113: * Returns a String representation of the object.
0114: */
0115: public String toString() {
0116: return getDeclaringClass().getName() + "." + getName() + ":"
0117: + fieldInfo.getDescriptor();
0118: }
0119:
0120: protected void extendToString(StringBuffer buffer) {
0121: buffer.append(' ');
0122: buffer.append(getName());
0123: buffer.append(' ');
0124: buffer.append(fieldInfo.getDescriptor());
0125: }
0126:
0127: /* Javac.CtFieldWithInit overrides.
0128: */
0129: protected ASTree getInitAST() {
0130: return null;
0131: }
0132:
0133: /* Called by CtClassType.addField().
0134: */
0135: Initializer getInit() {
0136: ASTree tree = getInitAST();
0137: if (tree == null)
0138: return null;
0139: else
0140: return Initializer.byExpr(tree);
0141: }
0142:
0143: /**
0144: * Compiles the given source code and creates a field.
0145: * Examples of the source code are:
0146: *
0147: * <ul><pre>
0148: * "public String name;"
0149: * "public int k = 3;"</pre></ul>
0150: *
0151: * <p>Note that the source code ends with <code>';'</code>
0152: * (semicolon).
0153: *
0154: * @param src the source text.
0155: * @param declaring the class to which the created field is added.
0156: */
0157: public static CtField make(String src, CtClass declaring)
0158: throws CannotCompileException {
0159: Javac compiler = new Javac(declaring);
0160: try {
0161: CtMember obj = compiler.compile(src);
0162: if (obj instanceof CtField)
0163: return (CtField) obj; // an instance of Javac.CtFieldWithInit
0164: } catch (CompileError e) {
0165: throw new CannotCompileException(e);
0166: }
0167:
0168: throw new CannotCompileException("not a field");
0169: }
0170:
0171: /**
0172: * Returns the FieldInfo representing the field in the class file.
0173: */
0174: public FieldInfo getFieldInfo() {
0175: declaringClass.checkModify();
0176: return fieldInfo;
0177: }
0178:
0179: /**
0180: * Returns the FieldInfo representing the field in the class
0181: * file (read only).
0182: * Normal applications do not need calling this method. Use
0183: * <code>getFieldInfo()</code>.
0184: *
0185: * <p>The <code>FieldInfo</code> object obtained by this method
0186: * is read only. Changes to this object might not be reflected
0187: * on a class file generated by <code>toBytecode()</code>,
0188: * <code>toClass()</code>, etc in <code>CtClass</code>.
0189: *
0190: * <p>This method is available even if the <code>CtClass</code>
0191: * containing this field is frozen. However, if the class is
0192: * frozen, the <code>FieldInfo</code> might be also pruned.
0193: *
0194: * @see #getFieldInfo()
0195: * @see CtClass#isFrozen()
0196: * @see CtClass#prune()
0197: */
0198: public FieldInfo getFieldInfo2() {
0199: return fieldInfo;
0200: }
0201:
0202: /**
0203: * Returns the class declaring the field.
0204: */
0205: public CtClass getDeclaringClass() {
0206: // this is redundant but for javadoc.
0207: return super .getDeclaringClass();
0208: }
0209:
0210: /**
0211: * Returns the name of the field.
0212: */
0213: public String getName() {
0214: return fieldInfo.getName();
0215: }
0216:
0217: /**
0218: * Changes the name of the field.
0219: */
0220: public void setName(String newName) {
0221: declaringClass.checkModify();
0222: fieldInfo.setName(newName);
0223: }
0224:
0225: /**
0226: * Returns the encoded modifiers of the field.
0227: *
0228: * @see Modifier
0229: */
0230: public int getModifiers() {
0231: return AccessFlag.toModifier(fieldInfo.getAccessFlags());
0232: }
0233:
0234: /**
0235: * Sets the encoded modifiers of the field.
0236: *
0237: * @see Modifier
0238: */
0239: public void setModifiers(int mod) {
0240: declaringClass.checkModify();
0241: fieldInfo.setAccessFlags(AccessFlag.of(mod));
0242: }
0243:
0244: /**
0245: * Returns the annotations associated with this field.
0246: *
0247: * @return an array of annotation-type objects.
0248: * @see #getAvailableAnnotations()
0249: * @since 3.1
0250: */
0251: public Object[] getAnnotations() throws ClassNotFoundException {
0252: return getAnnotations(false);
0253: }
0254:
0255: /**
0256: * Returns the annotations associated with this field.
0257: * If any annotations are not on the classpath, they are not included
0258: * in the returned array.
0259: *
0260: * @return an array of annotation-type objects.
0261: * @see #getAnnotations()
0262: * @since 3.3
0263: */
0264: public Object[] getAvailableAnnotations() {
0265: try {
0266: return getAnnotations(true);
0267: } catch (ClassNotFoundException e) {
0268: throw new RuntimeException("Unexpected exception", e);
0269: }
0270: }
0271:
0272: private Object[] getAnnotations(boolean ignoreNotFound)
0273: throws ClassNotFoundException {
0274: FieldInfo fi = getFieldInfo2();
0275: AnnotationsAttribute ainfo = (AnnotationsAttribute) fi
0276: .getAttribute(AnnotationsAttribute.invisibleTag);
0277: AnnotationsAttribute ainfo2 = (AnnotationsAttribute) fi
0278: .getAttribute(AnnotationsAttribute.visibleTag);
0279: return CtClassType.toAnnotationType(ignoreNotFound,
0280: getDeclaringClass().getClassPool(), ainfo, ainfo2);
0281: }
0282:
0283: /**
0284: * Returns the character string representing the type of the field.
0285: * If two fields have the same type,
0286: * <code>getSignature()</code> returns the same string.
0287: */
0288: public String getSignature() {
0289: return fieldInfo.getDescriptor();
0290: }
0291:
0292: /**
0293: * Returns the type of the field.
0294: */
0295: public CtClass getType() throws NotFoundException {
0296: return Descriptor.toCtClass(fieldInfo.getDescriptor(),
0297: declaringClass.getClassPool());
0298: }
0299:
0300: /**
0301: * Sets the type of the field.
0302: */
0303: public void setType(CtClass clazz) {
0304: declaringClass.checkModify();
0305: fieldInfo.setDescriptor(Descriptor.of(clazz));
0306: }
0307:
0308: /**
0309: * Returns the value of this field if it is a constant field.
0310: * This method works only if the field type is a primitive type
0311: * or <code>String</code> type. Otherwise, it returns <code>null</code>.
0312: * A constant field is <code>static</code> and <code>final</code>.
0313: *
0314: * @return a <code>Integer</code>, <code>Long</code>, <code>Float</code>,
0315: * <code>Double</code>, <code>Boolean</code>,
0316: * or <code>String</code> object
0317: * representing the constant value.
0318: * <code>null</code> if it is not a constant field
0319: * or if the field type is not a primitive type
0320: * or <code>String</code>.
0321: */
0322: public Object getConstantValue() {
0323: // When this method is modified,
0324: // see also getConstantFieldValue() in TypeChecker.
0325:
0326: int index = fieldInfo.getConstantValue();
0327: if (index == 0)
0328: return null;
0329:
0330: ConstPool cp = fieldInfo.getConstPool();
0331: switch (cp.getTag(index)) {
0332: case ConstPool.CONST_Long:
0333: return new Long(cp.getLongInfo(index));
0334: case ConstPool.CONST_Float:
0335: return new Float(cp.getFloatInfo(index));
0336: case ConstPool.CONST_Double:
0337: return new Double(cp.getDoubleInfo(index));
0338: case ConstPool.CONST_Integer:
0339: int value = cp.getIntegerInfo(index);
0340: // "Z" means boolean type.
0341: if ("Z".equals(fieldInfo.getDescriptor()))
0342: return new Boolean(value != 0);
0343: else
0344: return new Integer(value);
0345: case ConstPool.CONST_String:
0346: return cp.getStringInfo(index);
0347: default:
0348: throw new RuntimeException("bad tag: " + cp.getTag(index)
0349: + " at " + index);
0350: }
0351: }
0352:
0353: /**
0354: * Obtains an attribute with the given name.
0355: * If that attribute is not found in the class file, this
0356: * method returns null.
0357: *
0358: * <p>Note that an attribute is a data block specified by
0359: * the class file format.
0360: * See {@link javassist.bytecode.AttributeInfo}.
0361: *
0362: * @param name attribute name
0363: */
0364: public byte[] getAttribute(String name) {
0365: AttributeInfo ai = fieldInfo.getAttribute(name);
0366: if (ai == null)
0367: return null;
0368: else
0369: return ai.get();
0370: }
0371:
0372: /**
0373: * Adds an attribute. The attribute is saved in the class file.
0374: *
0375: * <p>Note that an attribute is a data block specified by
0376: * the class file format.
0377: * See {@link javassist.bytecode.AttributeInfo}.
0378: *
0379: * @param name attribute name
0380: * @param data attribute value
0381: */
0382: public void setAttribute(String name, byte[] data) {
0383: declaringClass.checkModify();
0384: fieldInfo.addAttribute(new AttributeInfo(fieldInfo
0385: .getConstPool(), name, data));
0386: }
0387:
0388: // inner classes
0389:
0390: /**
0391: * Instances of this class specify how to initialize a field.
0392: * <code>Initializer</code> is passed to
0393: * <code>CtClass.addField()</code> with a <code>CtField</code>.
0394: *
0395: * <p>This class cannot be instantiated with the <code>new</code> operator.
0396: * Factory methods such as <code>byParameter()</code> and
0397: * <code>byNew</code>
0398: * must be used for the instantiation. They create a new instance with
0399: * the given parameters and return it.
0400: *
0401: * @see CtClass#addField(CtField,CtField.Initializer)
0402: */
0403: public static abstract class Initializer {
0404: /**
0405: * Makes an initializer that assigns a constant integer value.
0406: * The field must be integer type.
0407: */
0408: public static Initializer constant(int i) {
0409: return new IntInitializer(i);
0410: }
0411:
0412: /**
0413: * Makes an initializer that assigns a constant long value.
0414: * The field must be long type.
0415: */
0416: public static Initializer constant(long l) {
0417: return new LongInitializer(l);
0418: }
0419:
0420: /**
0421: * Makes an initializer that assigns a constant double value.
0422: * The field must be double type.
0423: */
0424: public static Initializer constant(double d) {
0425: return new DoubleInitializer(d);
0426: }
0427:
0428: /**
0429: * Makes an initializer that assigns a constant string value.
0430: * The field must be <code>java.lang.String</code> type.
0431: */
0432: public static Initializer constant(String s) {
0433: return new StringInitializer(s);
0434: }
0435:
0436: /**
0437: * Makes an initializer using a constructor parameter.
0438: *
0439: * <p>The initial value is the
0440: * N-th parameter given to the constructor of the object including
0441: * the field. If the constructor takes less than N parameters,
0442: * the field is not initialized.
0443: * If the field is static, it is never initialized.
0444: *
0445: * @param nth the n-th (>= 0) parameter is used as
0446: * the initial value.
0447: * If nth is 0, then the first parameter is
0448: * used.
0449: */
0450: public static Initializer byParameter(int nth) {
0451: ParamInitializer i = new ParamInitializer();
0452: i.nthParam = nth;
0453: return i;
0454: }
0455:
0456: /**
0457: * Makes an initializer creating a new object.
0458: *
0459: * <p>This initializer creates a new object and uses it as the initial
0460: * value of the field. The constructor of the created object receives
0461: * the parameter:
0462: *
0463: * <ul><code>Object obj</code> - the object including the field.<br>
0464: * </ul>
0465: *
0466: * <p>If the initialized field is static, then the constructor does
0467: * not receive any parameters.
0468: *
0469: * @param objectType the class instantiated for the initial value.
0470: */
0471: public static Initializer byNew(CtClass objectType) {
0472: NewInitializer i = new NewInitializer();
0473: i.objectType = objectType;
0474: i.stringParams = null;
0475: i.withConstructorParams = false;
0476: return i;
0477: }
0478:
0479: /**
0480: * Makes an initializer creating a new object.
0481: *
0482: * <p>This initializer creates a new object and uses it as the initial
0483: * value of the field. The constructor of the created object receives
0484: * the parameters:
0485: *
0486: * <ul><code>Object obj</code> - the object including the field.<br>
0487: * <code>String[] strs</code> - the character strings specified
0488: * by <code>stringParams</code><br>
0489: * </ul>
0490: *
0491: * <p>If the initialized field is static, then the constructor
0492: * receives only <code>strs</code>.
0493: *
0494: * @param objectType the class instantiated for the initial value.
0495: * @param stringParams the array of strings passed to the
0496: * constructor.
0497: */
0498: public static Initializer byNew(CtClass objectType,
0499: String[] stringParams) {
0500: NewInitializer i = new NewInitializer();
0501: i.objectType = objectType;
0502: i.stringParams = stringParams;
0503: i.withConstructorParams = false;
0504: return i;
0505: }
0506:
0507: /**
0508: * Makes an initializer creating a new object.
0509: *
0510: * <p>This initializer creates a new object and uses it as the initial
0511: * value of the field. The constructor of the created object receives
0512: * the parameters:
0513: *
0514: * <ul><code>Object obj</code> - the object including the field.<br>
0515: * <code>Object[] args</code> - the parameters passed to the
0516: * constructor of the object including the
0517: * filed.
0518: * </ul>
0519: *
0520: * <p>If the initialized field is static, then the constructor does
0521: * not receive any parameters.
0522: *
0523: * @param objectType the class instantiated for the initial value.
0524: *
0525: * @see javassist.CtField.Initializer#byNewArray(CtClass,int)
0526: * @see javassist.CtField.Initializer#byNewArray(CtClass,int[])
0527: */
0528: public static Initializer byNewWithParams(CtClass objectType) {
0529: NewInitializer i = new NewInitializer();
0530: i.objectType = objectType;
0531: i.stringParams = null;
0532: i.withConstructorParams = true;
0533: return i;
0534: }
0535:
0536: /**
0537: * Makes an initializer creating a new object.
0538: *
0539: * <p>This initializer creates a new object and uses it as the initial
0540: * value of the field. The constructor of the created object receives
0541: * the parameters:
0542: *
0543: * <ul><code>Object obj</code> - the object including the field.<br>
0544: * <code>String[] strs</code> - the character strings specified
0545: * by <code>stringParams</code><br>
0546: * <code>Object[] args</code> - the parameters passed to the
0547: * constructor of the object including the
0548: * filed.
0549: * </ul>
0550: *
0551: * <p>If the initialized field is static, then the constructor receives
0552: * only <code>strs</code>.
0553: *
0554: * @param objectType the class instantiated for the initial value.
0555: * @param stringParams the array of strings passed to the
0556: * constructor.
0557: */
0558: public static Initializer byNewWithParams(CtClass objectType,
0559: String[] stringParams) {
0560: NewInitializer i = new NewInitializer();
0561: i.objectType = objectType;
0562: i.stringParams = stringParams;
0563: i.withConstructorParams = true;
0564: return i;
0565: }
0566:
0567: /**
0568: * Makes an initializer calling a static method.
0569: *
0570: * <p>This initializer calls a static method and uses the returned
0571: * value as the initial value of the field.
0572: * The called method receives the parameters:
0573: *
0574: * <ul><code>Object obj</code> - the object including the field.<br>
0575: * </ul>
0576: *
0577: * <p>If the initialized field is static, then the method does
0578: * not receive any parameters.
0579: *
0580: * <p>The type of the returned value must be the same as the field
0581: * type.
0582: *
0583: * @param methodClass the class that the static method is
0584: * declared in.
0585: * @param methodName the name of the satic method.
0586: */
0587: public static Initializer byCall(CtClass methodClass,
0588: String methodName) {
0589: MethodInitializer i = new MethodInitializer();
0590: i.objectType = methodClass;
0591: i.methodName = methodName;
0592: i.stringParams = null;
0593: i.withConstructorParams = false;
0594: return i;
0595: }
0596:
0597: /**
0598: * Makes an initializer calling a static method.
0599: *
0600: * <p>This initializer calls a static method and uses the returned
0601: * value as the initial value of the field. The called method
0602: * receives the parameters:
0603: *
0604: * <ul><code>Object obj</code> - the object including the field.<br>
0605: * <code>String[] strs</code> - the character strings specified
0606: * by <code>stringParams</code><br>
0607: * </ul>
0608: *
0609: * <p>If the initialized field is static, then the method
0610: * receive only <code>strs</code>.
0611: *
0612: * <p>The type of the returned value must be the same as the field
0613: * type.
0614: *
0615: * @param methodClass the class that the static method is
0616: * declared in.
0617: * @param methodName the name of the satic method.
0618: * @param stringParams the array of strings passed to the
0619: * static method.
0620: */
0621: public static Initializer byCall(CtClass methodClass,
0622: String methodName, String[] stringParams) {
0623: MethodInitializer i = new MethodInitializer();
0624: i.objectType = methodClass;
0625: i.methodName = methodName;
0626: i.stringParams = stringParams;
0627: i.withConstructorParams = false;
0628: return i;
0629: }
0630:
0631: /**
0632: * Makes an initializer calling a static method.
0633: *
0634: * <p>This initializer calls a static method and uses the returned
0635: * value as the initial value of the field. The called method
0636: * receives the parameters:
0637: *
0638: * <ul><code>Object obj</code> - the object including the field.<br>
0639: * <code>Object[] args</code> - the parameters passed to the
0640: * constructor of the object including the
0641: * filed.
0642: * </ul>
0643: *
0644: * <p>If the initialized field is static, then the method does
0645: * not receive any parameters.
0646: *
0647: * <p>The type of the returned value must be the same as the field
0648: * type.
0649: *
0650: * @param methodClass the class that the static method is
0651: * declared in.
0652: * @param methodName the name of the satic method.
0653: */
0654: public static Initializer byCallWithParams(CtClass methodClass,
0655: String methodName) {
0656: MethodInitializer i = new MethodInitializer();
0657: i.objectType = methodClass;
0658: i.methodName = methodName;
0659: i.stringParams = null;
0660: i.withConstructorParams = true;
0661: return i;
0662: }
0663:
0664: /**
0665: * Makes an initializer calling a static method.
0666: *
0667: * <p>This initializer calls a static method and uses the returned
0668: * value as the initial value of the field. The called method
0669: * receives the parameters:
0670: *
0671: * <ul><code>Object obj</code> - the object including the field.<br>
0672: * <code>String[] strs</code> - the character strings specified
0673: * by <code>stringParams</code><br>
0674: * <code>Object[] args</code> - the parameters passed to the
0675: * constructor of the object including the
0676: * filed.
0677: * </ul>
0678: *
0679: * <p>If the initialized field is static, then the method
0680: * receive only <code>strs</code>.
0681: *
0682: * <p>The type of the returned value must be the same as the field
0683: * type.
0684: *
0685: * @param methodClass the class that the static method is
0686: * declared in.
0687: * @param methodName the name of the satic method.
0688: * @param stringParams the array of strings passed to the
0689: * static method.
0690: */
0691: public static Initializer byCallWithParams(CtClass methodClass,
0692: String methodName, String[] stringParams) {
0693: MethodInitializer i = new MethodInitializer();
0694: i.objectType = methodClass;
0695: i.methodName = methodName;
0696: i.stringParams = stringParams;
0697: i.withConstructorParams = true;
0698: return i;
0699: }
0700:
0701: /**
0702: * Makes an initializer creating a new array.
0703: *
0704: * @param type the type of the array.
0705: * @param size the size of the array.
0706: * @throws NotFoundException if the type of the array components
0707: * is not found.
0708: */
0709: public static Initializer byNewArray(CtClass type, int size)
0710: throws NotFoundException {
0711: return new ArrayInitializer(type.getComponentType(), size);
0712: }
0713:
0714: /**
0715: * Makes an initializer creating a new multi-dimensional array.
0716: *
0717: * @param type the type of the array.
0718: * @param sizes an <code>int</code> array of the size in every
0719: * dimension.
0720: * The first element is the size in the first
0721: * dimension. The second is in the second, etc.
0722: */
0723: public static Initializer byNewArray(CtClass type, int[] sizes) {
0724: return new MultiArrayInitializer(type, sizes);
0725: }
0726:
0727: /**
0728: * Makes an initializer.
0729: *
0730: * @param source initializer expression.
0731: */
0732: public static Initializer byExpr(String source) {
0733: return new CodeInitializer(source);
0734: }
0735:
0736: static Initializer byExpr(ASTree source) {
0737: return new PtreeInitializer(source);
0738: }
0739:
0740: // Check whether this initializer is valid for the field type.
0741: // If it is invaild, this method throws an exception.
0742: void check(CtClass type) throws CannotCompileException {
0743: }
0744:
0745: // produce codes for initialization
0746: abstract int compile(CtClass type, String name, Bytecode code,
0747: CtClass[] parameters, Javac drv)
0748: throws CannotCompileException;
0749:
0750: // produce codes for initialization
0751: abstract int compileIfStatic(CtClass type, String name,
0752: Bytecode code, Javac drv) throws CannotCompileException;
0753:
0754: // returns the index of CONSTANT_Integer_info etc
0755: // if the value is constant. Otherwise, 0.
0756: int getConstantValue(ConstPool cp, CtClass type) {
0757: return 0;
0758: }
0759: }
0760:
0761: static abstract class CodeInitializer0 extends Initializer {
0762: abstract void compileExpr(Javac drv) throws CompileError;
0763:
0764: int compile(CtClass type, String name, Bytecode code,
0765: CtClass[] parameters, Javac drv)
0766: throws CannotCompileException {
0767: try {
0768: code.addAload(0);
0769: compileExpr(drv);
0770: code.addPutfield(Bytecode.THIS, name, Descriptor
0771: .of(type));
0772: return code.getMaxStack();
0773: } catch (CompileError e) {
0774: throw new CannotCompileException(e);
0775: }
0776: }
0777:
0778: int compileIfStatic(CtClass type, String name, Bytecode code,
0779: Javac drv) throws CannotCompileException {
0780: try {
0781: compileExpr(drv);
0782: code.addPutstatic(Bytecode.THIS, name, Descriptor
0783: .of(type));
0784: return code.getMaxStack();
0785: } catch (CompileError e) {
0786: throw new CannotCompileException(e);
0787: }
0788: }
0789:
0790: int getConstantValue2(ConstPool cp, CtClass type, ASTree tree) {
0791: if (type.isPrimitive()) {
0792: if (tree instanceof IntConst) {
0793: long value = ((IntConst) tree).get();
0794: if (type == CtClass.doubleType)
0795: return cp.addDoubleInfo((double) value);
0796: else if (type == CtClass.floatType)
0797: return cp.addFloatInfo((float) value);
0798: else if (type == CtClass.longType)
0799: return cp.addLongInfo(value);
0800: else if (type != CtClass.voidType)
0801: return cp.addIntegerInfo((int) value);
0802: } else if (tree instanceof DoubleConst) {
0803: double value = ((DoubleConst) tree).get();
0804: if (type == CtClass.floatType)
0805: return cp.addFloatInfo((float) value);
0806: else if (type == CtClass.doubleType)
0807: return cp.addDoubleInfo(value);
0808: }
0809: } else if (tree instanceof StringL
0810: && type.getName().equals(javaLangString))
0811: return cp.addStringInfo(((StringL) tree).get());
0812:
0813: return 0;
0814: }
0815: }
0816:
0817: static class CodeInitializer extends CodeInitializer0 {
0818: private String expression;
0819:
0820: CodeInitializer(String expr) {
0821: expression = expr;
0822: }
0823:
0824: void compileExpr(Javac drv) throws CompileError {
0825: drv.compileExpr(expression);
0826: }
0827:
0828: int getConstantValue(ConstPool cp, CtClass type) {
0829: try {
0830: ASTree t = Javac.parseExpr(expression,
0831: new SymbolTable());
0832: return getConstantValue2(cp, type, t);
0833: } catch (CompileError e) {
0834: return 0;
0835: }
0836: }
0837: }
0838:
0839: static class PtreeInitializer extends CodeInitializer0 {
0840: private ASTree expression;
0841:
0842: PtreeInitializer(ASTree expr) {
0843: expression = expr;
0844: }
0845:
0846: void compileExpr(Javac drv) throws CompileError {
0847: drv.compileExpr(expression);
0848: }
0849:
0850: int getConstantValue(ConstPool cp, CtClass type) {
0851: return getConstantValue2(cp, type, expression);
0852: }
0853: }
0854:
0855: /**
0856: * A field initialized with a parameter passed to the constructor
0857: * of the class containing that field.
0858: */
0859: static class ParamInitializer extends Initializer {
0860: int nthParam;
0861:
0862: ParamInitializer() {
0863: }
0864:
0865: int compile(CtClass type, String name, Bytecode code,
0866: CtClass[] parameters, Javac drv)
0867: throws CannotCompileException {
0868: if (parameters != null && nthParam < parameters.length) {
0869: code.addAload(0);
0870: int nth = nthParamToLocal(nthParam, parameters, false);
0871: int s = code.addLoad(nth, type) + 1;
0872: code.addPutfield(Bytecode.THIS, name, Descriptor
0873: .of(type));
0874: return s; // stack size
0875: } else
0876: return 0; // do not initialize
0877: }
0878:
0879: /**
0880: * Computes the index of the local variable that the n-th parameter
0881: * is assigned to.
0882: *
0883: * @param nth n-th parameter
0884: * @param params list of parameter types
0885: * @param isStatic true if the method is static.
0886: */
0887: static int nthParamToLocal(int nth, CtClass[] params,
0888: boolean isStatic) {
0889: CtClass longType = CtClass.longType;
0890: CtClass doubleType = CtClass.doubleType;
0891: int k;
0892: if (isStatic)
0893: k = 0;
0894: else
0895: k = 1; // 0 is THIS.
0896:
0897: for (int i = 0; i < nth; ++i) {
0898: CtClass type = params[i];
0899: if (type == longType || type == doubleType)
0900: k += 2;
0901: else
0902: ++k;
0903: }
0904:
0905: return k;
0906: }
0907:
0908: int compileIfStatic(CtClass type, String name, Bytecode code,
0909: Javac drv) throws CannotCompileException {
0910: return 0;
0911: }
0912: }
0913:
0914: /**
0915: * A field initialized with an object created by the new operator.
0916: */
0917: static class NewInitializer extends Initializer {
0918: CtClass objectType;
0919: String[] stringParams;
0920: boolean withConstructorParams;
0921:
0922: NewInitializer() {
0923: }
0924:
0925: /**
0926: * Produces codes in which a new object is created and assigned to
0927: * the field as the initial value.
0928: */
0929: int compile(CtClass type, String name, Bytecode code,
0930: CtClass[] parameters, Javac drv)
0931: throws CannotCompileException {
0932: int stacksize;
0933:
0934: code.addAload(0);
0935: code.addNew(objectType);
0936: code.add(Bytecode.DUP);
0937: code.addAload(0);
0938:
0939: if (stringParams == null)
0940: stacksize = 4;
0941: else
0942: stacksize = compileStringParameter(code) + 4;
0943:
0944: if (withConstructorParams)
0945: stacksize += CtNewWrappedMethod.compileParameterList(
0946: code, parameters, 1);
0947:
0948: code
0949: .addInvokespecial(objectType, "<init>",
0950: getDescriptor());
0951: code.addPutfield(Bytecode.THIS, name, Descriptor.of(type));
0952: return stacksize;
0953: }
0954:
0955: private String getDescriptor() {
0956: final String desc3 = "(Ljava/lang/Object;[Ljava/lang/String;[Ljava/lang/Object;)V";
0957:
0958: if (stringParams == null)
0959: if (withConstructorParams)
0960: return "(Ljava/lang/Object;[Ljava/lang/Object;)V";
0961: else
0962: return "(Ljava/lang/Object;)V";
0963: else if (withConstructorParams)
0964: return desc3;
0965: else
0966: return "(Ljava/lang/Object;[Ljava/lang/String;)V";
0967: }
0968:
0969: /**
0970: * Produces codes for a static field.
0971: */
0972: int compileIfStatic(CtClass type, String name, Bytecode code,
0973: Javac drv) throws CannotCompileException {
0974: String desc;
0975:
0976: code.addNew(objectType);
0977: code.add(Bytecode.DUP);
0978:
0979: int stacksize = 2;
0980: if (stringParams == null)
0981: desc = "()V";
0982: else {
0983: desc = "([Ljava/lang/String;)V";
0984: stacksize += compileStringParameter(code);
0985: }
0986:
0987: code.addInvokespecial(objectType, "<init>", desc);
0988: code.addPutstatic(Bytecode.THIS, name, Descriptor.of(type));
0989: return stacksize;
0990: }
0991:
0992: protected final int compileStringParameter(Bytecode code)
0993: throws CannotCompileException {
0994: int nparam = stringParams.length;
0995: code.addIconst(nparam);
0996: code.addAnewarray(javaLangString);
0997: for (int j = 0; j < nparam; ++j) {
0998: code.add(Bytecode.DUP); // dup
0999: code.addIconst(j); // iconst_<j>
1000: code.addLdc(stringParams[j]); // ldc ...
1001: code.add(Bytecode.AASTORE); // aastore
1002: }
1003:
1004: return 4;
1005: }
1006:
1007: }
1008:
1009: /**
1010: * A field initialized with the result of a static method call.
1011: */
1012: static class MethodInitializer extends NewInitializer {
1013: String methodName;
1014:
1015: // the method class is specified by objectType.
1016:
1017: MethodInitializer() {
1018: }
1019:
1020: /**
1021: * Produces codes in which a new object is created and assigned to
1022: * the field as the initial value.
1023: */
1024: int compile(CtClass type, String name, Bytecode code,
1025: CtClass[] parameters, Javac drv)
1026: throws CannotCompileException {
1027: int stacksize;
1028:
1029: code.addAload(0);
1030: code.addAload(0);
1031:
1032: if (stringParams == null)
1033: stacksize = 2;
1034: else
1035: stacksize = compileStringParameter(code) + 2;
1036:
1037: if (withConstructorParams)
1038: stacksize += CtNewWrappedMethod.compileParameterList(
1039: code, parameters, 1);
1040:
1041: String typeDesc = Descriptor.of(type);
1042: String mDesc = getDescriptor() + typeDesc;
1043: code.addInvokestatic(objectType, methodName, mDesc);
1044: code.addPutfield(Bytecode.THIS, name, typeDesc);
1045: return stacksize;
1046: }
1047:
1048: private String getDescriptor() {
1049: final String desc3 = "(Ljava/lang/Object;[Ljava/lang/String;[Ljava/lang/Object;)";
1050:
1051: if (stringParams == null)
1052: if (withConstructorParams)
1053: return "(Ljava/lang/Object;[Ljava/lang/Object;)";
1054: else
1055: return "(Ljava/lang/Object;)";
1056: else if (withConstructorParams)
1057: return desc3;
1058: else
1059: return "(Ljava/lang/Object;[Ljava/lang/String;)";
1060: }
1061:
1062: /**
1063: * Produces codes for a static field.
1064: */
1065: int compileIfStatic(CtClass type, String name, Bytecode code,
1066: Javac drv) throws CannotCompileException {
1067: String desc;
1068:
1069: int stacksize = 1;
1070: if (stringParams == null)
1071: desc = "()";
1072: else {
1073: desc = "([Ljava/lang/String;)";
1074: stacksize += compileStringParameter(code);
1075: }
1076:
1077: String typeDesc = Descriptor.of(type);
1078: code.addInvokestatic(objectType, methodName, desc
1079: + typeDesc);
1080: code.addPutstatic(Bytecode.THIS, name, typeDesc);
1081: return stacksize;
1082: }
1083: }
1084:
1085: static class IntInitializer extends Initializer {
1086: int value;
1087:
1088: IntInitializer(int v) {
1089: value = v;
1090: }
1091:
1092: void check(CtClass type) throws CannotCompileException {
1093: if (type != CtClass.intType)
1094: throw new CannotCompileException("type mismatch");
1095: }
1096:
1097: int compile(CtClass type, String name, Bytecode code,
1098: CtClass[] parameters, Javac drv)
1099: throws CannotCompileException {
1100: code.addAload(0);
1101: code.addIconst(value);
1102: code.addPutfield(Bytecode.THIS, name, Descriptor.of(type));
1103: return 2; // stack size
1104: }
1105:
1106: int compileIfStatic(CtClass type, String name, Bytecode code,
1107: Javac drv) throws CannotCompileException {
1108: code.addIconst(value);
1109: code.addPutstatic(Bytecode.THIS, name, Descriptor.of(type));
1110: return 1; // stack size
1111: }
1112:
1113: int getConstantValue(ConstPool cp, CtClass type) {
1114: if (type == CtClass.intType)
1115: return cp.addIntegerInfo(value);
1116: else
1117: return 0;
1118: }
1119: }
1120:
1121: static class LongInitializer extends Initializer {
1122: long value;
1123:
1124: LongInitializer(long v) {
1125: value = v;
1126: }
1127:
1128: void check(CtClass type) throws CannotCompileException {
1129: if (type != CtClass.longType)
1130: throw new CannotCompileException("type mismatch");
1131: }
1132:
1133: int compile(CtClass type, String name, Bytecode code,
1134: CtClass[] parameters, Javac drv)
1135: throws CannotCompileException {
1136: code.addAload(0);
1137: code.addLdc2w(value);
1138: code.addPutfield(Bytecode.THIS, name, Descriptor.of(type));
1139: return 3; // stack size
1140: }
1141:
1142: int compileIfStatic(CtClass type, String name, Bytecode code,
1143: Javac drv) throws CannotCompileException {
1144: code.addLdc2w(value);
1145: code.addPutstatic(Bytecode.THIS, name, Descriptor.of(type));
1146: return 2; // stack size
1147: }
1148:
1149: int getConstantValue(ConstPool cp, CtClass type) {
1150: if (type == CtClass.longType)
1151: return cp.addLongInfo(value);
1152: else
1153: return 0;
1154: }
1155: }
1156:
1157: static class DoubleInitializer extends Initializer {
1158: double value;
1159:
1160: DoubleInitializer(double v) {
1161: value = v;
1162: }
1163:
1164: void check(CtClass type) throws CannotCompileException {
1165: if (type != CtClass.doubleType)
1166: throw new CannotCompileException("type mismatch");
1167: }
1168:
1169: int compile(CtClass type, String name, Bytecode code,
1170: CtClass[] parameters, Javac drv)
1171: throws CannotCompileException {
1172: code.addAload(0);
1173: code.addLdc2w(value);
1174: code.addPutfield(Bytecode.THIS, name, Descriptor.of(type));
1175: return 3; // stack size
1176: }
1177:
1178: int compileIfStatic(CtClass type, String name, Bytecode code,
1179: Javac drv) throws CannotCompileException {
1180: code.addLdc2w(value);
1181: code.addPutstatic(Bytecode.THIS, name, Descriptor.of(type));
1182: return 2; // stack size
1183: }
1184:
1185: int getConstantValue(ConstPool cp, CtClass type) {
1186: if (type == CtClass.doubleType)
1187: return cp.addDoubleInfo(value);
1188: else
1189: return 0;
1190: }
1191: }
1192:
1193: static class StringInitializer extends Initializer {
1194: String value;
1195:
1196: StringInitializer(String v) {
1197: value = v;
1198: }
1199:
1200: void check(CtClass type) throws CannotCompileException {
1201: if (!type.getName().equals(javaLangString))
1202: throw new CannotCompileException("type mismatch");
1203: }
1204:
1205: int compile(CtClass type, String name, Bytecode code,
1206: CtClass[] parameters, Javac drv)
1207: throws CannotCompileException {
1208: code.addAload(0);
1209: code.addLdc(value);
1210: code.addPutfield(Bytecode.THIS, name, Descriptor.of(type));
1211: return 2; // stack size
1212: }
1213:
1214: int compileIfStatic(CtClass type, String name, Bytecode code,
1215: Javac drv) throws CannotCompileException {
1216: code.addLdc(value);
1217: code.addPutstatic(Bytecode.THIS, name, Descriptor.of(type));
1218: return 1; // stack size
1219: }
1220:
1221: int getConstantValue(ConstPool cp, CtClass type) {
1222: if (type.getName().equals(javaLangString))
1223: return cp.addStringInfo(value);
1224: else
1225: return 0;
1226: }
1227: }
1228:
1229: static class ArrayInitializer extends Initializer {
1230: CtClass type;
1231: int size;
1232:
1233: ArrayInitializer(CtClass t, int s) {
1234: type = t;
1235: size = s;
1236: }
1237:
1238: private void addNewarray(Bytecode code) {
1239: if (type.isPrimitive())
1240: code.addNewarray(((CtPrimitiveType) type)
1241: .getArrayType(), size);
1242: else
1243: code.addAnewarray(type, size);
1244: }
1245:
1246: int compile(CtClass type, String name, Bytecode code,
1247: CtClass[] parameters, Javac drv)
1248: throws CannotCompileException {
1249: code.addAload(0);
1250: addNewarray(code);
1251: code.addPutfield(Bytecode.THIS, name, Descriptor.of(type));
1252: return 2; // stack size
1253: }
1254:
1255: int compileIfStatic(CtClass type, String name, Bytecode code,
1256: Javac drv) throws CannotCompileException {
1257: addNewarray(code);
1258: code.addPutstatic(Bytecode.THIS, name, Descriptor.of(type));
1259: return 1; // stack size
1260: }
1261: }
1262:
1263: static class MultiArrayInitializer extends Initializer {
1264: CtClass type;
1265: int[] dim;
1266:
1267: MultiArrayInitializer(CtClass t, int[] d) {
1268: type = t;
1269: dim = d;
1270: }
1271:
1272: void check(CtClass type) throws CannotCompileException {
1273: if (!type.isArray())
1274: throw new CannotCompileException("type mismatch");
1275: }
1276:
1277: int compile(CtClass type, String name, Bytecode code,
1278: CtClass[] parameters, Javac drv)
1279: throws CannotCompileException {
1280: code.addAload(0);
1281: int s = code.addMultiNewarray(type, dim);
1282: code.addPutfield(Bytecode.THIS, name, Descriptor.of(type));
1283: return s + 1; // stack size
1284: }
1285:
1286: int compileIfStatic(CtClass type, String name, Bytecode code,
1287: Javac drv) throws CannotCompileException {
1288: int s = code.addMultiNewarray(type, dim);
1289: code.addPutstatic(Bytecode.THIS, name, Descriptor.of(type));
1290: return s; // stack size
1291: }
1292: }
1293: }
|