1 /*
2 * Licensed to the Apache Software Foundation (ASF) under one
3 * or more contributor license agreements. See the NOTICE file
4 * distributed with this work for additional information
5 * regarding copyright ownership. The ASF licenses this file
6 * to you under the Apache License, Version 2.0 (the
7 * "License"); you may not use this file except in compliance
8 * with the License. You may obtain a copy of the License at
9 *
10 * https://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing,
13 * software distributed under the License is distributed on an
14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 * KIND, either express or implied. See the License for the
16 * specific language governing permissions and limitations
17 * under the License.
18 */
19 package org.apache.bcel.classfile;
20
21 import java.io.DataInput;
22 import java.io.DataOutputStream;
23 import java.io.IOException;
24 import java.util.ArrayList;
25 import java.util.List;
26 import java.util.stream.Stream;
27
28 import org.apache.commons.lang3.stream.Streams;
29
30 /**
31 * Represents one annotation in the annotation table
32 *
33 * @since 6.0
34 */
35 public class AnnotationEntry implements Node {
36
37 /**
38 * Empty array of AnnotationEntry objects.
39 */
40 public static final AnnotationEntry[] EMPTY_ARRAY = {};
41
42 /**
43 * Creates annotation entries from attributes.
44 *
45 * @param attributes the attributes.
46 * @return the annotation entries.
47 */
48 public static AnnotationEntry[] createAnnotationEntries(final Attribute[] attributes) {
49 // Find attributes that contain annotation data
50 return Streams.of(attributes).filter(Annotations.class::isInstance).flatMap(e -> Stream.of(((Annotations) e).getAnnotationEntries()))
51 .toArray(AnnotationEntry[]::new);
52 }
53
54 /**
55 * Factory method to create an AnnotionEntry from a DataInput.
56 *
57 * @param input the input stream.
58 * @param constantPool the constant pool.
59 * @param isRuntimeVisible whether the annotation is runtime visible.
60 * @return the entry.
61 * @throws IOException if an I/O error occurs.
62 */
63 public static AnnotationEntry read(final DataInput input, final ConstantPool constantPool, final boolean isRuntimeVisible) throws IOException {
64 final AnnotationEntry annotationEntry = new AnnotationEntry(input.readUnsignedShort(), constantPool, isRuntimeVisible);
65 final int numElementValuePairs = input.readUnsignedShort();
66 for (int i = 0; i < numElementValuePairs; i++) {
67 annotationEntry.elementValuePairs
68 .add(new ElementValuePair(input.readUnsignedShort(), ElementValue.readElementValue(input, constantPool), constantPool));
69 }
70 return annotationEntry;
71 }
72
73 private final int typeIndex;
74
75 private final ConstantPool constantPool;
76
77 private final boolean isRuntimeVisible;
78
79 private final List<ElementValuePair> elementValuePairs;
80
81 /**
82 * Constructs an AnnotationEntry.
83 *
84 * @param typeIndex the type index.
85 * @param constantPool the constant pool.
86 * @param isRuntimeVisible whether the annotation is runtime visible.
87 */
88 public AnnotationEntry(final int typeIndex, final ConstantPool constantPool, final boolean isRuntimeVisible) {
89 this.typeIndex = typeIndex;
90 this.constantPool = constantPool;
91 this.isRuntimeVisible = isRuntimeVisible;
92 this.elementValuePairs = new ArrayList<>();
93 }
94
95 /**
96 * Called by objects that are traversing the nodes of the tree implicitly defined by the contents of a Java class.
97 * I.e., the hierarchy of methods, fields, attributes, etc. spawns a tree of objects.
98 *
99 * @param v Visitor object.
100 */
101 @Override
102 public void accept(final Visitor v) {
103 v.visitAnnotationEntry(this);
104 }
105
106 /**
107 * Adds an element name value pair.
108 *
109 * @param elementNameValuePair the element name value pair.
110 */
111 public void addElementNameValuePair(final ElementValuePair elementNameValuePair) {
112 elementValuePairs.add(elementNameValuePair);
113 }
114
115 /**
116 * Dumps this annotation entry to a DataOutputStream.
117 *
118 * @param dos the output stream.
119 * @throws IOException if an I/O error occurs.
120 */
121 public void dump(final DataOutputStream dos) throws IOException {
122 dos.writeShort(typeIndex); // u2 index of type name in cpool
123 dos.writeShort(elementValuePairs.size()); // u2 element_value pair
124 // count
125 for (final ElementValuePair envp : elementValuePairs) {
126 envp.dump(dos);
127 }
128 }
129
130 /**
131 * Gets the annotation type name.
132 *
133 * @return the annotation type name.
134 */
135 public String getAnnotationType() {
136 return constantPool.getConstantUtf8(typeIndex).getBytes();
137 }
138
139 /**
140 * Gets the annotation type index.
141 *
142 * @return the annotation type index.
143 */
144 public int getAnnotationTypeIndex() {
145 return typeIndex;
146 }
147
148 /**
149 * Gets the constant pool.
150 *
151 * @return the constant pool.
152 */
153 public ConstantPool getConstantPool() {
154 return constantPool;
155 }
156
157 /**
158 * Gets the element value pairs in this annotation entry.
159 *
160 * @return the element value pairs in this annotation entry.
161 */
162 public ElementValuePair[] getElementValuePairs() {
163 // TODO return List
164 return elementValuePairs.toArray(ElementValuePair.EMPTY_ARRAY);
165 }
166
167 /**
168 * Gets the number of element value pairs in this annotation entry.
169 *
170 * @return the number of element value pairs in this annotation entry.
171 */
172 public final int getNumElementValuePairs() {
173 return elementValuePairs.size();
174 }
175
176 /**
177 * Gets the type index.
178 *
179 * @return the type index.
180 */
181 public int getTypeIndex() {
182 return typeIndex;
183 }
184
185 /**
186 * Gets whether this annotation is runtime visible.
187 *
188 * @return true if this annotation is runtime visible.
189 */
190 public boolean isRuntimeVisible() {
191 return isRuntimeVisible;
192 }
193
194 /**
195 * Gets a short string representation of this annotation.
196 *
197 * @return a short string representation of this annotation.
198 */
199 public String toShortString() {
200 final StringBuilder result = new StringBuilder();
201 result.append("@");
202 result.append(getAnnotationType());
203 final ElementValuePair[] evPairs = getElementValuePairs();
204 if (evPairs.length > 0) {
205 result.append("(");
206 for (final ElementValuePair element : evPairs) {
207 result.append(element.toShortString());
208 result.append(", ");
209 }
210 // remove last ", "
211 result.setLength(result.length() - 2);
212 result.append(")");
213 }
214 return result.toString();
215 }
216
217 @Override
218 public String toString() {
219 return toShortString();
220 }
221 }