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   * @since 6.0
52   */
53  public abstract class ElementValue {
54  
55      public static final byte STRING = 's';
56      public static final byte ENUM_CONSTANT = 'e';
57      public static final byte CLASS = 'c';
58      public static final byte ANNOTATION = '@';
59      public static final byte ARRAY = '[';
60      public static final byte PRIMITIVE_INT = 'I';
61      public static final byte PRIMITIVE_BYTE = 'B';
62      public static final byte PRIMITIVE_CHAR = 'C';
63      public static final byte PRIMITIVE_DOUBLE = 'D';
64      public static final byte PRIMITIVE_FLOAT = 'F';
65      public static final byte PRIMITIVE_LONG = 'J';
66      public static final byte PRIMITIVE_SHORT = 'S';
67      public static final byte PRIMITIVE_BOOLEAN = 'Z';
68      static final ElementValue[] EMPTY_ARRAY = {};
69  
70      /**
71       * Reads an {@code element_value} as an {@code ElementValue}.
72       *
73       * @param input Raw data input.
74       * @param cpool Constant pool.
75       * @return a new ElementValue.
76       * @throws IOException if an I/O error occurs.
77       */
78      public static ElementValue readElementValue(final DataInput input, final ConstantPool cpool) throws IOException {
79          return readElementValue(input, cpool, 0);
80      }
81  
82      /**
83       * Reads an {@code element_value} as an {@code ElementValue}.
84       *
85       * @param input Raw data input.
86       * @param cpool Constant pool.
87       * @param arrayNesting level of current array nesting.
88       * @return a new ElementValue.
89       * @throws IOException if an I/O error occurs.
90       * @since 6.7.0
91       */
92      public static ElementValue readElementValue(final DataInput input, final ConstantPool cpool, int arrayNesting)
93              throws IOException {
94          final byte tag = input.readByte();
95          switch (tag) {
96          case PRIMITIVE_BYTE:
97          case PRIMITIVE_CHAR:
98          case PRIMITIVE_DOUBLE:
99          case PRIMITIVE_FLOAT:
100         case PRIMITIVE_INT:
101         case PRIMITIVE_LONG:
102         case PRIMITIVE_SHORT:
103         case PRIMITIVE_BOOLEAN:
104         case STRING:
105             return new SimpleElementValue(tag, input.readUnsignedShort(), cpool);
106 
107         case ENUM_CONSTANT:
108             return new EnumElementValue(ENUM_CONSTANT, input.readUnsignedShort(), input.readUnsignedShort(), cpool);
109 
110         case CLASS:
111             return new ClassElementValue(CLASS, input.readUnsignedShort(), cpool);
112 
113         case ANNOTATION:
114             // TODO isRuntimeVisible
115             return new AnnotationElementValue(ANNOTATION, AnnotationEntry.read(input, cpool, false), cpool);
116 
117         case ARRAY:
118             arrayNesting++;
119             if (arrayNesting > Const.MAX_ARRAY_DIMENSIONS) {
120                 // JVM spec 4.4.1
121                 throw new ClassFormatException(String.format("Arrays are only valid if they represent %,d or fewer dimensions.", Const.MAX_ARRAY_DIMENSIONS));
122             }
123             final int numArrayVals = input.readUnsignedShort();
124             final ElementValue[] evalues = new ElementValue[numArrayVals];
125             for (int j = 0; j < numArrayVals; j++) {
126                 evalues[j] = readElementValue(input, cpool, arrayNesting);
127             }
128             return new ArrayElementValue(ARRAY, evalues, cpool);
129 
130         default:
131             throw new ClassFormatException("Unexpected element value tag in annotation: " + tag);
132         }
133     }
134 
135     /**
136      * @deprecated (since 6.0) will be made private and final; do not access directly, use getter
137      */
138     @java.lang.Deprecated
139     protected int type; // TODO should be final
140     /**
141      * @deprecated (since 6.0) will be made private and final; do not access directly, use getter
142      */
143     @java.lang.Deprecated
144     protected ConstantPool cpool; // TODO should be final
145 
146     protected ElementValue(final int type, final ConstantPool cpool) {
147         this.type = type;
148         this.cpool = cpool;
149     }
150 
151     public abstract void dump(DataOutputStream dos) throws IOException;
152 
153     /** @since 6.0 */
154     final ConstantPool getConstantPool() {
155         return cpool;
156     }
157 
158     public int getElementValueType() {
159         return type;
160     }
161 
162     /** @since 6.0 */
163     final int getType() {
164         return type;
165     }
166 
167     public abstract String stringifyValue();
168 
169     public String toShortString() {
170         return stringifyValue();
171     }
172 
173     @Override
174     public String toString() {
175         return stringifyValue();
176     }
177 }