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  
18  package org.apache.bcel.classfile;
19  
20  import java.io.DataInput;
21  import java.io.DataOutputStream;
22  import java.io.IOException;
23  
24  import org.apache.bcel.Const;
25  
26  /**
27   * The element_value structure is documented at https://docs.oracle.com/javase/specs/jvms/se11/html/jvms-4.html#jvms-4.7.16.1
28   *
29   * <pre>
30   * element_value {
31   *    u1 tag;
32   *    union {
33   *        u2 const_value_index;
34   *
35   *        {   u2 type_name_index;
36   *            u2 const_name_index;
37   *        } enum_const_value;
38   *
39   *        u2 class_info_index;
40   *
41   *        annotation annotation_value;
42   *
43   *        {   u2            num_values;
44   *            element_value values[num_values];
45   *        } array_value;
46   *    } value;
47   *}
48   *</pre>
49   * @since 6.0
50   */
51  public abstract class ElementValue {
52  
53      public static final byte STRING = 's';
54      public static final byte ENUM_CONSTANT = 'e';
55      public static final byte CLASS = 'c';
56      public static final byte ANNOTATION = '@';
57      public static final byte ARRAY = '[';
58      public static final byte PRIMITIVE_INT = 'I';
59      public static final byte PRIMITIVE_BYTE = 'B';
60      public static final byte PRIMITIVE_CHAR = 'C';
61      public static final byte PRIMITIVE_DOUBLE = 'D';
62      public static final byte PRIMITIVE_FLOAT = 'F';
63      public static final byte PRIMITIVE_LONG = 'J';
64      public static final byte PRIMITIVE_SHORT = 'S';
65      public static final byte PRIMITIVE_BOOLEAN = 'Z';
66      static final ElementValue[] EMPTY_ARRAY = {};
67  
68      /**
69       * Reads an {@code element_value} as an {@code ElementValue}.
70       *
71       * @param input Raw data input.
72       * @param cpool Constant pool.
73       * @return a new ElementValue.
74       * @throws IOException if an I/O error occurs.
75       */
76      public static ElementValue readElementValue(final DataInput input, final ConstantPool cpool) throws IOException {
77          return readElementValue(input, cpool, 0);
78      }
79  
80      /**
81       * Reads an {@code element_value} as an {@code ElementValue}.
82       *
83       * @param input Raw data input.
84       * @param cpool Constant pool.
85       * @param arrayNesting level of current array nesting.
86       * @return a new ElementValue.
87       * @throws IOException if an I/O error occurs.
88       * @since 6.7.0
89       */
90      public static ElementValue readElementValue(final DataInput input, final ConstantPool cpool, int arrayNesting)
91              throws IOException {
92          final byte tag = input.readByte();
93          switch (tag) {
94          case PRIMITIVE_BYTE:
95          case PRIMITIVE_CHAR:
96          case PRIMITIVE_DOUBLE:
97          case PRIMITIVE_FLOAT:
98          case PRIMITIVE_INT:
99          case PRIMITIVE_LONG:
100         case PRIMITIVE_SHORT:
101         case PRIMITIVE_BOOLEAN:
102         case STRING:
103             return new SimpleElementValue(tag, input.readUnsignedShort(), cpool);
104 
105         case ENUM_CONSTANT:
106             return new EnumElementValue(ENUM_CONSTANT, input.readUnsignedShort(), input.readUnsignedShort(), cpool);
107 
108         case CLASS:
109             return new ClassElementValue(CLASS, input.readUnsignedShort(), cpool);
110 
111         case ANNOTATION:
112             // TODO isRuntimeVisible
113             return new AnnotationElementValue(ANNOTATION, AnnotationEntry.read(input, cpool, false), cpool);
114 
115         case ARRAY:
116             arrayNesting++;
117             if (arrayNesting > Const.MAX_ARRAY_DIMENSIONS) {
118                 // JVM spec 4.4.1
119                 throw new ClassFormatException(String.format("Arrays are only valid if they represent %,d or fewer dimensions.", Const.MAX_ARRAY_DIMENSIONS));
120             }
121             final int numArrayVals = input.readUnsignedShort();
122             final ElementValue[] evalues = new ElementValue[numArrayVals];
123             for (int j = 0; j < numArrayVals; j++) {
124                 evalues[j] = ElementValue.readElementValue(input, cpool, arrayNesting);
125             }
126             return new ArrayElementValue(ARRAY, evalues, cpool);
127 
128         default:
129             throw new ClassFormatException("Unexpected element value tag in annotation: " + tag);
130         }
131     }
132 
133     /**
134      * @deprecated (since 6.0) will be made private and final; do not access directly, use getter
135      */
136     @java.lang.Deprecated
137     protected int type; // TODO should be final
138     /**
139      * @deprecated (since 6.0) will be made private and final; do not access directly, use getter
140      */
141     @java.lang.Deprecated
142     protected ConstantPool cpool; // TODO should be final
143 
144     protected ElementValue(final int type, final ConstantPool cpool) {
145         this.type = type;
146         this.cpool = cpool;
147     }
148 
149     public abstract void dump(DataOutputStream dos) throws IOException;
150 
151     /** @since 6.0 */
152     final ConstantPool getConstantPool() {
153         return cpool;
154     }
155 
156     public int getElementValueType() {
157         return type;
158     }
159 
160     /** @since 6.0 */
161     final int getType() {
162         return type;
163     }
164 
165     public abstract String stringifyValue();
166 
167     public String toShortString() {
168         return stringifyValue();
169     }
170 
171     @Override
172     public String toString() {
173         return stringifyValue();
174     }
175 }