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, that is, 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       * Constructs an InnerClass.
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, final int innerAccessFlags) {
68          this.innerClassIndex = innerClassIndex;
69          this.outerClassIndex = outerClassIndex;
70          this.innerNameIndex = innerNameIndex;
71          this.innerAccessFlags = innerAccessFlags;
72      }
73  
74      /**
75       * Called by objects that are traversing the nodes of the tree implicitly defined by the contents of a Java class.
76       * I.e., the hierarchy of methods, fields, attributes, etc. spawns a tree of objects.
77       *
78       * @param v Visitor object.
79       */
80      @Override
81      public void accept(final Visitor v) {
82          v.visitInnerClass(this);
83      }
84  
85      /**
86       * Creates a deep copy of this object.
87       *
88       * @return deep copy of this object.
89       */
90      public InnerClass copy() {
91          try {
92              return (InnerClass) clone();
93          } catch (final CloneNotSupportedException e) {
94              // TODO should this throw?
95          }
96          return null;
97      }
98  
99      /**
100      * Dumps inner class attribute to file stream in binary format.
101      *
102      * @param file Output file stream.
103      * @throws IOException if an I/O error occurs.
104      */
105     public void dump(final DataOutputStream file) throws IOException {
106         file.writeShort(innerClassIndex);
107         file.writeShort(outerClassIndex);
108         file.writeShort(innerNameIndex);
109         file.writeShort(innerAccessFlags);
110     }
111 
112     /**
113      * Gets the access flags of inner class.
114      *
115      * @return access flags of inner class.
116      */
117     public int getInnerAccessFlags() {
118         return innerAccessFlags;
119     }
120 
121     /**
122      * Gets the class index of inner class.
123      *
124      * @return class index of inner class.
125      */
126     public int getInnerClassIndex() {
127         return innerClassIndex;
128     }
129 
130     /**
131      * Gets the name index of inner class.
132      *
133      * @return name index of inner class.
134      */
135     public int getInnerNameIndex() {
136         return innerNameIndex;
137     }
138 
139     /**
140      * Gets the class index of outer class.
141      *
142      * @return class index of outer class.
143      */
144     public int getOuterClassIndex() {
145         return outerClassIndex;
146     }
147 
148     /**
149      * Sets the access flags for this inner class.
150      *
151      * @param innerAccessFlags access flags for this inner class.
152      */
153     public void setInnerAccessFlags(final int innerAccessFlags) {
154         this.innerAccessFlags = innerAccessFlags;
155     }
156 
157     /**
158      * Sets the index into the constant pool for this class.
159      *
160      * @param innerClassIndex index into the constant pool for this class.
161      */
162     public void setInnerClassIndex(final int innerClassIndex) {
163         this.innerClassIndex = innerClassIndex;
164     }
165 
166     /**
167      * Sets the index into the constant pool for this class's name.
168      *
169      * @param innerNameIndex index into the constant pool for this class's name.
170      */
171     public void setInnerNameIndex(final int innerNameIndex) { // TODO unused
172         this.innerNameIndex = innerNameIndex;
173     }
174 
175     /**
176      * Sets the index into the constant pool for the owning class.
177      *
178      * @param outerClassIndex index into the constant pool for the owning class.
179      */
180     public void setOuterClassIndex(final int outerClassIndex) { // TODO unused
181         this.outerClassIndex = outerClassIndex;
182     }
183 
184     /**
185      * Gets the string representation.
186      *
187      * @return String representation.
188      */
189     @Override
190     public String toString() {
191         return "InnerClass(" + innerClassIndex + ", " + outerClassIndex + ", " + innerNameIndex + ", " + innerAccessFlags + ")";
192     }
193 
194     /**
195      * Gets the resolved string representation.
196      *
197      * @param constantPool the constant pool.
198      * @return Resolved string representation.
199      */
200     public String toString(final ConstantPool constantPool) {
201         String outerClassName;
202         String innerClassName = constantPool.getConstantString(innerClassIndex, Const.CONSTANT_Class);
203         innerClassName = Utility.compactClassName(innerClassName, false);
204         if (outerClassIndex != 0) {
205             outerClassName = constantPool.getConstantString(outerClassIndex, Const.CONSTANT_Class);
206             outerClassName = " of class " + Utility.compactClassName(outerClassName, false);
207         } else {
208             outerClassName = "";
209         }
210         final String innerName;
211         if (innerNameIndex != 0) {
212             innerName = constantPool.getConstantUtf8(innerNameIndex).getBytes();
213         } else {
214             innerName = "(anonymous)";
215         }
216         String access = Utility.accessToString(innerAccessFlags, true);
217         access = access.isEmpty() ? "" : access + " ";
218         return "  " + access + innerName + "=class " + innerClassName + outerClassName;
219     }
220 }