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 }