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 }