ElementValue.java

  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. import java.io.DataInput;
  19. import java.io.DataOutputStream;
  20. import java.io.IOException;

  21. import org.apache.bcel.Const;

  22. /**
  23.  * The element_value structure is documented at https://docs.oracle.com/javase/specs/jvms/se11/html/jvms-4.html#jvms-4.7.16.1
  24.  *
  25.  * <pre>
  26.  * element_value {
  27.  *    u1 tag;
  28.  *    union {
  29.  *        u2 const_value_index;
  30.  *
  31.  *        {   u2 type_name_index;
  32.  *            u2 const_name_index;
  33.  *        } enum_const_value;
  34.  *
  35.  *        u2 class_info_index;
  36.  *
  37.  *        annotation annotation_value;
  38.  *
  39.  *        {   u2            num_values;
  40.  *            element_value values[num_values];
  41.  *        } array_value;
  42.  *    } value;
  43.  *}
  44.  *</pre>
  45.  * @since 6.0
  46.  */
  47. public abstract class ElementValue {

  48.     public static final byte STRING = 's';
  49.     public static final byte ENUM_CONSTANT = 'e';
  50.     public static final byte CLASS = 'c';
  51.     public static final byte ANNOTATION = '@';
  52.     public static final byte ARRAY = '[';
  53.     public static final byte PRIMITIVE_INT = 'I';
  54.     public static final byte PRIMITIVE_BYTE = 'B';
  55.     public static final byte PRIMITIVE_CHAR = 'C';
  56.     public static final byte PRIMITIVE_DOUBLE = 'D';
  57.     public static final byte PRIMITIVE_FLOAT = 'F';
  58.     public static final byte PRIMITIVE_LONG = 'J';
  59.     public static final byte PRIMITIVE_SHORT = 'S';
  60.     public static final byte PRIMITIVE_BOOLEAN = 'Z';
  61.     static final ElementValue[] EMPTY_ARRAY = {};

  62.     /**
  63.      * Reads an {@code element_value} as an {@code ElementValue}.
  64.      *
  65.      * @param input Raw data input.
  66.      * @param cpool Constant pool.
  67.      * @return a new ElementValue.
  68.      * @throws IOException if an I/O error occurs.
  69.      */
  70.     public static ElementValue readElementValue(final DataInput input, final ConstantPool cpool) throws IOException {
  71.         return readElementValue(input, cpool, 0);
  72.     }

  73.     /**
  74.      * Reads an {@code element_value} as an {@code ElementValue}.
  75.      *
  76.      * @param input Raw data input.
  77.      * @param cpool Constant pool.
  78.      * @param arrayNesting level of current array nesting.
  79.      * @return a new ElementValue.
  80.      * @throws IOException if an I/O error occurs.
  81.      * @since 6.7.0
  82.      */
  83.     public static ElementValue readElementValue(final DataInput input, final ConstantPool cpool, int arrayNesting)
  84.             throws IOException {
  85.         final byte tag = input.readByte();
  86.         switch (tag) {
  87.         case PRIMITIVE_BYTE:
  88.         case PRIMITIVE_CHAR:
  89.         case PRIMITIVE_DOUBLE:
  90.         case PRIMITIVE_FLOAT:
  91.         case PRIMITIVE_INT:
  92.         case PRIMITIVE_LONG:
  93.         case PRIMITIVE_SHORT:
  94.         case PRIMITIVE_BOOLEAN:
  95.         case STRING:
  96.             return new SimpleElementValue(tag, input.readUnsignedShort(), cpool);

  97.         case ENUM_CONSTANT:
  98.             return new EnumElementValue(ENUM_CONSTANT, input.readUnsignedShort(), input.readUnsignedShort(), cpool);

  99.         case CLASS:
  100.             return new ClassElementValue(CLASS, input.readUnsignedShort(), cpool);

  101.         case ANNOTATION:
  102.             // TODO isRuntimeVisible
  103.             return new AnnotationElementValue(ANNOTATION, AnnotationEntry.read(input, cpool, false), cpool);

  104.         case ARRAY:
  105.             arrayNesting++;
  106.             if (arrayNesting > Const.MAX_ARRAY_DIMENSIONS) {
  107.                 // JVM spec 4.4.1
  108.                 throw new ClassFormatException(String.format("Arrays are only valid if they represent %,d or fewer dimensions.", Const.MAX_ARRAY_DIMENSIONS));
  109.             }
  110.             final int numArrayVals = input.readUnsignedShort();
  111.             final ElementValue[] evalues = new ElementValue[numArrayVals];
  112.             for (int j = 0; j < numArrayVals; j++) {
  113.                 evalues[j] = readElementValue(input, cpool, arrayNesting);
  114.             }
  115.             return new ArrayElementValue(ARRAY, evalues, cpool);

  116.         default:
  117.             throw new ClassFormatException("Unexpected element value tag in annotation: " + tag);
  118.         }
  119.     }

  120.     /**
  121.      * @deprecated (since 6.0) will be made private and final; do not access directly, use getter
  122.      */
  123.     @java.lang.Deprecated
  124.     protected int type; // TODO should be final
  125.     /**
  126.      * @deprecated (since 6.0) will be made private and final; do not access directly, use getter
  127.      */
  128.     @java.lang.Deprecated
  129.     protected ConstantPool cpool; // TODO should be final

  130.     protected ElementValue(final int type, final ConstantPool cpool) {
  131.         this.type = type;
  132.         this.cpool = cpool;
  133.     }

  134.     public abstract void dump(DataOutputStream dos) throws IOException;

  135.     /** @since 6.0 */
  136.     final ConstantPool getConstantPool() {
  137.         return cpool;
  138.     }

  139.     public int getElementValueType() {
  140.         return type;
  141.     }

  142.     /** @since 6.0 */
  143.     final int getType() {
  144.         return type;
  145.     }

  146.     public abstract String stringifyValue();

  147.     public String toShortString() {
  148.         return stringifyValue();
  149.     }

  150.     @Override
  151.     public String toString() {
  152.         return stringifyValue();
  153.     }
  154. }