1 /*
   2  * reserved comment block
   3  * DO NOT REMOVE OR ALTER!
   4  */
   5 package com.sun.org.apache.bcel.internal.generic;
   6 
   7 /* ====================================================================
   8  * The Apache Software License, Version 1.1
   9  *
  10  * Copyright (c) 2001 The Apache Software Foundation.  All rights
  11  * reserved.
  12  *
  13  * Redistribution and use in source and binary forms, with or without
  14  * modification, are permitted provided that the following conditions
  15  * are met:
  16  *
  17  * 1. Redistributions of source code must retain the above copyright
  18  *    notice, this list of conditions and the following disclaimer.
  19  *
  20  * 2. Redistributions in binary form must reproduce the above copyright
  21  *    notice, this list of conditions and the following disclaimer in
  22  *    the documentation and/or other materials provided with the
  23  *    distribution.
  24  *
  25  * 3. The end-user documentation included with the redistribution,
  26  *    if any, must include the following acknowledgment:
  27  *       "This product includes software developed by the
  28  *        Apache Software Foundation (http://www.apache.org/)."
  29  *    Alternately, this acknowledgment may appear in the software itself,
  30  *    if and wherever such third-party acknowledgments normally appear.
  31  *
  32  * 4. The names "Apache" and "Apache Software Foundation" and
  33  *    "Apache BCEL" must not be used to endorse or promote products
  34  *    derived from this software without prior written permission. For
  35  *    written permission, please contact apache@apache.org.
  36  *
  37  * 5. Products derived from this software may not be called "Apache",
  38  *    "Apache BCEL", nor may "Apache" appear in their name, without
  39  *    prior written permission of the Apache Software Foundation.
  40  *
  41  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
  42  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
  43  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  44  * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
  45  * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  46  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
  47  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
  48  * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
  49  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
  50  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
  51  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  52  * SUCH DAMAGE.
  53  * ====================================================================
  54  *
  55  * This software consists of voluntary contributions made by many
  56  * individuals on behalf of the Apache Software Foundation.  For more
  57  * information on the Apache Software Foundation, please see
  58  * <http://www.apache.org/>.
  59  */
  60 
  61 import com.sun.org.apache.bcel.internal.Constants;
  62 import com.sun.org.apache.bcel.internal.classfile.*;
  63 import java.util.ArrayList;
  64 import java.util.Iterator;
  65 
  66 /**
  67  * Template class for building up a field.  The only extraordinary thing
  68  * one can do is to add a constant value attribute to a field (which must of
  69  * course be compatible with to the declared type).
  70  *
  71  * @author  <A HREF="mailto:markus.dahm@berlin.de">M. Dahm</A>
  72  * @see Field
  73  */
  74 public class FieldGen extends FieldGenOrMethodGen {
  75   private Object value = null;
  76 
  77   /**
  78    * Declare a field. If it is static (isStatic() == true) and has a
  79    * basic type like int or String it may have an initial value
  80    * associated with it as defined by setInitValue().
  81    *
  82    * @param access_flags access qualifiers
  83    * @param type  field type
  84    * @param name field name
  85    * @param cp constant pool
  86    */
  87   public FieldGen(int access_flags, Type type, String name, ConstantPoolGen cp) {
  88     setAccessFlags(access_flags);
  89     setType(type);
  90     setName(name);
  91     setConstantPool(cp);
  92   }
  93 
  94   /**
  95    * Instantiate from existing field.
  96    *
  97    * @param field Field object
  98    * @param cp constant pool (must contain the same entries as the field's constant pool)
  99    */
 100   public FieldGen(Field field, ConstantPoolGen cp) {
 101     this(field.getAccessFlags(), Type.getType(field.getSignature()), field.getName(), cp);
 102 
 103     Attribute[] attrs = field.getAttributes();
 104 
 105     for(int i=0; i < attrs.length; i++) {
 106       if(attrs[i] instanceof ConstantValue)
 107         setValue(((ConstantValue)attrs[i]).getConstantValueIndex());
 108       else
 109         addAttribute(attrs[i]);
 110     }
 111   }
 112 
 113   private void setValue(int index) {
 114     ConstantPool cp  = this.cp.getConstantPool();
 115     Constant     c   = cp.getConstant(index);
 116     value = ((ConstantObject)c).getConstantValue(cp);
 117   }
 118 
 119   /**
 120    * Set (optional) initial value of field, otherwise it will be set to null/0/false
 121    * by the JVM automatically.
 122    */
 123   public void setInitValue(String str) {
 124     checkType(new ObjectType("java.lang.String"));
 125 
 126     if(str != null)
 127       value = str;
 128   }
 129 
 130   public void setInitValue(long l) {
 131     checkType(Type.LONG);
 132 
 133     if(l != 0L)
 134       value = new Long(l);
 135   }
 136 
 137   public void setInitValue(int i) {
 138     checkType(Type.INT);
 139 
 140     if(i != 0)
 141       value = new Integer(i);
 142   }
 143 
 144   public void setInitValue(short s) {
 145     checkType(Type.SHORT);
 146 
 147     if(s != 0)
 148       value = new Integer(s);
 149   }
 150 
 151   public void setInitValue(char c) {
 152     checkType(Type.CHAR);
 153 
 154     if(c != 0)
 155       value = new Integer(c);
 156   }
 157 
 158   public void setInitValue(byte b) {
 159     checkType(Type.BYTE);
 160 
 161     if(b != 0)
 162       value = new Integer(b);
 163   }
 164 
 165   public void setInitValue(boolean b) {
 166     checkType(Type.BOOLEAN);
 167 
 168     if(b)
 169       value = new Integer(1);
 170   }
 171 
 172   public void setInitValue(float f) {
 173     checkType(Type.FLOAT);
 174 
 175     if(f != 0.0)
 176       value = new Float(f);
 177   }
 178 
 179   public void setInitValue(double d) {
 180     checkType(Type.DOUBLE);
 181 
 182     if(d != 0.0)
 183       value = new Double(d);
 184   }
 185 
 186   /** Remove any initial value.
 187    */
 188   public void cancelInitValue() {
 189     value = null;
 190   }
 191 
 192   private void checkType(Type atype) {
 193     if(type == null)
 194       throw new ClassGenException("You haven't defined the type of the field yet");
 195 
 196     if(!isFinal())
 197       throw new ClassGenException("Only final fields may have an initial value!");
 198 
 199     if(!type.equals(atype))
 200       throw new ClassGenException("Types are not compatible: " + type + " vs. " + atype);
 201   }
 202 
 203   /**
 204    * Get field object after having set up all necessary values.
 205    */
 206   public Field getField() {
 207     String      signature       = getSignature();
 208     int         name_index      = cp.addUtf8(name);
 209     int         signature_index = cp.addUtf8(signature);
 210 
 211     if(value != null) {
 212       checkType(type);
 213       int index = addConstant();
 214       addAttribute(new ConstantValue(cp.addUtf8("ConstantValue"),
 215                                      2, index, cp.getConstantPool()));
 216     }
 217 
 218     return new Field(access_flags, name_index, signature_index, getAttributes(),
 219                      cp.getConstantPool());
 220   }
 221 
 222   private int addConstant() {
 223     switch(type.getType()) {
 224     case Constants.T_INT: case Constants.T_CHAR: case Constants.T_BYTE:
 225     case Constants.T_BOOLEAN: case Constants.T_SHORT:
 226       return cp.addInteger(((Integer)value).intValue());
 227 
 228     case Constants.T_FLOAT:
 229       return cp.addFloat(((Float)value).floatValue());
 230 
 231     case Constants.T_DOUBLE:
 232       return cp.addDouble(((Double)value).doubleValue());
 233 
 234     case Constants.T_LONG:
 235       return cp.addLong(((Long)value).longValue());
 236 
 237     case Constants.T_REFERENCE:
 238       return cp.addString(((String)value));
 239 
 240     default:
 241       throw new RuntimeException("Oops: Unhandled : " + type.getType());
 242     }
 243   }
 244 
 245   public String  getSignature()  { return type.getSignature(); }
 246 
 247   private ArrayList observers;
 248 
 249   /** Add observer for this object.
 250    */
 251   public void addObserver(FieldObserver o) {
 252     if(observers == null)
 253       observers = new ArrayList();
 254 
 255     observers.add(o);
 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   /** Call notify() method on all observers. This method is not called
 266    * automatically whenever the state has changed, but has to be
 267    * called by the user after he has finished editing the object.
 268    */
 269   public void update() {
 270     if(observers != null)
 271       for(Iterator e = observers.iterator(); e.hasNext(); )
 272         ((FieldObserver)e.next()).notify(this);
 273   }
 274 
 275   public String getInitValue() {
 276     if(value != null) {
 277       return value.toString();
 278     } else
 279       return null;
 280   }
 281 
 282   /**
 283    * Return string representation close to declaration format,
 284    * `public static final short MAX = 100', e.g..
 285    *
 286    * @return String representation of field
 287    */
 288   public final String toString() {
 289     String name, signature, access; // Short cuts to constant pool
 290 
 291     access    = Utility.accessToString(access_flags);
 292     access    = access.equals("")? "" : (access + " ");
 293     signature = type.toString();
 294     name      = getName();
 295 
 296     StringBuffer buf = new StringBuffer(access + signature + " " + name);
 297     String value = getInitValue();
 298 
 299     if(value != null)
 300       buf.append(" = " + value);
 301 
 302     return buf.toString();
 303   }
 304 
 305   /** @return deep copy of this field
 306    */
 307   public FieldGen copy(ConstantPoolGen cp) {
 308     FieldGen fg = (FieldGen)clone();
 309 
 310     fg.setConstantPool(cp);
 311     return fg;
 312   }
 313 }