1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.apache.bcel.generic;
20
21 import java.util.ArrayList;
22 import java.util.List;
23 import java.util.Objects;
24 import java.util.stream.Stream;
25
26 import org.apache.bcel.Const;
27 import org.apache.bcel.classfile.Annotations;
28 import org.apache.bcel.classfile.Attribute;
29 import org.apache.bcel.classfile.Constant;
30 import org.apache.bcel.classfile.ConstantObject;
31 import org.apache.bcel.classfile.ConstantPool;
32 import org.apache.bcel.classfile.ConstantValue;
33 import org.apache.bcel.classfile.Field;
34 import org.apache.bcel.classfile.Utility;
35 import org.apache.bcel.util.BCELComparator;
36
37
38
39
40
41
42
43 public class FieldGen extends FieldGenOrMethodGen {
44
45 private static BCELComparator<FieldGen> bcelComparator = new BCELComparator<FieldGen>() {
46
47 @Override
48 public boolean equals(final FieldGen a, final FieldGen b) {
49 return a == b || a != null && b != null && Objects.equals(a.getName(), b.getName()) && Objects.equals(a.getSignature(), b.getSignature());
50 }
51
52 @Override
53 public int hashCode(final FieldGen o) {
54 return o != null ? Objects.hash(o.getSignature(), o.getName()) : 0;
55 }
56 };
57
58
59
60
61 public static BCELComparator<FieldGen> getComparator() {
62 return bcelComparator;
63 }
64
65
66
67
68 public static void setComparator(final BCELComparator<FieldGen> comparator) {
69 bcelComparator = comparator;
70 }
71
72 private Object value;
73
74 private List<FieldObserver> observers;
75
76
77
78
79
80
81
82 public FieldGen(final Field field, final ConstantPoolGen cp) {
83 this(field.getAccessFlags(), Type.getType(field.getSignature()), field.getName(), cp);
84 final Attribute[] attrs = field.getAttributes();
85 for (final Attribute attr : attrs) {
86 if (attr instanceof ConstantValue) {
87 setValue(((ConstantValue) attr).getConstantValueIndex());
88 } else if (attr instanceof Annotations) {
89 final Annotations runtimeAnnotations = (Annotations) attr;
90 runtimeAnnotations.forEach(element -> addAnnotationEntry(new AnnotationEntryGen(element, cp, false)));
91 } else {
92 addAttribute(attr);
93 }
94 }
95 }
96
97
98
99
100
101
102
103
104
105
106 public FieldGen(final int accessFlags, final Type type, final String name, final ConstantPoolGen cp) {
107 super(accessFlags);
108 setType(type);
109 setName(name);
110 setConstantPool(cp);
111 }
112
113 private void addAnnotationsAsAttribute(final ConstantPoolGen cp) {
114 Stream.of(AnnotationEntryGen.getAnnotationAttributes(cp, super.getAnnotationEntries())).forEach(this::addAttribute);
115 }
116
117 private int addConstant() {
118 switch (super.getType().getType()) {
119 case Const.T_INT:
120 case Const.T_CHAR:
121 case Const.T_BYTE:
122 case Const.T_BOOLEAN:
123 case Const.T_SHORT:
124 return super.getConstantPool().addInteger(((Integer) value).intValue());
125 case Const.T_FLOAT:
126 return super.getConstantPool().addFloat(((Float) value).floatValue());
127 case Const.T_DOUBLE:
128 return super.getConstantPool().addDouble(((Double) value).doubleValue());
129 case Const.T_LONG:
130 return super.getConstantPool().addLong(((Long) value).longValue());
131 case Const.T_REFERENCE:
132 return super.getConstantPool().addString((String) value);
133 default:
134 throw new IllegalStateException("Unhandled : " + super.getType().getType());
135 }
136 }
137
138
139
140
141 public void addObserver(final FieldObserver o) {
142 if (observers == null) {
143 observers = new ArrayList<>();
144 }
145 observers.add(o);
146 }
147
148
149
150
151 public void cancelInitValue() {
152 value = null;
153 }
154
155 private void checkType(final Type atype) {
156 final Type superType = super.getType();
157 if (superType == null) {
158 throw new ClassGenException("You haven't defined the type of the field yet");
159 }
160 if (!isFinal()) {
161 throw new ClassGenException("Only final fields may have an initial value!");
162 }
163 if (!superType.equals(atype)) {
164 throw new ClassGenException("Types are not compatible: " + superType + " vs. " + atype);
165 }
166 }
167
168
169
170
171 public FieldGen copy(final ConstantPoolGen cp) {
172 final FieldGen fg = (FieldGen) clone();
173 fg.setConstantPool(cp);
174 return fg;
175 }
176
177
178
179
180
181
182
183 @Override
184 public boolean equals(final Object obj) {
185 return obj instanceof FieldGen && bcelComparator.equals(this, (FieldGen) obj);
186 }
187
188
189
190
191 public Field getField() {
192 final String signature = getSignature();
193 final int nameIndex = super.getConstantPool().addUtf8(super.getName());
194 final int signatureIndex = super.getConstantPool().addUtf8(signature);
195 if (value != null) {
196 checkType(super.getType());
197 final int index = addConstant();
198 addAttribute(new ConstantValue(super.getConstantPool().addUtf8("ConstantValue"), 2, index, super.getConstantPool().getConstantPool()));
199 }
200 addAnnotationsAsAttribute(super.getConstantPool());
201 return new Field(super.getAccessFlags(), nameIndex, signatureIndex, getAttributes(), super.getConstantPool().getConstantPool());
202 }
203
204 public String getInitValue() {
205 return Objects.toString(value, null);
206 }
207
208 @Override
209 public String getSignature() {
210 return super.getType().getSignature();
211 }
212
213
214
215
216
217
218
219 @Override
220 public int hashCode() {
221 return bcelComparator.hashCode(this);
222 }
223
224
225
226
227 public void removeObserver(final FieldObserver o) {
228 if (observers != null) {
229 observers.remove(o);
230 }
231 }
232
233 public void setInitValue(final boolean b) {
234 checkType(Type.BOOLEAN);
235 if (b) {
236 value = Integer.valueOf(1);
237 }
238 }
239
240 public void setInitValue(final byte b) {
241 checkType(Type.BYTE);
242 if (b != 0) {
243 value = Integer.valueOf(b);
244 }
245 }
246
247 public void setInitValue(final char c) {
248 checkType(Type.CHAR);
249 if (c != 0) {
250 value = Integer.valueOf(c);
251 }
252 }
253
254 public void setInitValue(final double d) {
255 checkType(Type.DOUBLE);
256 if (d != 0.0) {
257 value = Double.valueOf(d);
258 }
259 }
260
261 public void setInitValue(final float f) {
262 checkType(Type.FLOAT);
263 if (f != 0.0) {
264 value = Float.valueOf(f);
265 }
266 }
267
268 public void setInitValue(final int i) {
269 checkType(Type.INT);
270 if (i != 0) {
271 value = Integer.valueOf(i);
272 }
273 }
274
275 public void setInitValue(final long l) {
276 checkType(Type.LONG);
277 if (l != 0L) {
278 value = Long.valueOf(l);
279 }
280 }
281
282 public void setInitValue(final short s) {
283 checkType(Type.SHORT);
284 if (s != 0) {
285 value = Integer.valueOf(s);
286 }
287 }
288
289
290
291
292 public void setInitValue(final String str) {
293 checkType(ObjectType.getInstance("java.lang.String"));
294 if (str != null) {
295 value = str;
296 }
297 }
298
299 private void setValue(final int index) {
300 final ConstantPool cp = super.getConstantPool().getConstantPool();
301 final Constant c = cp.getConstant(index);
302 value = ((ConstantObject) c).getConstantValue(cp);
303 }
304
305
306
307
308
309
310 @Override
311 public final String toString() {
312
313 String access = Utility.accessToString(super.getAccessFlags());
314 access = access.isEmpty() ? "" : access + " ";
315 final String signature = super.getType().toString();
316 final String name = getName();
317 final StringBuilder buf = new StringBuilder(32);
318 buf.append(access).append(signature).append(" ").append(name);
319 final String value = getInitValue();
320 if (value != null) {
321 buf.append(" = ").append(value);
322 }
323 return buf.toString();
324 }
325
326
327
328
329
330 public void update() {
331 if (observers != null) {
332 for (final FieldObserver observer : observers) {
333 observer.notify(this);
334 }
335 }
336 }
337 }