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