Source code: com/techtrader/modules/tools/bytecode/InnerClassesAttribute.java
1 package com.techtrader.modules.tools.bytecode;
2
3
4 import java.io.DataOutput;
5 import java.io.DataInput;
6 import java.io.IOException;
7 import java.util.List;
8 import java.util.LinkedList;
9 import java.util.Iterator;
10
11 import com.techtrader.modules.tools.bytecode.visitor.BCVisitor;
12
13
14 /**
15 * Attribute describing the inner classes of a .class file. Note: for
16 * methods that take in the name of the inner class, this refers to the
17 * short name it is referred to be within the owning class, not the full
18 * name. For anonymous inner classes, use the empty String.
19 * TODO: Import and copy methods are broken.
20 *
21 * @author Abe White
22 */
23 public class InnerClassesAttribute
24 extends Attribute
25 {
26 private List _innerClasses = new LinkedList ();
27
28
29 /**
30 * Protected constructor.
31 */
32 public InnerClassesAttribute (int nameIndex, BCEntity owner)
33 {
34 super (nameIndex, owner);
35 }
36
37
38 /**
39 * Get all the inner classes owned by this entity.
40 *
41 * @return all owned inner classes, or empty array if none
42 */
43 public InnerClass[] getInnerClasses ()
44 {
45 return (InnerClass[]) _innerClasses.toArray
46 (new InnerClass[_innerClasses.size ()]);
47 }
48
49
50 /**
51 * Return the inner class with the given name. If multiple inner classes
52 * share the name, which is returned is undefined.
53 */
54 public InnerClass getInnerClass (String name)
55 {
56 InnerClass next;
57 for (Iterator i = _innerClasses.iterator (); i.hasNext ();)
58 {
59 next = (InnerClass) i.next ();
60 if (next.getName ().equals (name))
61 return next;
62 }
63
64 return null;
65 }
66
67
68 /**
69 * Returns all inner classes with the given name.
70 *
71 * @return the matching inner classes, or empty array if none
72 */
73 public InnerClass[] getInnerClasses (String name)
74 {
75 List matches = new LinkedList ();
76
77 InnerClass next;
78 for (Iterator i = _innerClasses.iterator (); i.hasNext ();)
79 {
80 next = (InnerClass) i.next ();
81 if (next.getName ().equals (name))
82 matches.add (next);
83 }
84
85 return (InnerClass[]) matches.toArray (new InnerClass[matches.size ()]);
86 }
87
88
89 /**
90 * Import an inner class from another entity, or make a copy of one
91 * on this entity.
92 */
93 public InnerClass importInnerClass (InnerClass inner)
94 {
95 InnerClass newInner = addInnerClass (inner.getName ());
96 newInner.setAccessFlags (inner.getAccessFlags ());
97
98 return newInner;
99 }
100
101
102 /**
103 * Import all inner classes from another entity.
104 */
105 public void importInnerClasses (InnerClassesAttribute other)
106 {
107 if (other == null)
108 return;
109
110 InnerClass[] inners = other.getInnerClasses ();
111 for (int i = 0; i < inners.length; i++)
112 importInnerClass (inners[i]);
113 }
114
115
116 /**
117 * Add an inner class.
118 */
119 public InnerClass addInnerClass ()
120 {
121 InnerClass inner = new InnerClass (this);
122 _innerClasses.add (inner);
123
124 return inner;
125 }
126
127
128 /**
129 * Add an inner class with the given name.
130 */
131 public InnerClass addInnerClass (String name)
132 {
133 InnerClass inner = new InnerClass (name, this);
134 _innerClasses.add (inner);
135
136 return inner;
137 }
138
139
140 /**
141 * Clear all inner classes from this entity.
142 */
143 public void clearInnerClasses ()
144 {
145 _innerClasses.clear ();
146 }
147
148
149 /**
150 * Remove all inner classes with the given name from the list.
151 *
152 * @return true if an inner class was removed, false otherwise
153 */
154 public boolean removeInnerClass (String name)
155 {
156 InnerClass[] matches = getInnerClasses (name);
157 for (int i = 0; i < matches.length; i++)
158 removeInnerClass (matches[i]);
159
160 return (matches.length > 0);
161 }
162
163
164 /**
165 * Remove the given inner class. After being removed, the given InnerClass
166 * is invalid, and the result of any operations on it are undefined.
167 *
168 * @return true if the inner class was removed, false otherwise
169 */
170 public boolean removeInnerClass (InnerClass innerClass)
171 {
172 if (innerClass == null || !_innerClasses.remove (innerClass))
173 return false;
174
175 innerClass.invalidate ();
176 return true;
177 }
178
179
180 public int getLength ()
181 {
182 return 2 + 8 * _innerClasses.size ();
183 }
184
185
186 protected void copy (Attribute other)
187 {
188 importInnerClasses ((InnerClassesAttribute) other);
189 }
190
191
192 protected void readData (DataInput in, int length)
193 throws IOException
194 {
195 _innerClasses.clear ();
196 int numInnerClasses = in.readUnsignedShort ();
197
198 InnerClass innerClass;
199 for (int i = 0; i < numInnerClasses; i++)
200 {
201 innerClass = addInnerClass ();
202 innerClass.readData (in);
203 }
204 }
205
206
207 protected void writeData (DataOutput out, int length)
208 throws IOException
209 {
210 out.writeShort (_innerClasses.size ());
211 for (Iterator i = _innerClasses.iterator (); i.hasNext ();)
212 ((InnerClass) i.next ()).writeData (out);
213 }
214
215
216 public void acceptVisit (BCVisitor visit)
217 {
218 visit.enterInnerClassesAttribute (this);
219
220 for (Iterator i = _innerClasses.iterator (); i.hasNext ();)
221 ((InnerClass) i.next ()).acceptVisit (visit);
222
223 visit.exitInnerClassesAttribute (this);
224 }
225 }