View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    *
9    *      http://www.apache.org/licenses/LICENSE-2.0
10   *
11   *  Unless required by applicable law or agreed to in writing, software
12   *  distributed under the License is distributed on an "AS IS" BASIS,
13   *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   *  See the License for the specific language governing permissions and
15   *  limitations under the License.
16   *
17   */
18  package org.apache.bcel.classfile;
19  
20  import java.io.DataInput;
21  import java.io.DataOutputStream;
22  import java.io.IOException;
23  
24  import org.apache.bcel.Const;
25  
26  /**
27   * This class represents a inner class attribute, i.e., the class
28   * indices of the inner and outer classes, the name and the attributes
29   * of the inner class.
30   *
31   * @see InnerClasses
32   */
33  public final class InnerClass implements Cloneable, Node {
34  
35      private int innerClassIndex;
36      private int outerClassIndex;
37      private int innerNameIndex;
38      private int innerAccessFlags;
39  
40  
41      /**
42       * Initialize from another object.
43       */
44      public InnerClass/InnerClass.html#InnerClass">InnerClass(final InnerClass c) {
45          this(c.getInnerClassIndex(), c.getOuterClassIndex(), c.getInnerNameIndex(), c
46                  .getInnerAccessFlags());
47      }
48  
49  
50      /**
51       * Construct object from file stream.
52       * @param file Input stream
53       * @throws IOException
54       */
55      InnerClass(final DataInput file) throws IOException {
56          this(file.readUnsignedShort(), file.readUnsignedShort(), file.readUnsignedShort(), file
57                  .readUnsignedShort());
58      }
59  
60  
61      /**
62       * @param innerClassIndex Class index in constant pool of inner class
63       * @param outerClassIndex Class index in constant pool of outer class
64       * @param innerNameIndex  Name index in constant pool of inner class
65       * @param innerAccessFlags Access flags of inner class
66       */
67      public InnerClass(final int innerClassIndex, final int outerClassIndex, final int innerNameIndex,
68              final int innerAccessFlags) {
69          this.innerClassIndex = innerClassIndex;
70          this.outerClassIndex = outerClassIndex;
71          this.innerNameIndex = innerNameIndex;
72          this.innerAccessFlags = innerAccessFlags;
73      }
74  
75  
76      /**
77       * Called by objects that are traversing the nodes of the tree implicitely
78       * defined by the contents of a Java class. I.e., the hierarchy of methods,
79       * fields, attributes, etc. spawns a tree of objects.
80       *
81       * @param v Visitor object
82       */
83      @Override
84      public void accept( final Visitor v ) {
85          v.visitInnerClass(this);
86      }
87  
88  
89      /**
90       * Dump inner class attribute to file stream in binary format.
91       *
92       * @param file Output file stream
93       * @throws IOException
94       */
95      public void dump( final DataOutputStream file ) throws IOException {
96          file.writeShort(innerClassIndex);
97          file.writeShort(outerClassIndex);
98          file.writeShort(innerNameIndex);
99          file.writeShort(innerAccessFlags);
100     }
101 
102 
103     /**
104      * @return access flags of inner class.
105      */
106     public int getInnerAccessFlags() {
107         return innerAccessFlags;
108     }
109 
110 
111     /**
112      * @return class index of inner class.
113      */
114     public int getInnerClassIndex() {
115         return innerClassIndex;
116     }
117 
118 
119     /**
120      * @return name index of inner class.
121      */
122     public int getInnerNameIndex() {
123         return innerNameIndex;
124     }
125 
126 
127     /**
128      * @return class index of outer class.
129      */
130     public int getOuterClassIndex() {
131         return outerClassIndex;
132     }
133 
134 
135     /**
136      * @param innerAccessFlags access flags for this inner class
137      */
138     public void setInnerAccessFlags( final int innerAccessFlags ) {
139         this.innerAccessFlags = innerAccessFlags;
140     }
141 
142 
143     /**
144      * @param innerClassIndex index into the constant pool for this class
145      */
146     public void setInnerClassIndex( final int innerClassIndex ) {
147         this.innerClassIndex = innerClassIndex;
148     }
149 
150 
151     /**
152      * @param innerNameIndex index into the constant pool for this class's name
153      */
154     public void setInnerNameIndex( final int innerNameIndex ) { // TODO unused
155         this.innerNameIndex = innerNameIndex;
156     }
157 
158 
159     /**
160      * @param outerClassIndex index into the constant pool for the owning class
161      */
162     public void setOuterClassIndex( final int outerClassIndex ) { // TODO unused
163         this.outerClassIndex = outerClassIndex;
164     }
165 
166 
167     /**
168      * @return String representation.
169      */
170     @Override
171     public String toString() {
172         return "InnerClass(" + innerClassIndex + ", " + outerClassIndex + ", "
173                 + innerNameIndex + ", " + innerAccessFlags + ")";
174     }
175 
176 
177     /**
178      * @return Resolved string representation
179      */
180     public String toString( final ConstantPool constantPool ) {
181         String outer_class_name;
182         String inner_name;
183         String inner_class_name = constantPool.getConstantString(innerClassIndex,
184                 Const.CONSTANT_Class);
185         inner_class_name = Utility.compactClassName(inner_class_name, false);
186         if (outerClassIndex != 0) {
187             outer_class_name = constantPool.getConstantString(outerClassIndex,
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 (innerNameIndex != 0) {
194             inner_name = ((ConstantUtf8) constantPool.getConstant(innerNameIndex,
195                     Const.CONSTANT_Utf8)).getBytes();
196         } else {
197             inner_name = "(anonymous)";
198         }
199         String access = Utility.accessToString(innerAccessFlags, 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 }