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  
20  package org.apache.bcel.classfile;
21  
22  import java.io.DataInput;
23  import java.io.DataOutputStream;
24  import java.io.IOException;
25  
26  import org.apache.bcel.Const;
27  
28  /**
29   * The element_value structure is documented at https://docs.oracle.com/javase/specs/jvms/se11/html/jvms-4.html#jvms-4.7.16.1
30   *
31   * <pre>
32   * element_value {
33   *    u1 tag;
34   *    union {
35   *        u2 const_value_index;
36   *
37   *        {   u2 type_name_index;
38   *            u2 const_name_index;
39   *        } enum_const_value;
40   *
41   *        u2 class_info_index;
42   *
43   *        annotation annotation_value;
44   *
45   *        {   u2            num_values;
46   *            element_value values[num_values];
47   *        } array_value;
48   *    } value;
49   *}
50   *</pre>
51   *
52   * @since 6.0
53   */
54  public abstract class ElementValue {
55  
56      /** Element value type: string. */
57      public static final byte STRING = 's';
58  
59      /** Element value type: enum constant. */
60      public static final byte ENUM_CONSTANT = 'e';
61  
62      /** Element value type: class. */
63      public static final byte CLASS = 'c';
64  
65      /** Element value type: annotation. */
66      public static final byte ANNOTATION = '@';
67  
68      /** Element value type: array. */
69      public static final byte ARRAY = '[';
70  
71      /** Element value type: primitive int. */
72      public static final byte PRIMITIVE_INT = 'I';
73  
74      /** Element value type: primitive byte. */
75      public static final byte PRIMITIVE_BYTE = 'B';
76  
77      /** Element value type: primitive char. */
78      public static final byte PRIMITIVE_CHAR = 'C';
79  
80      /** Element value type: primitive double. */
81      public static final byte PRIMITIVE_DOUBLE = 'D';
82  
83      /** Element value type: primitive float. */
84      public static final byte PRIMITIVE_FLOAT = 'F';
85  
86      /** Element value type: primitive long. */
87      public static final byte PRIMITIVE_LONG = 'J';
88  
89      /** Element value type: primitive short. */
90      public static final byte PRIMITIVE_SHORT = 'S';
91  
92      /** Element value type: primitive boolean. */
93      public static final byte PRIMITIVE_BOOLEAN = 'Z';
94  
95      /** Empty array constant. */
96      static final ElementValue[] EMPTY_ARRAY = {};
97  
98      /**
99       * Reads an {@code element_value} as an {@code ElementValue}.
100      *
101      * @param input Raw data input.
102      * @param cpool Constant pool.
103      * @return a new ElementValue.
104      * @throws IOException if an I/O error occurs.
105      */
106     public static ElementValue readElementValue(final DataInput input, final ConstantPool cpool) throws IOException {
107         return readElementValue(input, cpool, 0);
108     }
109 
110     /**
111      * Reads an {@code element_value} as an {@code ElementValue}.
112      *
113      * @param input Raw data input.
114      * @param cpool Constant pool.
115      * @param arrayNesting level of current array nesting.
116      * @return a new ElementValue.
117      * @throws IOException if an I/O error occurs.
118      * @since 6.7.0
119      */
120     public static ElementValue readElementValue(final DataInput input, final ConstantPool cpool, int arrayNesting)
121             throws IOException {
122         final byte tag = input.readByte();
123         switch (tag) {
124         case PRIMITIVE_BYTE:
125         case PRIMITIVE_CHAR:
126         case PRIMITIVE_DOUBLE:
127         case PRIMITIVE_FLOAT:
128         case PRIMITIVE_INT:
129         case PRIMITIVE_LONG:
130         case PRIMITIVE_SHORT:
131         case PRIMITIVE_BOOLEAN:
132         case STRING:
133             return new SimpleElementValue(tag, input.readUnsignedShort(), cpool);
134 
135         case ENUM_CONSTANT:
136             return new EnumElementValue(ENUM_CONSTANT, input.readUnsignedShort(), input.readUnsignedShort(), cpool);
137 
138         case CLASS:
139             return new ClassElementValue(CLASS, input.readUnsignedShort(), cpool);
140 
141         case ANNOTATION:
142             // TODO isRuntimeVisible
143             return new AnnotationElementValue(ANNOTATION, AnnotationEntry.read(input, cpool, false), cpool);
144 
145         case ARRAY:
146             arrayNesting++;
147             if (arrayNesting > Const.MAX_ARRAY_DIMENSIONS) {
148                 // JVM spec 4.4.1
149                 throw new ClassFormatException(String.format("Arrays are only valid if they represent %,d or fewer dimensions.", Const.MAX_ARRAY_DIMENSIONS));
150             }
151             final int numArrayVals = input.readUnsignedShort();
152             final ElementValue[] evalues = new ElementValue[numArrayVals];
153             for (int j = 0; j < numArrayVals; j++) {
154                 evalues[j] = readElementValue(input, cpool, arrayNesting);
155             }
156             return new ArrayElementValue(ARRAY, evalues, cpool);
157 
158         default:
159             throw new ClassFormatException("Unexpected element value tag in annotation: " + tag);
160         }
161     }
162 
163     /**
164      * @deprecated (since 6.0) will be made private and final; do not access directly, use getter.
165      */
166     @java.lang.Deprecated
167     protected int type; // TODO should be final
168 
169     /**
170      * @deprecated (since 6.0) will be made private and final; do not access directly, use getter.
171      */
172     @java.lang.Deprecated
173     protected ConstantPool cpool; // TODO should be final
174 
175     /**
176      * Constructs an ElementValue.
177      *
178      * @param type the element value type.
179      * @param cpool the constant pool.
180      */
181     protected ElementValue(final int type, final ConstantPool cpool) {
182         this.type = type;
183         this.cpool = cpool;
184     }
185 
186     /**
187      * Dumps this element value to a DataOutputStream.
188      *
189      * @param dos the output stream.
190      * @throws IOException if an I/O error occurs.
191      */
192     public abstract void dump(DataOutputStream dos) throws IOException;
193 
194     /**
195      * Gets the constant pool.
196      *
197      * @return the constant pool.
198      * @since 6.0
199      */
200     final ConstantPool getConstantPool() {
201         return cpool;
202     }
203 
204     /**
205      * Gets the element value type.
206      *
207      * @return the element value type.
208      */
209     public int getElementValueType() {
210         return type;
211     }
212 
213     /**
214      * Gets the type.
215      *
216      * @return the type.
217      * @since 6.0
218      */
219     final int getType() {
220         return type;
221     }
222 
223     /**
224      * Returns a string representation of the element value.
225      *
226      * @return a string representation of the element value.
227      */
228     public abstract String stringifyValue();
229 
230     /**
231      * Returns a short string representation of the element value.
232      *
233      * @return a short string representation of the element value.
234      */
235     public String toShortString() {
236         return stringifyValue();
237     }
238 
239     /**
240      * Returns a string representation of the element value.
241      *
242      * @return a string representation of the element value.
243      */
244     @Override
245     public String toString() {
246         return stringifyValue();
247     }
248 }