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  package org.apache.bcel.classfile;
18  
19  import java.io.DataInput;
20  import java.io.DataOutputStream;
21  import java.io.IOException;
22  
23  import org.apache.bcel.Const;
24  
25  /**
26   * This class represents a inner class attribute, i.e., the class indices of the inner and outer classes, the name and
27   * the attributes of the inner class.
28   *
29   * @see InnerClasses
30   */
31  public final class InnerClass implements Cloneable, Node {
32  
33      private int innerClassIndex;
34      private int outerClassIndex;
35      private int innerNameIndex;
36      private int innerAccessFlags;
37  
38      /**
39       * Constructs object from file stream.
40       *
41       * @param file Input stream
42       * @throws IOException if an I/O error occurs.
43       */
44      InnerClass(final DataInput file) throws IOException {
45          this(file.readUnsignedShort(), file.readUnsignedShort(), file.readUnsignedShort(), file.readUnsignedShort());
46      }
47  
48      /**
49       * Initialize from another object.
50       *
51       * @param c Source to copy.
52       */
53      public InnerClass(final InnerClass c) {
54          this(c.getInnerClassIndex(), c.getOuterClassIndex(), c.getInnerNameIndex(), c.getInnerAccessFlags());
55      }
56  
57      /**
58       * @param innerClassIndex Class index in constant pool of inner class
59       * @param outerClassIndex Class index in constant pool of outer class
60       * @param innerNameIndex Name index in constant pool of inner class
61       * @param innerAccessFlags Access flags of inner class
62       */
63      public InnerClass(final int innerClassIndex, final int outerClassIndex, final int innerNameIndex, final int innerAccessFlags) {
64          this.innerClassIndex = innerClassIndex;
65          this.outerClassIndex = outerClassIndex;
66          this.innerNameIndex = innerNameIndex;
67          this.innerAccessFlags = innerAccessFlags;
68      }
69  
70      /**
71       * Called by objects that are traversing the nodes of the tree implicitly defined by the contents of a Java class.
72       * I.e., the hierarchy of methods, fields, attributes, etc. spawns a tree of objects.
73       *
74       * @param v Visitor object
75       */
76      @Override
77      public void accept(final Visitor v) {
78          v.visitInnerClass(this);
79      }
80  
81      /**
82       * @return deep copy of this object
83       */
84      public InnerClass copy() {
85          try {
86              return (InnerClass) clone();
87          } catch (final CloneNotSupportedException e) {
88              // TODO should this throw?
89          }
90          return null;
91      }
92  
93      /**
94       * Dump inner class attribute to file stream in binary format.
95       *
96       * @param file Output file stream
97       * @throws IOException if an I/O error occurs.
98       */
99      public void dump(final DataOutputStream file) throws IOException {
100         file.writeShort(innerClassIndex);
101         file.writeShort(outerClassIndex);
102         file.writeShort(innerNameIndex);
103         file.writeShort(innerAccessFlags);
104     }
105 
106     /**
107      * @return access flags of inner class.
108      */
109     public int getInnerAccessFlags() {
110         return innerAccessFlags;
111     }
112 
113     /**
114      * @return class index of inner class.
115      */
116     public int getInnerClassIndex() {
117         return innerClassIndex;
118     }
119 
120     /**
121      * @return name index of inner class.
122      */
123     public int getInnerNameIndex() {
124         return innerNameIndex;
125     }
126 
127     /**
128      * @return class index of outer class.
129      */
130     public int getOuterClassIndex() {
131         return outerClassIndex;
132     }
133 
134     /**
135      * @param innerAccessFlags access flags for this inner class
136      */
137     public void setInnerAccessFlags(final int innerAccessFlags) {
138         this.innerAccessFlags = innerAccessFlags;
139     }
140 
141     /**
142      * @param innerClassIndex index into the constant pool for this class
143      */
144     public void setInnerClassIndex(final int innerClassIndex) {
145         this.innerClassIndex = innerClassIndex;
146     }
147 
148     /**
149      * @param innerNameIndex index into the constant pool for this class's name
150      */
151     public void setInnerNameIndex(final int innerNameIndex) { // TODO unused
152         this.innerNameIndex = innerNameIndex;
153     }
154 
155     /**
156      * @param outerClassIndex index into the constant pool for the owning class
157      */
158     public void setOuterClassIndex(final int outerClassIndex) { // TODO unused
159         this.outerClassIndex = outerClassIndex;
160     }
161 
162     /**
163      * @return String representation.
164      */
165     @Override
166     public String toString() {
167         return "InnerClass(" + innerClassIndex + ", " + outerClassIndex + ", " + innerNameIndex + ", " + innerAccessFlags + ")";
168     }
169 
170     /**
171      * @return Resolved string representation
172      */
173     public String toString(final ConstantPool constantPool) {
174         String outerClassName;
175         String innerName;
176         String innerClassName = constantPool.getConstantString(innerClassIndex, Const.CONSTANT_Class);
177         innerClassName = Utility.compactClassName(innerClassName, false);
178         if (outerClassIndex != 0) {
179             outerClassName = constantPool.getConstantString(outerClassIndex, Const.CONSTANT_Class);
180             outerClassName = " of class " + Utility.compactClassName(outerClassName, false);
181         } else {
182             outerClassName = "";
183         }
184         if (innerNameIndex != 0) {
185             innerName = constantPool.getConstantUtf8(innerNameIndex).getBytes();
186         } else {
187             innerName = "(anonymous)";
188         }
189         String access = Utility.accessToString(innerAccessFlags, true);
190         access = access.isEmpty() ? "" : access + " ";
191         return "  " + access + innerName + "=class " + innerClassName + outerClassName;
192     }
193 }