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