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