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