Constant.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 java.util.Objects;

  22. import org.apache.bcel.Const;
  23. import org.apache.bcel.util.BCELComparator;

  24. /**
  25.  * Abstract superclass for classes to represent the different constant types in the constant pool of a class file. The
  26.  * classes keep closely to the JVM specification.
  27.  */
  28. public abstract class Constant implements Cloneable, Node {

  29.     static final Constant[] EMPTY_ARRAY = {};

  30.     private static BCELComparator<Constant> bcelComparator = new BCELComparator<Constant>() {

  31.         @Override
  32.         public boolean equals(final Constant a, final Constant b) {
  33.             return a == b || a != null && b != null && Objects.equals(a.toString(), b.toString());
  34.         }

  35.         @Override
  36.         public int hashCode(final Constant o) {
  37.             return o != null ? Objects.hashCode(o.toString()) : 0;
  38.         }
  39.     };

  40.     /**
  41.      * @return Comparison strategy object.
  42.      */
  43.     public static BCELComparator<Constant> getComparator() {
  44.         return bcelComparator;
  45.     }

  46.     /**
  47.      * Reads one constant from the given input, the type depends on a tag byte.
  48.      *
  49.      * @param dataInput Input stream
  50.      * @return Constant object
  51.      * @throws IOException if an I/O error occurs reading from the given {@code dataInput}.
  52.      * @throws ClassFormatException if the next byte is not recognized
  53.      * @since 6.0 made public
  54.      */
  55.     public static Constant readConstant(final DataInput dataInput) throws IOException, ClassFormatException {
  56.         final byte b = dataInput.readByte(); // Read tag byte
  57.         switch (b) {
  58.         case Const.CONSTANT_Class:
  59.             return new ConstantClass(dataInput);
  60.         case Const.CONSTANT_Fieldref:
  61.             return new ConstantFieldref(dataInput);
  62.         case Const.CONSTANT_Methodref:
  63.             return new ConstantMethodref(dataInput);
  64.         case Const.CONSTANT_InterfaceMethodref:
  65.             return new ConstantInterfaceMethodref(dataInput);
  66.         case Const.CONSTANT_String:
  67.             return new ConstantString(dataInput);
  68.         case Const.CONSTANT_Integer:
  69.             return new ConstantInteger(dataInput);
  70.         case Const.CONSTANT_Float:
  71.             return new ConstantFloat(dataInput);
  72.         case Const.CONSTANT_Long:
  73.             return new ConstantLong(dataInput);
  74.         case Const.CONSTANT_Double:
  75.             return new ConstantDouble(dataInput);
  76.         case Const.CONSTANT_NameAndType:
  77.             return new ConstantNameAndType(dataInput);
  78.         case Const.CONSTANT_Utf8:
  79.             return ConstantUtf8.getInstance(dataInput);
  80.         case Const.CONSTANT_MethodHandle:
  81.             return new ConstantMethodHandle(dataInput);
  82.         case Const.CONSTANT_MethodType:
  83.             return new ConstantMethodType(dataInput);
  84.         case Const.CONSTANT_Dynamic:
  85.             return new ConstantDynamic(dataInput);
  86.         case Const.CONSTANT_InvokeDynamic:
  87.             return new ConstantInvokeDynamic(dataInput);
  88.         case Const.CONSTANT_Module:
  89.             return new ConstantModule(dataInput);
  90.         case Const.CONSTANT_Package:
  91.             return new ConstantPackage(dataInput);
  92.         default:
  93.             throw new ClassFormatException("Invalid byte tag in constant pool: " + b);
  94.         }
  95.     }

  96.     /**
  97.      * @param comparator Comparison strategy object
  98.      */
  99.     public static void setComparator(final BCELComparator<Constant> comparator) {
  100.         bcelComparator = comparator;
  101.     }

  102.     /*
  103.      * In fact this tag is redundant since we can distinguish different 'Constant' objects by their type, i.e., via
  104.      * 'instanceof'. In some places we will use the tag for switch()es anyway.
  105.      *
  106.      * First, we want match the specification as closely as possible. Second we need the tag as an index to select the
  107.      * corresponding class name from the 'CONSTANT_NAMES' array.
  108.      */
  109.     /**
  110.      * @deprecated (since 6.0) will be made private; do not access directly, use getter/setter
  111.      */
  112.     @java.lang.Deprecated
  113.     protected byte tag; // TODO should be private & final

  114.     Constant(final byte tag) {
  115.         this.tag = tag;
  116.     }

  117.     /**
  118.      * Called by objects that are traversing the nodes of the tree implicitly defined by the contents of a Java class.
  119.      * I.e., the hierarchy of methods, fields, attributes, etc. spawns a tree of objects.
  120.      *
  121.      * @param v Visitor object
  122.      */
  123.     @Override
  124.     public abstract void accept(Visitor v);

  125.     @Override
  126.     public Object clone() {
  127.         try {
  128.             return super.clone();
  129.         } catch (final CloneNotSupportedException e) {
  130.             throw new UnsupportedOperationException("Clone Not Supported", e); // never happens
  131.         }
  132.     }

  133.     /**
  134.      * @return deep copy of this constant
  135.      */
  136.     public Constant copy() {
  137.         try {
  138.             return (Constant) super.clone();
  139.         } catch (final CloneNotSupportedException e) {
  140.             // TODO should this throw?
  141.         }
  142.         return null;
  143.     }

  144.     public abstract void dump(DataOutputStream file) throws IOException;

  145.     /**
  146.      * Returns value as defined by given BCELComparator strategy. By default two Constant objects are said to be equal when
  147.      * the result of toString() is equal.
  148.      *
  149.      * @see Object#equals(Object)
  150.      */
  151.     @Override
  152.     public boolean equals(final Object obj) {
  153.         return obj instanceof Constant && bcelComparator.equals(this, (Constant) obj);
  154.     }

  155.     /**
  156.      * @return Tag of constant, i.e., its type. No setTag() method to avoid confusion.
  157.      */
  158.     public final byte getTag() {
  159.         return tag;
  160.     }

  161.     /**
  162.      * Returns value as defined by given BCELComparator strategy. By default return the hash code of the result of
  163.      * toString().
  164.      *
  165.      * @see Object#hashCode()
  166.      */
  167.     @Override
  168.     public int hashCode() {
  169.         return bcelComparator.hashCode(this);
  170.     }

  171.     /**
  172.      * @return String representation.
  173.      */
  174.     @Override
  175.     public String toString() {
  176.         return Const.getConstantName(tag) + "[" + tag + "]";
  177.     }
  178. }