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; 024 025import org.apache.bcel.Const; 026 027/** 028 * This class represents a inner class attribute, that is, the class indices of the inner and outer classes, the name and 029 * the attributes of the inner class. 030 * 031 * @see InnerClasses 032 */ 033public final class InnerClass implements Cloneable, Node { 034 035 private int innerClassIndex; 036 private int outerClassIndex; 037 private int innerNameIndex; 038 private int innerAccessFlags; 039 040 /** 041 * Constructs object from file stream. 042 * 043 * @param file Input stream. 044 * @throws IOException if an I/O error occurs. 045 */ 046 InnerClass(final DataInput file) throws IOException { 047 this(file.readUnsignedShort(), file.readUnsignedShort(), file.readUnsignedShort(), file.readUnsignedShort()); 048 } 049 050 /** 051 * Initialize from another object. 052 * 053 * @param c Source to copy. 054 */ 055 public InnerClass(final InnerClass c) { 056 this(c.getInnerClassIndex(), c.getOuterClassIndex(), c.getInnerNameIndex(), c.getInnerAccessFlags()); 057 } 058 059 /** 060 * Constructs an InnerClass. 061 * 062 * @param innerClassIndex Class index in constant pool of inner class. 063 * @param outerClassIndex Class index in constant pool of outer class. 064 * @param innerNameIndex Name index in constant pool of inner class. 065 * @param innerAccessFlags Access flags of inner class. 066 */ 067 public InnerClass(final int innerClassIndex, final int outerClassIndex, final int innerNameIndex, final int innerAccessFlags) { 068 this.innerClassIndex = innerClassIndex; 069 this.outerClassIndex = outerClassIndex; 070 this.innerNameIndex = innerNameIndex; 071 this.innerAccessFlags = innerAccessFlags; 072 } 073 074 /** 075 * Called by objects that are traversing the nodes of the tree implicitly defined by the contents of a Java class. 076 * I.e., the hierarchy of methods, fields, attributes, etc. spawns a tree of objects. 077 * 078 * @param v Visitor object. 079 */ 080 @Override 081 public void accept(final Visitor v) { 082 v.visitInnerClass(this); 083 } 084 085 /** 086 * Creates a deep copy of this object. 087 * 088 * @return deep copy of this object. 089 */ 090 public InnerClass copy() { 091 try { 092 return (InnerClass) clone(); 093 } catch (final CloneNotSupportedException e) { 094 // TODO should this throw? 095 } 096 return null; 097 } 098 099 /** 100 * Dumps inner class attribute to file stream in binary format. 101 * 102 * @param file Output file stream. 103 * @throws IOException if an I/O error occurs. 104 */ 105 public void dump(final DataOutputStream file) throws IOException { 106 file.writeShort(innerClassIndex); 107 file.writeShort(outerClassIndex); 108 file.writeShort(innerNameIndex); 109 file.writeShort(innerAccessFlags); 110 } 111 112 /** 113 * Gets the access flags of inner class. 114 * 115 * @return access flags of inner class. 116 */ 117 public int getInnerAccessFlags() { 118 return innerAccessFlags; 119 } 120 121 /** 122 * Gets the class index of inner class. 123 * 124 * @return class index of inner class. 125 */ 126 public int getInnerClassIndex() { 127 return innerClassIndex; 128 } 129 130 /** 131 * Gets the name index of inner class. 132 * 133 * @return name index of inner class. 134 */ 135 public int getInnerNameIndex() { 136 return innerNameIndex; 137 } 138 139 /** 140 * Gets the class index of outer class. 141 * 142 * @return class index of outer class. 143 */ 144 public int getOuterClassIndex() { 145 return outerClassIndex; 146 } 147 148 /** 149 * Sets the access flags for this inner class. 150 * 151 * @param innerAccessFlags access flags for this inner class. 152 */ 153 public void setInnerAccessFlags(final int innerAccessFlags) { 154 this.innerAccessFlags = innerAccessFlags; 155 } 156 157 /** 158 * Sets the index into the constant pool for this class. 159 * 160 * @param innerClassIndex index into the constant pool for this class. 161 */ 162 public void setInnerClassIndex(final int innerClassIndex) { 163 this.innerClassIndex = innerClassIndex; 164 } 165 166 /** 167 * Sets the index into the constant pool for this class's name. 168 * 169 * @param innerNameIndex index into the constant pool for this class's name. 170 */ 171 public void setInnerNameIndex(final int innerNameIndex) { // TODO unused 172 this.innerNameIndex = innerNameIndex; 173 } 174 175 /** 176 * Sets the index into the constant pool for the owning class. 177 * 178 * @param outerClassIndex index into the constant pool for the owning class. 179 */ 180 public void setOuterClassIndex(final int outerClassIndex) { // TODO unused 181 this.outerClassIndex = outerClassIndex; 182 } 183 184 /** 185 * Gets the string representation. 186 * 187 * @return String representation. 188 */ 189 @Override 190 public String toString() { 191 return "InnerClass(" + innerClassIndex + ", " + outerClassIndex + ", " + innerNameIndex + ", " + innerAccessFlags + ")"; 192 } 193 194 /** 195 * Gets the resolved string representation. 196 * 197 * @param constantPool the constant pool. 198 * @return Resolved string representation. 199 */ 200 public String toString(final ConstantPool constantPool) { 201 String outerClassName; 202 String innerClassName = constantPool.getConstantString(innerClassIndex, Const.CONSTANT_Class); 203 innerClassName = Utility.compactClassName(innerClassName, false); 204 if (outerClassIndex != 0) { 205 outerClassName = constantPool.getConstantString(outerClassIndex, Const.CONSTANT_Class); 206 outerClassName = " of class " + Utility.compactClassName(outerClassName, false); 207 } else { 208 outerClassName = ""; 209 } 210 final String innerName; 211 if (innerNameIndex != 0) { 212 innerName = constantPool.getConstantUtf8(innerNameIndex).getBytes(); 213 } else { 214 innerName = "(anonymous)"; 215 } 216 String access = Utility.accessToString(innerAccessFlags, true); 217 access = access.isEmpty() ? "" : access + " "; 218 return " " + access + innerName + "=class " + innerClassName + outerClassName; 219 } 220}