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 is derived from <em>Attribute</em> and denotes that this class
28   * is an Inner class of another.
29   * to the source file of this class.
30   * It is instantiated from the <em>Attribute.readAttribute()</em> method.
31   *
32   * @version $Id: InnerClasses.html 1018313 2017-09-18 09:03:04Z britter $
33   * @see     Attribute
34   */
35  public final class InnerClasses extends Attribute {
36  
37      private InnerClass[] inner_classes;
38  
39  
40      /**
41       * Initialize from another object. Note that both objects use the same
42       * references (shallow copy). Use clone() for a physical copy.
43       */
44      public InnerClasses(final InnerClasses c) {
45          this(c.getNameIndex(), c.getLength(), c.getInnerClasses(), c.getConstantPool());
46      }
47  
48  
49      /**
50       * @param name_index Index in constant pool to CONSTANT_Utf8
51       * @param length Content length in bytes
52       * @param inner_classes array of inner classes attributes
53       * @param constant_pool Array of constants
54       */
55      public InnerClasses(final int name_index, final int length, final InnerClass[] inner_classes,
56              final ConstantPool constant_pool) {
57          super(Const.ATTR_INNER_CLASSES, name_index, length, constant_pool);
58          this.inner_classes = inner_classes != null ? inner_classes : new InnerClass[0];
59      }
60  
61  
62      /**
63       * Construct object from input stream.
64       *
65       * @param name_index Index in constant pool to CONSTANT_Utf8
66       * @param length Content length in bytes
67       * @param input Input stream
68       * @param constant_pool Array of constants
69       * @throws IOException
70       */
71      InnerClasses(final int name_index, final int length, final DataInput input, final ConstantPool constant_pool)
72              throws IOException {
73          this(name_index, length, (InnerClass[]) null, constant_pool);
74          final int number_of_classes = input.readUnsignedShort();
75          inner_classes = new InnerClass[number_of_classes];
76          for (int i = 0; i < number_of_classes; i++) {
77              inner_classes[i] = new InnerClass(input);
78          }
79      }
80  
81  
82      /**
83       * Called by objects that are traversing the nodes of the tree implicitely
84       * defined by the contents of a Java class. I.e., the hierarchy of methods,
85       * fields, attributes, etc. spawns a tree of objects.
86       *
87       * @param v Visitor object
88       */
89      @Override
90      public void accept( final Visitor v ) {
91          v.visitInnerClasses(this);
92      }
93  
94  
95      /**
96       * Dump source file attribute to file stream in binary format.
97       *
98       * @param file Output file stream
99       * @throws IOException
100      */
101     @Override
102     public final void dump( final DataOutputStream file ) throws IOException {
103         super.dump(file);
104         file.writeShort(inner_classes.length);
105         for (final InnerClass inner_class : inner_classes) {
106             inner_class.dump(file);
107         }
108     }
109 
110 
111     /**
112      * @return array of inner class "records"
113      */
114     public final InnerClass[] getInnerClasses() {
115         return inner_classes;
116     }
117 
118 
119     /**
120      * @param inner_classes the array of inner classes
121      */
122     public final void setInnerClasses( final InnerClass[] inner_classes ) {
123         this.inner_classes = inner_classes != null ? inner_classes : new InnerClass[0];
124     }
125 
126 
127     /**
128      * @return String representation.
129      */
130     @Override
131     public final String toString() {
132         final StringBuilder buf = new StringBuilder();
133         buf.append("InnerClasses(");
134         buf.append(inner_classes.length);
135         buf.append("):\n");
136         for (final InnerClass inner_class : inner_classes) {
137             buf.append(inner_class.toString(super.getConstantPool())).append("\n");
138         }
139         return buf.toString();
140     }
141 
142 
143     /**
144      * @return deep copy of this attribute
145      */
146     @Override
147     public Attribute copy( final ConstantPool _constant_pool ) {
148         // TODO this could be recoded to use a lower level constructor after creating a copy of the inner classes
149         final InnerClasses c = (InnerClasses) clone();
150         c.inner_classes = new InnerClass[inner_classes.length];
151         for (int i = 0; i < inner_classes.length; i++) {
152             c.inner_classes[i] = inner_classes[i].copy();
153         }
154         c.setConstantPool(_constant_pool);
155         return c;
156     }
157 }