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