View Javadoc

    1   /*
    2    * Copyright  2000-2004 The Apache Software Foundation
    3    *
    4    *  Licensed under the Apache License, Version 2.0 (the "License");
    5    *  you may not use this file except in compliance with the License.
    6    *  You may obtain a copy of the License at
    7    *
    8    *      http://www.apache.org/licenses/LICENSE-2.0
    9    *
    10   *  Unless required by applicable law or agreed to in writing, software
    11   *  distributed under the License is distributed on an "AS IS" BASIS,
    12   *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13   *  See the License for the specific language governing permissions and
    14   *  limitations under the License.
    15   *
    16   */
    17  package org.apache.bcel.generic;
    18
    19  import java.util.ArrayList;
    20  import java.util.Iterator;
    21  import java.util.List;
    22  import org.apache.bcel.Constants;
    23  import org.apache.bcel.classfile.Attribute;
    24  import org.apache.bcel.classfile.Constant;
    25  import org.apache.bcel.classfile.ConstantObject;
    26  import org.apache.bcel.classfile.ConstantPool;
    27  import org.apache.bcel.classfile.ConstantValue;
    28  import org.apache.bcel.classfile.Field;
    29  import org.apache.bcel.classfile.Utility;
    30  import org.apache.bcel.util.BCELComparator;
    31
    32  /***
    33   * Template class for building up a field.  The only extraordinary thing
    34   * one can do is to add a constant value attribute to a field (which must of
    35   * course be compatible with to the declared type).
    36   *
    37   * @version $Id: FieldGen.java 386056 2006-03-15 11:31:56Z tcurdt $
    38   * @author  <A HREF="mailto:m.dahm@gmx.de">M. Dahm</A>
    39   * @see Field
    40   */
    41  public class FieldGen extends FieldGenOrMethodGen {
    42
    43      private Object value = null;
    44      private static BCELComparator _cmp = new BCELComparator() {
    45
    46          public boolean equals( Object o1, Object o2 ) {
    47              FieldGen THIS = (FieldGen) o1;
    48              FieldGen THAT = (FieldGen) o2;
    49              return THIS.getName().equals(THAT.getName())
    50                      && THIS.getSignature().equals(THAT.getSignature());
    51          }
    52
    53
    54          public int hashCode( Object o ) {
    55              FieldGen THIS = (FieldGen) o;
    56              return THIS.getSignature().hashCode() ^ THIS.getName().hashCode();
    57          }
    58      };
    59
    60
    61      /***
    62       * Declare a field. If it is static (isStatic() == true) and has a
    63       * basic type like int or String it may have an initial value
    64       * associated with it as defined by setInitValue().
    65       *
    66       * @param access_flags access qualifiers
    67       * @param type  field type
    68       * @param name field name
    69       * @param cp constant pool
    70       */
    71      public FieldGen(int access_flags, Type type, String name, ConstantPoolGen cp) {
    72          setAccessFlags(access_flags);
    73          setType(type);
    74          setName(name);
    75          setConstantPool(cp);
    76      }
    77
    78
    79      /***
    80       * Instantiate from existing field.
    81       *
    82       * @param field Field object
    83       * @param cp constant pool (must contain the same entries as the field's constant pool)
    84       */
    85      public FieldGen(Field field, ConstantPoolGen cp) {
    86          this(field.getAccessFlags(), Type.getType(field.getSignature()), field.getName(), cp);
    87          Attribute[] attrs = field.getAttributes();
    88          for (int i = 0; i < attrs.length; i++) {
    89              if (attrs[i] instanceof ConstantValue) {
    90                  setValue(((ConstantValue) attrs[i]).getConstantValueIndex());
    91              } else {
    92                  addAttribute(attrs[i]);
    93              }
    94          }
    95      }
    96
    97
    98      private void setValue( int index ) {
    99          ConstantPool cp = this.cp.getConstantPool();
    100         Constant c = cp.getConstant(index);
    101         value = ((ConstantObject) c).getConstantValue(cp);
    102     }
    103
    104
    105     /***
    106      * Set (optional) initial value of field, otherwise it will be set to null/0/false
    107      * by the JVM automatically.
    108      */
    109     public void setInitValue( String str ) {
    110         checkType(new ObjectType("java.lang.String"));
    111         if (str != null) {
    112             value = str;
    113         }
    114     }
    115
    116
    117     public void setInitValue( long l ) {
    118         checkType(Type.LONG);
    119         if (l != 0L) {
    120             value = new Long(l);
    121         }
    122     }
    123
    124
    125     public void setInitValue( int i ) {
    126         checkType(Type.INT);
    127         if (i != 0) {
    128             value = new Integer(i);
    129         }
    130     }
    131
    132
    133     public void setInitValue( short s ) {
    134         checkType(Type.SHORT);
    135         if (s != 0) {
    136             value = new Integer(s);
    137         }
    138     }
    139
    140
    141     public void setInitValue( char c ) {
    142         checkType(Type.CHAR);
    143         if (c != 0) {
    144             value = new Integer(c);
    145         }
    146     }
    147
    148
    149     public void setInitValue( byte b ) {
    150         checkType(Type.BYTE);
    151         if (b != 0) {
    152             value = new Integer(b);
    153         }
    154     }
    155
    156
    157     public void setInitValue( boolean b ) {
    158         checkType(Type.BOOLEAN);
    159         if (b) {
    160             value = new Integer(1);
    161         }
    162     }
    163
    164
    165     public void setInitValue( float f ) {
    166         checkType(Type.FLOAT);
    167         if (f != 0.0) {
    168             value = new Float(f);
    169         }
    170     }
    171
    172
    173     public void setInitValue( double d ) {
    174         checkType(Type.DOUBLE);
    175         if (d != 0.0) {
    176             value = new Double(d);
    177         }
    178     }
    179
    180
    181     /*** Remove any initial value.
    182      */
    183     public void cancelInitValue() {
    184         value = null;
    185     }
    186
    187
    188     private void checkType( Type atype ) {
    189         if (type == null) {
    190             throw new ClassGenException("You haven't defined the type of the field yet");
    191         }
    192         if (!isFinal()) {
    193             throw new ClassGenException("Only final fields may have an initial value!");
    194         }
    195         if (!type.equals(atype)) {
    196             throw new ClassGenException("Types are not compatible: " + type + " vs. " + atype);
    197         }
    198     }
    199
    200
    201     /***
    202      * Get field object after having set up all necessary values.
    203      */
    204     public Field getField() {
    205         String signature = getSignature();
    206         int name_index = cp.addUtf8(name);
    207         int signature_index = cp.addUtf8(signature);
    208         if (value != null) {
    209             checkType(type);
    210             int index = addConstant();
    211             addAttribute(new ConstantValue(cp.addUtf8("ConstantValue"), 2, index, cp
    212                     .getConstantPool()));
    213         }
    214         return new Field(access_flags, name_index, signature_index, getAttributes(), cp
    215                 .getConstantPool());
    216     }
    217
    218
    219     private int addConstant() {
    220         switch (type.getType()) {
    221             case Constants.T_INT:
    222             case Constants.T_CHAR:
    223             case Constants.T_BYTE:
    224             case Constants.T_BOOLEAN:
    225             case Constants.T_SHORT:
    226                 return cp.addInteger(((Integer) value).intValue());
    227             case Constants.T_FLOAT:
    228                 return cp.addFloat(((Float) value).floatValue());
    229             case Constants.T_DOUBLE:
    230                 return cp.addDouble(((Double) value).doubleValue());
    231             case Constants.T_LONG:
    232                 return cp.addLong(((Long) value).longValue());
    233             case Constants.T_REFERENCE:
    234                 return cp.addString(((String) value));
    235             default:
    236                 throw new RuntimeException("Oops: Unhandled : " + type.getType());
    237         }
    238     }
    239
    240
    241     public String getSignature() {
    242         return type.getSignature();
    243     }
    244
    245     private List observers;
    246
    247
    248     /*** Add observer for this object.
    249      */
    250     public void addObserver( FieldObserver o ) {
    251         if (observers == null) {
    252             observers = new ArrayList();
    253         }
    254         observers.add(o);
    255     }
    256
    257
    258     /*** Remove observer for this object.
    259      */
    260     public void removeObserver( FieldObserver o ) {
    261         if (observers != null) {
    262             observers.remove(o);
    263         }
    264     }
    265
    266
    267     /*** Call notify() method on all observers. This method is not called
    268      * automatically whenever the state has changed, but has to be
    269      * called by the user after he has finished editing the object.
    270      */
    271     public void update() {
    272         if (observers != null) {
    273             for (Iterator e = observers.iterator(); e.hasNext();) {
    274                 ((FieldObserver) e.next()).notify(this);
    275             }
    276         }
    277     }
    278
    279
    280     public String getInitValue() {
    281         if (value != null) {
    282             return value.toString();
    283         } else {
    284             return null;
    285         }
    286     }
    287
    288
    289     /***
    290      * Return string representation close to declaration format,
    291      * `public static final short MAX = 100', e.g..
    292      *
    293      * @return String representation of field
    294      */
    295     public final String toString() {
    296         String name, signature, access; // Short cuts to constant pool
    297         access = Utility.accessToString(access_flags);
    298         access = access.equals("") ? "" : (access + " ");
    299         signature = type.toString();
    300         name = getName();
    301         StringBuffer buf = new StringBuffer(32);
    302         buf.append(access).append(signature).append(" ").append(name);
    303         String value = getInitValue();
    304         if (value != null) {
    305             buf.append(" = ").append(value);
    306         }
    307         return buf.toString();
    308     }
    309
    310
    311     /*** @return deep copy of this field
    312      */
    313     public FieldGen copy( ConstantPoolGen cp ) {
    314         FieldGen fg = (FieldGen) clone();
    315         fg.setConstantPool(cp);
    316         return fg;
    317     }
    318
    319
    320     /***
    321      * @return Comparison strategy object
    322      */
    323     public static BCELComparator getComparator() {
    324         return _cmp;
    325     }
    326
    327
    328     /***
    329      * @param comparator Comparison strategy object
    330      */
    331     public static void setComparator( BCELComparator comparator ) {
    332         _cmp = comparator;
    333     }
    334
    335
    336     /***
    337      * Return value as defined by given BCELComparator strategy.
    338      * By default two FieldGen objects are said to be equal when
    339      * their names and signatures are equal.
    340      *
    341      * @see java.lang.Object#equals(java.lang.Object)
    342      */
    343     public boolean equals( Object obj ) {
    344         return _cmp.equals(this, obj);
    345     }
    346
    347
    348     /***
    349      * Return value as defined by given BCELComparator strategy.
    350      * By default return the hashcode of the field's name XOR signature.
    351      *
    352      * @see java.lang.Object#hashCode()
    353      */
    354     public int hashCode() {
    355         return _cmp.hashCode(this);
    356     }
    357 }