1 /*
   2  * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
   3  */
   4 /*
   5  * Licensed to the Apache Software Foundation (ASF) under one or more
   6  * contributor license agreements.  See the NOTICE file distributed with
   7  * this work for additional information regarding copyright ownership.
   8  * The ASF licenses this file to You under the Apache License, Version 2.0
   9  * (the "License"); you may not use this file except in compliance with
  10  * the License.  You may obtain a copy of the License at
  11  *
  12  *      http://www.apache.org/licenses/LICENSE-2.0
  13  *
  14  * Unless required by applicable law or agreed to in writing, software
  15  * distributed under the License is distributed on an "AS IS" BASIS,
  16  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  17  * See the License for the specific language governing permissions and
  18  * limitations under the License.
  19  */
  20 package com.sun.org.apache.bcel.internal.classfile;
  21 
  22 import java.io.DataInput;
  23 import java.io.DataOutputStream;
  24 import java.io.IOException;
  25 
  26 import com.sun.org.apache.bcel.internal.Const;
  27 import com.sun.org.apache.bcel.internal.util.BCELComparator;
  28 
  29 /**
  30  * Abstract superclass for classes to represent the different constant types in
  31  * the constant pool of a class file. The classes keep closely to the JVM
  32  * specification.
  33  *
  34  * @version $Id: Constant.java 1749603 2016-06-21 20:50:19Z ggregory $
  35  */
  36 public abstract class Constant implements Cloneable, Node {
  37 
  38     private static BCELComparator bcelComparator = new BCELComparator() {
  39 
  40         @Override
  41         public boolean equals(final Object o1, final Object o2) {
  42             final Constant THIS = (Constant) o1;
  43             final Constant THAT = (Constant) o2;
  44             return THIS.toString().equals(THAT.toString());
  45         }
  46 
  47         @Override
  48         public int hashCode(final Object o) {
  49             final Constant THIS = (Constant) o;
  50             return THIS.toString().hashCode();
  51         }
  52     };
  53 
  54     /* In fact this tag is redundant since we can distinguish different
  55      * `Constant' objects by their type, i.e., via `instanceof'. In some
  56      * places we will use the tag for switch()es anyway.
  57      *
  58      * First, we want match the specification as closely as possible. Second we
  59      * need the tag as an index to select the corresponding class name from the
  60      * `CONSTANT_NAMES' array.
  61      */
  62     private byte tag;
  63 
  64     Constant(final byte tag) {
  65         this.tag = tag;
  66     }
  67 
  68     /**
  69      * Called by objects that are traversing the nodes of the tree implicitely
  70      * defined by the contents of a Java class. I.e., the hierarchy of methods,
  71      * fields, attributes, etc. spawns a tree of objects.
  72      *
  73      * @param v Visitor object
  74      */
  75     @Override
  76     public abstract void accept(Visitor v);
  77 
  78     public abstract void dump(DataOutputStream file) throws IOException;
  79 
  80     /**
  81      * @return Tag of constant, i.e., its type. No setTag() method to avoid
  82      * confusion.
  83      */
  84     public final byte getTag() {
  85         return tag;
  86     }
  87 
  88     /**
  89      * @return String representation.
  90      */
  91     @Override
  92     public String toString() {
  93         return Const.getConstantName(tag) + "[" + tag + "]";
  94     }
  95 
  96     /**
  97      * @return deep copy of this constant
  98      */
  99     public Constant copy() {
 100         try {
 101             return (Constant) super.clone();
 102         } catch (final CloneNotSupportedException e) {
 103             // TODO should this throw?
 104         }
 105         return null;
 106     }
 107 
 108     @Override
 109     public Object clone() {
 110         try {
 111             return super.clone();
 112         } catch (final CloneNotSupportedException e) {
 113             throw new Error("Clone Not Supported"); // never happens
 114         }
 115     }
 116 
 117     /**
 118      * Read one constant from the given input, the type depends on a tag byte.
 119      *
 120      * @param input Input stream
 121      * @return Constant object
 122      * @since 6.0 made public
 123      */
 124     public static Constant readConstant(final DataInput input) throws IOException,
 125             ClassFormatException {
 126         final byte b = input.readByte(); // Read tag byte
 127         switch (b) {
 128             case Const.CONSTANT_Class:
 129                 return new ConstantClass(input);
 130             case Const.CONSTANT_Fieldref:
 131                 return new ConstantFieldref(input);
 132             case Const.CONSTANT_Methodref:
 133                 return new ConstantMethodref(input);
 134             case Const.CONSTANT_InterfaceMethodref:
 135                 return new ConstantInterfaceMethodref(input);
 136             case Const.CONSTANT_String:
 137                 return new ConstantString(input);
 138             case Const.CONSTANT_Integer:
 139                 return new ConstantInteger(input);
 140             case Const.CONSTANT_Float:
 141                 return new ConstantFloat(input);
 142             case Const.CONSTANT_Long:
 143                 return new ConstantLong(input);
 144             case Const.CONSTANT_Double:
 145                 return new ConstantDouble(input);
 146             case Const.CONSTANT_NameAndType:
 147                 return new ConstantNameAndType(input);
 148             case Const.CONSTANT_Utf8:
 149                 return ConstantUtf8.getInstance(input);
 150             case Const.CONSTANT_MethodHandle:
 151                 return new ConstantMethodHandle(input);
 152             case Const.CONSTANT_MethodType:
 153                 return new ConstantMethodType(input);
 154             case Const.CONSTANT_InvokeDynamic:
 155                 return new ConstantInvokeDynamic(input);
 156             default:
 157                 throw new ClassFormatException("Invalid byte tag in constant pool: " + b);
 158         }
 159     }
 160 
 161     /**
 162      * @return Comparison strategy object
 163      */
 164     public static BCELComparator getComparator() {
 165         return bcelComparator;
 166     }
 167 
 168     /**
 169      * @param comparator Comparison strategy object
 170      */
 171     public static void setComparator(final BCELComparator comparator) {
 172         bcelComparator = comparator;
 173     }
 174 
 175     /**
 176      * Return value as defined by given BCELComparator strategy. By default two
 177      * Constant objects are said to be equal when the result of toString() is
 178      * equal.
 179      *
 180      * @see java.lang.Object#equals(java.lang.Object)
 181      */
 182     @Override
 183     public boolean equals(final Object obj) {
 184         return bcelComparator.equals(this, obj);
 185     }
 186 
 187     /**
 188      * Return value as defined by given BCELComparator strategy. By default
 189      * return the hashcode of the result of toString().
 190      *
 191      * @see java.lang.Object#hashCode()
 192      */
 193     @Override
 194     public int hashCode() {
 195         return bcelComparator.hashCode(this);
 196     }
 197 }