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  package org.apache.bcel.classfile;
20  
21  import java.io.DataInput;
22  import java.io.DataOutputStream;
23  import java.io.IOException;
24  import java.util.Objects;
25  
26  import org.apache.bcel.Const;
27  import org.apache.bcel.util.BCELComparator;
28  
29  /**
30   * Abstract superclass for classes to represent the different constant types in the constant pool of a class file. The
31   * classes keep closely to the JVM specification.
32   */
33  public abstract class Constant implements Cloneable, Node {
34  
35      static final Constant[] EMPTY_ARRAY = {};
36  
37      private static BCELComparator<Constant> bcelComparator = new BCELComparator<Constant>() {
38  
39          @Override
40          public boolean equals(final Constant a, final Constant b) {
41              return a == b || a != null && b != null && Objects.equals(a.toString(), b.toString());
42          }
43  
44          @Override
45          public int hashCode(final Constant o) {
46              return o != null ? Objects.hashCode(o.toString()) : 0;
47          }
48      };
49  
50      /**
51       * Gets the comparison strategy object.
52       *
53       * @return Comparison strategy object.
54       */
55      public static BCELComparator<Constant> getComparator() {
56          return bcelComparator;
57      }
58  
59      /**
60       * Reads one constant from the given input, the type depends on a tag byte.
61       *
62       * @param dataInput Input stream.
63       * @return Constant object.
64       * @throws IOException if an I/O error occurs reading from the given {@code dataInput}.
65       * @throws ClassFormatException if the next byte is not recognized
66       * @since 6.0 made public
67       */
68      public static Constant readConstant(final DataInput dataInput) throws IOException, ClassFormatException {
69          final byte b = dataInput.readByte(); // Read tag byte
70          switch (b) {
71          case Const.CONSTANT_Class:
72              return new ConstantClass(dataInput);
73          case Const.CONSTANT_Fieldref:
74              return new ConstantFieldref(dataInput);
75          case Const.CONSTANT_Methodref:
76              return new ConstantMethodref(dataInput);
77          case Const.CONSTANT_InterfaceMethodref:
78              return new ConstantInterfaceMethodref(dataInput);
79          case Const.CONSTANT_String:
80              return new ConstantString(dataInput);
81          case Const.CONSTANT_Integer:
82              return new ConstantInteger(dataInput);
83          case Const.CONSTANT_Float:
84              return new ConstantFloat(dataInput);
85          case Const.CONSTANT_Long:
86              return new ConstantLong(dataInput);
87          case Const.CONSTANT_Double:
88              return new ConstantDouble(dataInput);
89          case Const.CONSTANT_NameAndType:
90              return new ConstantNameAndType(dataInput);
91          case Const.CONSTANT_Utf8:
92              return ConstantUtf8.getInstance(dataInput);
93          case Const.CONSTANT_MethodHandle:
94              return new ConstantMethodHandle(dataInput);
95          case Const.CONSTANT_MethodType:
96              return new ConstantMethodType(dataInput);
97          case Const.CONSTANT_Dynamic:
98              return new ConstantDynamic(dataInput);
99          case Const.CONSTANT_InvokeDynamic:
100             return new ConstantInvokeDynamic(dataInput);
101         case Const.CONSTANT_Module:
102             return new ConstantModule(dataInput);
103         case Const.CONSTANT_Package:
104             return new ConstantPackage(dataInput);
105         default:
106             throw new ClassFormatException("Invalid byte tag in constant pool: " + b);
107         }
108     }
109 
110     /**
111      * Sets the comparison strategy object.
112      *
113      * @param comparator Comparison strategy object.
114      */
115     public static void setComparator(final BCELComparator<Constant> comparator) {
116         bcelComparator = comparator;
117     }
118 
119     /*
120      * In fact this tag is redundant since we can distinguish different 'Constant' objects by their type, that is, via
121      * 'instanceof'. In some places we will use the tag for switch()es anyway.
122      *
123      * First, we want match the specification as closely as possible. Second we need the tag as an index to select the
124      * corresponding class name from the 'CONSTANT_NAMES' array.
125      */
126 
127     /**
128      * @deprecated (since 6.0) will be made private; do not access directly, use getter/setter.
129      */
130     @java.lang.Deprecated
131     protected byte tag; // TODO should be private & final
132 
133     Constant(final byte tag) {
134         this.tag = tag;
135     }
136 
137     /**
138      * Called by objects that are traversing the nodes of the tree implicitly defined by the contents of a Java class.
139      * I.e., the hierarchy of methods, fields, attributes, etc. spawns a tree of objects.
140      *
141      * @param v Visitor object.
142      */
143     @Override
144     public abstract void accept(Visitor v);
145 
146     @Override
147     public Object clone() {
148         try {
149             return super.clone();
150         } catch (final CloneNotSupportedException e) {
151             throw new UnsupportedOperationException("Clone Not Supported", e); // never happens
152         }
153     }
154 
155     /**
156      * Creates a deep copy of this constant.
157      *
158      * @return deep copy of this constant.
159      */
160     public Constant copy() {
161         try {
162             return (Constant) super.clone();
163         } catch (final CloneNotSupportedException e) {
164             // TODO should this throw?
165         }
166         return null;
167     }
168 
169     /**
170      * Dumps constant to file stream in binary format.
171      *
172      * @param file the output stream.
173      * @throws IOException if an I/O error occurs.
174      */
175     public abstract void dump(DataOutputStream file) throws IOException;
176 
177     /**
178      * Returns value as defined by given BCELComparator strategy. By default two Constant objects are said to be equal when
179      * the result of toString() is equal.
180      *
181      * @see Object#equals(Object)
182      */
183     @Override
184     public boolean equals(final Object obj) {
185         return obj instanceof Constant && bcelComparator.equals(this, (Constant) obj);
186     }
187 
188     /**
189      * Gets the tag of constant.
190      *
191      * @return Tag of constant, that is, its type. No setTag() method to avoid confusion.
192      */
193     public final byte getTag() {
194         return tag;
195     }
196 
197     /**
198      * Returns value as defined by given BCELComparator strategy. By default return the hash code of the result of
199      * toString().
200      *
201      * @see Object#hashCode()
202      */
203     @Override
204     public int hashCode() {
205         return bcelComparator.hashCode(this);
206     }
207 
208     /**
209      * @return String representation.
210      */
211     @Override
212     public String toString() {
213         return Const.getConstantName(tag) + "[" + tag + "]";
214     }
215 }