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.io.ByteArrayInputStream;
22 import java.io.ByteArrayOutputStream;
23 import java.io.DataInput;
24 import java.io.DataInputStream;
25 import java.io.DataOutputStream;
26 import java.io.IOException;
27 import java.util.ArrayList;
28 import java.util.List;
29 import java.util.stream.Collectors;
30
31 import org.apache.bcel.classfile.AnnotationEntry;
32 import org.apache.bcel.classfile.Attribute;
33 import org.apache.bcel.classfile.ConstantUtf8;
34 import org.apache.bcel.classfile.ElementValuePair;
35 import org.apache.bcel.classfile.RuntimeInvisibleAnnotations;
36 import org.apache.bcel.classfile.RuntimeInvisibleParameterAnnotations;
37 import org.apache.bcel.classfile.RuntimeVisibleAnnotations;
38 import org.apache.bcel.classfile.RuntimeVisibleParameterAnnotations;
39 import org.apache.bcel.util.Args;
40 import org.apache.commons.lang3.ArrayUtils;
41 import org.apache.commons.lang3.stream.Streams;
42
43
44
45
46
47
48 public class AnnotationEntryGen {
49
50 static final AnnotationEntryGen[] EMPTY_ARRAY = {};
51
52
53
54
55
56
57
58 static Attribute[] getAnnotationAttributes(final ConstantPoolGen cp, final AnnotationEntryGen[] annotationEntryGens) {
59 if (ArrayUtils.isEmpty(annotationEntryGens)) {
60 return Attribute.EMPTY_ARRAY;
61 }
62
63 try {
64 int countVisible = 0;
65 int countInvisible = 0;
66
67
68 for (final AnnotationEntryGen a : annotationEntryGens) {
69 if (a.isRuntimeVisible()) {
70 countVisible++;
71 } else {
72 countInvisible++;
73 }
74 }
75
76 final ByteArrayOutputStream rvaBytes = new ByteArrayOutputStream();
77 final ByteArrayOutputStream riaBytes = new ByteArrayOutputStream();
78 try (DataOutputStream rvaDos = new DataOutputStream(rvaBytes); DataOutputStream riaDos = new DataOutputStream(riaBytes)) {
79
80 rvaDos.writeShort(countVisible);
81 riaDos.writeShort(countInvisible);
82
83
84 for (final AnnotationEntryGen a : annotationEntryGens) {
85 if (a.isRuntimeVisible()) {
86 a.dump(rvaDos);
87 } else {
88 a.dump(riaDos);
89 }
90 }
91 }
92
93 final byte[] rvaData = rvaBytes.toByteArray();
94 final byte[] riaData = riaBytes.toByteArray();
95
96 int rvaIndex = -1;
97 int riaIndex = -1;
98
99 if (rvaData.length > 2) {
100 rvaIndex = cp.addUtf8("RuntimeVisibleAnnotations");
101 }
102 if (riaData.length > 2) {
103 riaIndex = cp.addUtf8("RuntimeInvisibleAnnotations");
104 }
105
106 final List<Attribute> newAttributes = new ArrayList<>();
107 if (rvaData.length > 2) {
108 newAttributes
109 .add(new RuntimeVisibleAnnotations(rvaIndex, rvaData.length, new DataInputStream(new ByteArrayInputStream(rvaData)), cp.getConstantPool()));
110 }
111 if (riaData.length > 2) {
112 newAttributes.add(
113 new RuntimeInvisibleAnnotations(riaIndex, riaData.length, new DataInputStream(new ByteArrayInputStream(riaData)), cp.getConstantPool()));
114 }
115
116 return newAttributes.toArray(Attribute.EMPTY_ARRAY);
117 } catch (final IOException e) {
118 System.err.println("IOException whilst processing annotations");
119 e.printStackTrace();
120 }
121 return null;
122 }
123
124
125
126
127
128 static Attribute[] getParameterAnnotationAttributes(final ConstantPoolGen cp,
129 final List<AnnotationEntryGen>[] vec) {
130 final int[] visCount = new int[vec.length];
131 int totalVisCount = 0;
132 final int[] invisCount = new int[vec.length];
133 int totalInvisCount = 0;
134 try {
135 for (int i = 0; i < vec.length; i++) {
136 if (vec[i] != null) {
137 for (final AnnotationEntryGen element : vec[i]) {
138 if (element.isRuntimeVisible()) {
139 visCount[i]++;
140 totalVisCount++;
141 } else {
142 invisCount[i]++;
143 totalInvisCount++;
144 }
145 }
146 }
147 }
148
149 final ByteArrayOutputStream rvaBytes = new ByteArrayOutputStream();
150 try (DataOutputStream rvaDos = new DataOutputStream(rvaBytes)) {
151 rvaDos.writeByte(Args.requireU1(vec.length, "vec.length"));
152 for (int i = 0; i < vec.length; i++) {
153 rvaDos.writeShort(visCount[i]);
154 if (visCount[i] > 0) {
155 for (final AnnotationEntryGen element : vec[i]) {
156 if (element.isRuntimeVisible()) {
157 element.dump(rvaDos);
158 }
159 }
160 }
161 }
162 }
163
164 final ByteArrayOutputStream riaBytes = new ByteArrayOutputStream();
165 try (DataOutputStream riaDos = new DataOutputStream(riaBytes)) {
166 riaDos.writeByte(Args.requireU1(vec.length, "vec.length"));
167 for (int i = 0; i < vec.length; i++) {
168 riaDos.writeShort(invisCount[i]);
169 if (invisCount[i] > 0) {
170 for (final AnnotationEntryGen element : vec[i]) {
171 if (!element.isRuntimeVisible()) {
172 element.dump(riaDos);
173 }
174 }
175 }
176 }
177 }
178 final byte[] rvaData = rvaBytes.toByteArray();
179 final byte[] riaData = riaBytes.toByteArray();
180 int rvaIndex = -1;
181 int riaIndex = -1;
182 if (totalVisCount > 0) {
183 rvaIndex = cp.addUtf8("RuntimeVisibleParameterAnnotations");
184 }
185 if (totalInvisCount > 0) {
186 riaIndex = cp.addUtf8("RuntimeInvisibleParameterAnnotations");
187 }
188 final List<Attribute> newAttributes = new ArrayList<>();
189 if (totalVisCount > 0) {
190 newAttributes.add(new RuntimeVisibleParameterAnnotations(rvaIndex, rvaData.length, new DataInputStream(new ByteArrayInputStream(rvaData)),
191 cp.getConstantPool()));
192 }
193 if (totalInvisCount > 0) {
194 newAttributes.add(new RuntimeInvisibleParameterAnnotations(riaIndex, riaData.length, new DataInputStream(new ByteArrayInputStream(riaData)),
195 cp.getConstantPool()));
196 }
197 return newAttributes.toArray(Attribute.EMPTY_ARRAY);
198 } catch (final IOException e) {
199 System.err.println("IOException whilst processing parameter annotations");
200 e.printStackTrace();
201 }
202 return null;
203 }
204
205
206
207
208
209
210
211
212
213
214 public static AnnotationEntryGen read(final DataInput dis, final ConstantPoolGen cpool, final boolean b) throws IOException {
215 final AnnotationEntryGen a = new AnnotationEntryGen(cpool);
216 a.typeIndex = dis.readUnsignedShort();
217 final int elemValuePairCount = dis.readUnsignedShort();
218 for (int i = 0; i < elemValuePairCount; i++) {
219 final int nidx = dis.readUnsignedShort();
220 a.addElementNameValuePair(new ElementValuePairGen(nidx, ElementValueGen.readElementValue(dis, cpool), cpool));
221 }
222 a.isRuntimeVisible(b);
223 return a;
224 }
225
226 private int typeIndex;
227
228 private List<ElementValuePairGen> evs;
229
230 private final ConstantPoolGen cpool;
231
232 private boolean isRuntimeVisible;
233
234
235
236
237
238
239
240
241
242
243
244 public AnnotationEntryGen(final AnnotationEntry a, final ConstantPoolGen cpool, final boolean copyPoolEntries) {
245 this.cpool = cpool;
246 if (copyPoolEntries) {
247 typeIndex = cpool.addUtf8(a.getAnnotationType());
248 } else {
249 typeIndex = a.getAnnotationTypeIndex();
250 }
251 isRuntimeVisible = a.isRuntimeVisible();
252 evs = copyValues(a.getElementValuePairs(), cpool, copyPoolEntries);
253 }
254
255 private AnnotationEntryGen(final ConstantPoolGen cpool) {
256 this.cpool = cpool;
257 }
258
259
260
261
262
263
264
265
266
267 public AnnotationEntryGen(final ObjectType type, final List<ElementValuePairGen> elements, final boolean vis, final ConstantPoolGen cpool) {
268 this.cpool = cpool;
269 this.typeIndex = cpool.addUtf8(type.getSignature());
270 evs = elements;
271 isRuntimeVisible = vis;
272 }
273
274
275
276
277
278
279 public void addElementNameValuePair(final ElementValuePairGen evp) {
280 if (evs == null) {
281 evs = new ArrayList<>();
282 }
283 evs.add(evp);
284 }
285
286 private List<ElementValuePairGen> copyValues(final ElementValuePair[] in, final ConstantPoolGen cpool, final boolean copyPoolEntries) {
287 return Streams.of(in).map(nvp -> new ElementValuePairGen(nvp, cpool, copyPoolEntries)).collect(Collectors.toList());
288 }
289
290
291
292
293
294
295
296 public void dump(final DataOutputStream dos) throws IOException {
297 dos.writeShort(typeIndex);
298 dos.writeShort(Args.requireU2(evs.size(), "evs.size()"));
299 for (final ElementValuePairGen envp : evs) {
300 envp.dump(dos);
301 }
302 }
303
304
305
306
307
308
309 public AnnotationEntry getAnnotation() {
310 final AnnotationEntry a = new AnnotationEntry(typeIndex, cpool.getConstantPool(), isRuntimeVisible);
311 for (final ElementValuePairGen element : evs) {
312 a.addElementNameValuePair(element.getElementNameValuePair());
313 }
314 return a;
315 }
316
317
318
319
320
321
322 public int getTypeIndex() {
323 return typeIndex;
324 }
325
326
327
328
329
330
331 public final String getTypeName() {
332 return getTypeSignature();
333
334 }
335
336
337
338
339
340
341 public final String getTypeSignature() {
342
343 final ConstantUtf8 utf8 = (ConstantUtf8) cpool.getConstant(typeIndex);
344 return utf8.getBytes();
345 }
346
347
348
349
350
351
352 public List<ElementValuePairGen> getValues() {
353 return evs;
354 }
355
356
357
358
359
360
361 public boolean isRuntimeVisible() {
362 return isRuntimeVisible;
363 }
364
365 private void isRuntimeVisible(final boolean b) {
366 isRuntimeVisible = b;
367 }
368
369
370
371
372
373
374 public String toShortString() {
375 final StringBuilder s = new StringBuilder();
376 s.append("@").append(getTypeName()).append("(");
377 for (int i = 0; i < evs.size(); i++) {
378 s.append(evs.get(i));
379 if (i + 1 < evs.size()) {
380 s.append(",");
381 }
382 }
383 s.append(")");
384 return s.toString();
385 }
386
387 @Override
388 public String toString() {
389 final StringBuilder s = new StringBuilder(32);
390 s.append("AnnotationGen:[").append(getTypeName()).append(" #").append(evs.size()).append(" {");
391 for (int i = 0; i < evs.size(); i++) {
392 s.append(evs.get(i));
393 if (i + 1 < evs.size()) {
394 s.append(",");
395 }
396 }
397 s.append("}]");
398 return s.toString();
399 }
400
401 }