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