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