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