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