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 */ 033public abstract class Constant implements Cloneable, Node { 034 035 private static BCELComparator bcelComparator = new BCELComparator() { 036 037 @Override 038 public boolean equals( final Object o1, final Object o2 ) { 039 final Constant THIS = (Constant) o1; 040 final Constant THAT = (Constant) o2; 041 return Objects.equals(THIS.toString(), THAT.toString()); 042 } 043 044 045 @Override 046 public int hashCode( final Object o ) { 047 final Constant THIS = (Constant) o; 048 return THIS.toString().hashCode(); 049 } 050 }; 051 052 /* In fact this tag is redundant since we can distinguish different 053 * `Constant' objects by their type, i.e., via `instanceof'. In some 054 * places we will use the tag for switch()es anyway. 055 * 056 * First, we want match the specification as closely as possible. Second we 057 * need the tag as an index to select the corresponding class name from the 058 * `CONSTANT_NAMES' array. 059 */ 060 /** 061 * @deprecated (since 6.0) will be made private; do not access directly, use getter/setter 062 */ 063 @java.lang.Deprecated 064 protected byte tag; // TODO should be private & final 065 066 Constant(final byte tag) { 067 this.tag = tag; 068 } 069 070 /** 071 * Called by objects that are traversing the nodes of the tree implicitely 072 * defined by the contents of a Java class. I.e., the hierarchy of methods, 073 * fields, attributes, etc. spawns a tree of objects. 074 * 075 * @param v Visitor object 076 */ 077 @Override 078 public abstract void accept( Visitor v ); 079 080 public abstract void dump( DataOutputStream file ) throws IOException; 081 082 /** 083 * @return Tag of constant, i.e., its type. No setTag() method to avoid 084 * confusion. 085 */ 086 public final byte getTag() { 087 return tag; 088 } 089 090 /** 091 * @return String representation. 092 */ 093 @Override 094 public String toString() { 095 return Const.getConstantName(tag) + "[" + tag + "]"; 096 } 097 098 /** 099 * @return deep copy of this constant 100 */ 101 public Constant copy() { 102 try { 103 return (Constant) super.clone(); 104 } catch (final CloneNotSupportedException e) { 105 // TODO should this throw? 106 } 107 return null; 108 } 109 110 @Override 111 public Object clone() { 112 try { 113 return super.clone(); 114 } catch (final CloneNotSupportedException e) { 115 throw new Error("Clone Not Supported"); // never happens 116 } 117 } 118 119 /** 120 * Reads one constant from the given input, the type depends on a tag byte. 121 * 122 * @param dataInput Input stream 123 * @return Constant object 124 * @throws IOException if an I/O error occurs reading from the given {@code dataInput}. 125 * @throws ClassFormatException if the next byte is not recognized 126 * @since 6.0 made public 127 */ 128 public static Constant readConstant(final DataInput dataInput) throws IOException, ClassFormatException { 129 final byte b = dataInput.readByte(); // Read tag byte 130 switch (b) { 131 case Const.CONSTANT_Class: 132 return new ConstantClass(dataInput); 133 case Const.CONSTANT_Fieldref: 134 return new ConstantFieldref(dataInput); 135 case Const.CONSTANT_Methodref: 136 return new ConstantMethodref(dataInput); 137 case Const.CONSTANT_InterfaceMethodref: 138 return new ConstantInterfaceMethodref(dataInput); 139 case Const.CONSTANT_String: 140 return new ConstantString(dataInput); 141 case Const.CONSTANT_Integer: 142 return new ConstantInteger(dataInput); 143 case Const.CONSTANT_Float: 144 return new ConstantFloat(dataInput); 145 case Const.CONSTANT_Long: 146 return new ConstantLong(dataInput); 147 case Const.CONSTANT_Double: 148 return new ConstantDouble(dataInput); 149 case Const.CONSTANT_NameAndType: 150 return new ConstantNameAndType(dataInput); 151 case Const.CONSTANT_Utf8: 152 return ConstantUtf8.getInstance(dataInput); 153 case Const.CONSTANT_MethodHandle: 154 return new ConstantMethodHandle(dataInput); 155 case Const.CONSTANT_MethodType: 156 return new ConstantMethodType(dataInput); 157 case Const.CONSTANT_Dynamic: 158 return new ConstantDynamic(dataInput); 159 case Const.CONSTANT_InvokeDynamic: 160 return new ConstantInvokeDynamic(dataInput); 161 case Const.CONSTANT_Module: 162 return new ConstantModule(dataInput); 163 case Const.CONSTANT_Package: 164 return new ConstantPackage(dataInput); 165 default: 166 throw new ClassFormatException("Invalid byte tag in constant pool: " + b); 167 } 168 } 169 170 /** 171 * @return Comparison strategy object 172 */ 173 public static BCELComparator getComparator() { 174 return bcelComparator; 175 } 176 177 /** 178 * @param comparator Comparison strategy object 179 */ 180 public static void setComparator( final BCELComparator comparator ) { 181 bcelComparator = comparator; 182 } 183 184 /** 185 * Returns value as defined by given BCELComparator strategy. 186 * By default two Constant objects are said to be equal when 187 * the result of toString() is equal. 188 * 189 * @see java.lang.Object#equals(java.lang.Object) 190 */ 191 @Override 192 public boolean equals( final Object obj ) { 193 return bcelComparator.equals(this, obj); 194 } 195 196 /** 197 * Returns value as defined by given BCELComparator strategy. 198 * By default return the hashcode of the result of toString(). 199 * 200 * @see java.lang.Object#hashCode() 201 */ 202 @Override 203 public int hashCode() { 204 return bcelComparator.hashCode(this); 205 } 206}