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