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