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