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