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