001    /*
002     * Licensed to the Apache Software Foundation (ASF) under one or more
003     * contributor license agreements.  See the NOTICE file distributed with
004     * this work for additional information regarding copyright ownership.
005     * The ASF licenses this file to You under the Apache License, Version 2.0
006     * (the "License"); you may not use this file except in compliance with
007     * the License.  You may obtain a copy of the License at
008     *
009     *      http://www.apache.org/licenses/LICENSE-2.0
010     *
011     *  Unless required by applicable law or agreed to in writing, software
012     *  distributed under the License is distributed on an "AS IS" BASIS,
013     *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014     *  See the License for the specific language governing permissions and
015     *  limitations under the License. 
016     *
017     */
018    package org.apache.bcel.classfile;
019    
020    import java.io.DataInput;
021    import java.io.DataOutputStream;
022    import java.io.IOException;
023    import java.io.Serializable;
024    
025    import org.apache.bcel.Constants;
026    
027    /** 
028     * This class represents a inner class attribute, i.e., the class
029     * indices of the inner and outer classes, the name and the attributes
030     * of the inner class.
031     *
032     * @version $Id: InnerClass.java 1152072 2011-07-29 01:54:05Z dbrosius $
033     * @author  <A HREF="mailto:m.dahm@gmx.de">M. Dahm</A>
034     * @see InnerClasses
035     */
036    public final class InnerClass implements Cloneable, Node, Serializable {
037    
038        private static final long serialVersionUID = -7200195918166127614L;
039        private int inner_class_index;
040        private int outer_class_index;
041        private int inner_name_index;
042        private int inner_access_flags;
043    
044    
045        /**
046         * Initialize from another object.
047         */
048        public InnerClass(InnerClass c) {
049            this(c.getInnerClassIndex(), c.getOuterClassIndex(), c.getInnerNameIndex(), c
050                    .getInnerAccessFlags());
051        }
052    
053    
054        /**
055         * Construct object from file stream.
056         * @param file Input stream
057         * @throws IOException
058         */
059        InnerClass(DataInput file) throws IOException {
060            this(file.readUnsignedShort(), file.readUnsignedShort(), file.readUnsignedShort(), file
061                    .readUnsignedShort());
062        }
063    
064    
065        /**
066         * @param inner_class_index Class index in constant pool of inner class
067         * @param outer_class_index Class index in constant pool of outer class
068         * @param inner_name_index  Name index in constant pool of inner class
069         * @param inner_access_flags Access flags of inner class
070         */
071        public InnerClass(int inner_class_index, int outer_class_index, int inner_name_index,
072                int inner_access_flags) {
073            this.inner_class_index = inner_class_index;
074            this.outer_class_index = outer_class_index;
075            this.inner_name_index = inner_name_index;
076            this.inner_access_flags = inner_access_flags;
077        }
078    
079    
080        /**
081         * Called by objects that are traversing the nodes of the tree implicitely
082         * defined by the contents of a Java class. I.e., the hierarchy of methods,
083         * fields, attributes, etc. spawns a tree of objects.
084         *
085         * @param v Visitor object
086         */
087        public void accept( Visitor v ) {
088            v.visitInnerClass(this);
089        }
090    
091    
092        /**
093         * Dump inner class attribute to file stream in binary format.
094         *
095         * @param file Output file stream
096         * @throws IOException
097         */
098        public final void dump( DataOutputStream file ) throws IOException {
099            file.writeShort(inner_class_index);
100            file.writeShort(outer_class_index);
101            file.writeShort(inner_name_index);
102            file.writeShort(inner_access_flags);
103        }
104    
105    
106        /**
107         * @return access flags of inner class.
108         */
109        public final int getInnerAccessFlags() {
110            return inner_access_flags;
111        }
112    
113    
114        /**
115         * @return class index of inner class.
116         */
117        public final int getInnerClassIndex() {
118            return inner_class_index;
119        }
120    
121    
122        /**
123         * @return name index of inner class.
124         */
125        public final int getInnerNameIndex() {
126            return inner_name_index;
127        }
128    
129    
130        /**
131         * @return class index of outer class.
132         */
133        public final int getOuterClassIndex() {
134            return outer_class_index;
135        }
136    
137    
138        /**
139         * @param inner_access_flags access flags for this inner class
140         */
141        public final void setInnerAccessFlags( int inner_access_flags ) {
142            this.inner_access_flags = inner_access_flags;
143        }
144    
145    
146        /**
147         * @param inner_class_index index into the constant pool for this class
148         */
149        public final void setInnerClassIndex( int inner_class_index ) {
150            this.inner_class_index = inner_class_index;
151        }
152    
153    
154        /**
155         * @param inner_name_index index into the constant pool for this class's name
156         */
157        public final void setInnerNameIndex( int inner_name_index ) {
158            this.inner_name_index = inner_name_index;
159        }
160    
161    
162        /**
163         * @param outer_class_index index into the constant pool for the owning class
164         */
165        public final void setOuterClassIndex( int outer_class_index ) {
166            this.outer_class_index = outer_class_index;
167        }
168    
169    
170        /**
171         * @return String representation.
172         */
173        @Override
174        public final String toString() {
175            return "InnerClass(" + inner_class_index + ", " + outer_class_index + ", "
176                    + inner_name_index + ", " + inner_access_flags + ")";
177        }
178    
179    
180        /**
181         * @return Resolved string representation
182         */
183        public final String toString( ConstantPool constant_pool ) {
184            String inner_class_name, outer_class_name, inner_name, access;
185            inner_class_name = constant_pool.getConstantString(inner_class_index,
186                    Constants.CONSTANT_Class);
187            inner_class_name = Utility.compactClassName(inner_class_name);
188            if (outer_class_index != 0) {
189                outer_class_name = constant_pool.getConstantString(outer_class_index,
190                        Constants.CONSTANT_Class);
191                outer_class_name = Utility.compactClassName(outer_class_name);
192            } else {
193                outer_class_name = "<not a member>";
194            }
195            if (inner_name_index != 0) {
196                inner_name = ((ConstantUtf8) constant_pool.getConstant(inner_name_index,
197                        Constants.CONSTANT_Utf8)).getBytes();
198            } else {
199                inner_name = "<anonymous>";
200            }
201            access = Utility.accessToString(inner_access_flags, true);
202            access = access.equals("") ? "" : (access + " ");
203            return "InnerClass:" + access + inner_class_name + "(\"" + outer_class_name + "\", \""
204                    + inner_name + "\")";
205        }
206    
207    
208        /**
209         * @return deep copy of this object
210         */
211        public InnerClass copy() {
212            try {
213                return (InnerClass) clone();
214            } catch (CloneNotSupportedException e) {
215            }
216            return null;
217        }
218    }