1
2
3
4
5
6
7
8
9
10
11
12
13
14
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;
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 }