View Javadoc
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      public static final AnnotationEntry[] EMPTY_ARRAY = {};
38  
39      public static AnnotationEntry[] createAnnotationEntries(final Attribute[] attributes) {
40          // Find attributes that contain annotation data
41          return Streams.of(attributes).filter(Annotations.class::isInstance).flatMap(e -> Stream.of(((Annotations) e).getAnnotationEntries()))
42                  .toArray(AnnotationEntry[]::new);
43      }
44  
45      /**
46       * Factory method to create an AnnotionEntry from a DataInput
47       *
48       * @param input
49       * @param constantPool
50       * @param isRuntimeVisible
51       * @return the entry
52       * @throws IOException if an I/O error occurs.
53       */
54      public static AnnotationEntry read(final DataInput input, final ConstantPool constantPool, final boolean isRuntimeVisible) throws IOException {
55          final AnnotationEntry annotationEntry = new AnnotationEntry(input.readUnsignedShort(), constantPool, isRuntimeVisible);
56          final int numElementValuePairs = input.readUnsignedShort();
57          for (int i = 0; i < numElementValuePairs; i++) {
58              annotationEntry.elementValuePairs
59                  .add(new ElementValuePair(input.readUnsignedShort(), ElementValue.readElementValue(input, constantPool), constantPool));
60          }
61          return annotationEntry;
62      }
63  
64      private final int typeIndex;
65  
66      private final ConstantPool constantPool;
67  
68      private final boolean isRuntimeVisible;
69  
70      private final List<ElementValuePair> elementValuePairs;
71  
72      public AnnotationEntry(final int typeIndex, final ConstantPool constantPool, final boolean isRuntimeVisible) {
73          this.typeIndex = typeIndex;
74          this.constantPool = constantPool;
75          this.isRuntimeVisible = isRuntimeVisible;
76          this.elementValuePairs = new ArrayList<>();
77      }
78  
79      /**
80       * Called by objects that are traversing the nodes of the tree implicitly defined by the contents of a Java class.
81       * I.e., the hierarchy of methods, fields, attributes, etc. spawns a tree of objects.
82       *
83       * @param v Visitor object
84       */
85      @Override
86      public void accept(final Visitor v) {
87          v.visitAnnotationEntry(this);
88      }
89  
90      public void addElementNameValuePair(final ElementValuePair elementNameValuePair) {
91          elementValuePairs.add(elementNameValuePair);
92      }
93  
94      public void dump(final DataOutputStream dos) throws IOException {
95          dos.writeShort(typeIndex); // u2 index of type name in cpool
96          dos.writeShort(elementValuePairs.size()); // u2 element_value pair
97          // count
98          for (final ElementValuePair envp : elementValuePairs) {
99              envp.dump(dos);
100         }
101     }
102 
103     /**
104      * @return the annotation type name
105      */
106     public String getAnnotationType() {
107         return constantPool.getConstantUtf8(typeIndex).getBytes();
108     }
109 
110     /**
111      * @return the annotation type index
112      */
113     public int getAnnotationTypeIndex() {
114         return typeIndex;
115     }
116 
117     public ConstantPool getConstantPool() {
118         return constantPool;
119     }
120 
121     /**
122      * @return the element value pairs in this annotation entry
123      */
124     public ElementValuePair[] getElementValuePairs() {
125         // TODO return List
126         return elementValuePairs.toArray(ElementValuePair.EMPTY_ARRAY);
127     }
128 
129     /**
130      * @return the number of element value pairs in this annotation entry
131      */
132     public final int getNumElementValuePairs() {
133         return elementValuePairs.size();
134     }
135 
136     public int getTypeIndex() {
137         return typeIndex;
138     }
139 
140     public boolean isRuntimeVisible() {
141         return isRuntimeVisible;
142     }
143 
144     public String toShortString() {
145         final StringBuilder result = new StringBuilder();
146         result.append("@");
147         result.append(getAnnotationType());
148         final ElementValuePair[] evPairs = getElementValuePairs();
149         if (evPairs.length > 0) {
150             result.append("(");
151             for (final ElementValuePair element : evPairs) {
152                 result.append(element.toShortString());
153                 result.append(", ");
154             }
155             // remove last ", "
156             result.setLength(result.length() - 2);
157             result.append(")");
158         }
159         return result.toString();
160     }
161 
162     @Override
163     public String toString() {
164         return toShortString();
165     }
166 }