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