001/* 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache License, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 * 017 */ 018package org.apache.bcel.classfile; 019 020import java.io.DataInput; 021import java.io.DataOutputStream; 022import java.io.IOException; 023import java.util.Objects; 024 025import org.apache.bcel.Const; 026import org.apache.bcel.util.BCELComparator; 027 028/** 029 * Abstract superclass for classes to represent the different constant types 030 * in the constant pool of a class file. The classes keep closely to 031 * the JVM specification. 032 * 033 * @version $Id$ 034 */ 035public abstract class Constant implements Cloneable, Node { 036 037 private static BCELComparator bcelComparator = new BCELComparator() { 038 039 @Override 040 public boolean equals( final Object o1, final Object o2 ) { 041 final Constant THIS = (Constant) o1; 042 final Constant THAT = (Constant) o2; 043 return Objects.equals(THIS.toString(), THAT.toString()); 044 } 045 046 047 @Override 048 public int hashCode( final Object o ) { 049 final Constant THIS = (Constant) o; 050 return THIS.toString().hashCode(); 051 } 052 }; 053 /* In fact this tag is redundant since we can distinguish different 054 * `Constant' objects by their type, i.e., via `instanceof'. In some 055 * places we will use the tag for switch()es anyway. 056 * 057 * First, we want match the specification as closely as possible. Second we 058 * need the tag as an index to select the corresponding class name from the 059 * `CONSTANT_NAMES' array. 060 */ 061 /** 062 * @deprecated (since 6.0) will be made private; do not access directly, use getter/setter 063 */ 064 @java.lang.Deprecated 065 protected byte tag; // TODO should be private & final 066 067 068 Constant(final byte tag) { 069 this.tag = tag; 070 } 071 072 073 /** 074 * Called by objects that are traversing the nodes of the tree implicitely 075 * defined by the contents of a Java class. I.e., the hierarchy of methods, 076 * fields, attributes, etc. spawns a tree of objects. 077 * 078 * @param v Visitor object 079 */ 080 @Override 081 public abstract void accept( Visitor v ); 082 083 084 public abstract void dump( DataOutputStream file ) throws IOException; 085 086 087 /** 088 * @return Tag of constant, i.e., its type. No setTag() method to avoid 089 * confusion. 090 */ 091 public final byte getTag() { 092 return tag; 093 } 094 095 096 /** 097 * @return String representation. 098 */ 099 @Override 100 public String toString() { 101 return Const.getConstantName(tag) + "[" + tag + "]"; 102 } 103 104 105 /** 106 * @return deep copy of this constant 107 */ 108 public Constant copy() { 109 try { 110 return (Constant) super.clone(); 111 } catch (final CloneNotSupportedException e) { 112 // TODO should this throw? 113 } 114 return null; 115 } 116 117 118 @Override 119 public Object clone() { 120 try { 121 return super.clone(); 122 } catch (final CloneNotSupportedException e) { 123 throw new Error("Clone Not Supported"); // never happens 124 } 125 } 126 127 128 /** 129 * Read one constant from the given input, the type depends on a tag byte. 130 * 131 * @param dataInput Input stream 132 * @return Constant object 133 * @throws IOException if an I/O error occurs reading from the given {@code dataInput}. 134 * @throws ClassFormatException if the next byte is not recognized 135 * @since 6.0 made public 136 */ 137 public static Constant readConstant(final DataInput dataInput) throws IOException, ClassFormatException { 138 final byte b = dataInput.readByte(); // Read tag byte 139 switch (b) { 140 case Const.CONSTANT_Class: 141 return new ConstantClass(dataInput); 142 case Const.CONSTANT_Fieldref: 143 return new ConstantFieldref(dataInput); 144 case Const.CONSTANT_Methodref: 145 return new ConstantMethodref(dataInput); 146 case Const.CONSTANT_InterfaceMethodref: 147 return new ConstantInterfaceMethodref(dataInput); 148 case Const.CONSTANT_String: 149 return new ConstantString(dataInput); 150 case Const.CONSTANT_Integer: 151 return new ConstantInteger(dataInput); 152 case Const.CONSTANT_Float: 153 return new ConstantFloat(dataInput); 154 case Const.CONSTANT_Long: 155 return new ConstantLong(dataInput); 156 case Const.CONSTANT_Double: 157 return new ConstantDouble(dataInput); 158 case Const.CONSTANT_NameAndType: 159 return new ConstantNameAndType(dataInput); 160 case Const.CONSTANT_Utf8: 161 return ConstantUtf8.getInstance(dataInput); 162 case Const.CONSTANT_MethodHandle: 163 return new ConstantMethodHandle(dataInput); 164 case Const.CONSTANT_MethodType: 165 return new ConstantMethodType(dataInput); 166 case Const.CONSTANT_Dynamic: 167 return new ConstantDynamic(dataInput); 168 case Const.CONSTANT_InvokeDynamic: 169 return new ConstantInvokeDynamic(dataInput); 170 case Const.CONSTANT_Module: 171 return new ConstantModule(dataInput); 172 case Const.CONSTANT_Package: 173 return new ConstantPackage(dataInput); 174 default: 175 throw new ClassFormatException("Invalid byte tag in constant pool: " + b); 176 } 177 } 178 179 /** 180 * @return Comparison strategy object 181 */ 182 public static BCELComparator getComparator() { 183 return bcelComparator; 184 } 185 186 187 /** 188 * @param comparator Comparison strategy object 189 */ 190 public static void setComparator( final BCELComparator comparator ) { 191 bcelComparator = comparator; 192 } 193 194 195 /** 196 * Return value as defined by given BCELComparator strategy. 197 * By default two Constant objects are said to be equal when 198 * the result of toString() is equal. 199 * 200 * @see java.lang.Object#equals(java.lang.Object) 201 */ 202 @Override 203 public boolean equals( final Object obj ) { 204 return bcelComparator.equals(this, obj); 205 } 206 207 208 /** 209 * Return value as defined by given BCELComparator strategy. 210 * By default return the hashcode of the result of toString(). 211 * 212 * @see java.lang.Object#hashCode() 213 */ 214 @Override 215 public int hashCode() { 216 return bcelComparator.hashCode(this); 217 } 218}