001/* 002 * Licensed to the Apache Software Foundation (ASF) under one 003 * or more contributor license agreements. See the NOTICE file 004 * distributed with this work for additional information 005 * regarding copyright ownership. The ASF licenses this file 006 * to you under the Apache License, Version 2.0 (the 007 * "License"); you may not use this file except in compliance 008 * with the License. You may obtain a copy of the License at 009 * 010 * https://www.apache.org/licenses/LICENSE-2.0 011 * 012 * Unless required by applicable law or agreed to in writing, 013 * software distributed under the License is distributed on an 014 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 015 * KIND, either express or implied. See the License for the 016 * specific language governing permissions and limitations 017 * under the License. 018 */ 019package org.apache.bcel.classfile; 020 021import java.io.DataInput; 022import java.io.DataOutputStream; 023import java.io.IOException; 024import java.util.Objects; 025 026import org.apache.bcel.Const; 027import org.apache.bcel.util.BCELComparator; 028 029/** 030 * Abstract superclass for classes to represent the different constant types in the constant pool of a class file. The 031 * classes keep closely to the JVM specification. 032 */ 033public abstract class Constant implements Cloneable, Node { 034 035 static final Constant[] EMPTY_ARRAY = {}; 036 037 private static BCELComparator<Constant> bcelComparator = new BCELComparator<Constant>() { 038 039 @Override 040 public boolean equals(final Constant a, final Constant b) { 041 return a == b || a != null && b != null && Objects.equals(a.toString(), b.toString()); 042 } 043 044 @Override 045 public int hashCode(final Constant o) { 046 return o != null ? Objects.hashCode(o.toString()) : 0; 047 } 048 }; 049 050 /** 051 * Gets the comparison strategy object. 052 * 053 * @return Comparison strategy object. 054 */ 055 public static BCELComparator<Constant> getComparator() { 056 return bcelComparator; 057 } 058 059 /** 060 * Reads one constant from the given input, the type depends on a tag byte. 061 * 062 * @param dataInput Input stream. 063 * @return Constant object. 064 * @throws IOException if an I/O error occurs reading from the given {@code dataInput}. 065 * @throws ClassFormatException if the next byte is not recognized 066 * @since 6.0 made public 067 */ 068 public static Constant readConstant(final DataInput dataInput) throws IOException, ClassFormatException { 069 final byte b = dataInput.readByte(); // Read tag byte 070 switch (b) { 071 case Const.CONSTANT_Class: 072 return new ConstantClass(dataInput); 073 case Const.CONSTANT_Fieldref: 074 return new ConstantFieldref(dataInput); 075 case Const.CONSTANT_Methodref: 076 return new ConstantMethodref(dataInput); 077 case Const.CONSTANT_InterfaceMethodref: 078 return new ConstantInterfaceMethodref(dataInput); 079 case Const.CONSTANT_String: 080 return new ConstantString(dataInput); 081 case Const.CONSTANT_Integer: 082 return new ConstantInteger(dataInput); 083 case Const.CONSTANT_Float: 084 return new ConstantFloat(dataInput); 085 case Const.CONSTANT_Long: 086 return new ConstantLong(dataInput); 087 case Const.CONSTANT_Double: 088 return new ConstantDouble(dataInput); 089 case Const.CONSTANT_NameAndType: 090 return new ConstantNameAndType(dataInput); 091 case Const.CONSTANT_Utf8: 092 return ConstantUtf8.getInstance(dataInput); 093 case Const.CONSTANT_MethodHandle: 094 return new ConstantMethodHandle(dataInput); 095 case Const.CONSTANT_MethodType: 096 return new ConstantMethodType(dataInput); 097 case Const.CONSTANT_Dynamic: 098 return new ConstantDynamic(dataInput); 099 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}