KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > net > innig > macker > structure > ParsedClassInfo


1 /*______________________________________________________________________________
2  *
3  * Macker http://innig.net/macker/
4  *
5  * Copyright 2002-2003 Paul Cantrell
6  *
7  * This program is free software; you can redistribute it and/or modify it under
8  * the terms of the GNU General Public License version 2, as published by the
9  * Free Software Foundation. See the file LICENSE.html for more information.
10  *
11  * This program is distributed in the hope that it will be useful, but WITHOUT
12  * ANY WARRANTY, including the implied warranty of MERCHANTABILITY or FITNESS
13  * FOR A PARTICULAR PURPOSE. See the license for more details.
14  *
15  * You should have received a copy of the GNU General Public License along with
16  * this program; if not, write to the Free Software Foundation, Inc. / 59 Temple
17  * Place, Suite 330 / Boston, MA 02111-1307 / USA.
18  *______________________________________________________________________________
19  */

20  
21 package net.innig.macker.structure;
22
23 import net.innig.macker.util.ClassNameTranslator;
24
25 import java.io.File JavaDoc;
26 import java.io.InputStream JavaDoc;
27 import java.io.IOException JavaDoc;
28 import java.util.*;
29 import net.innig.collect.*;
30
31 import org.apache.bcel.classfile.*;
32
33 /**
34     Class info retrieved from a class file.
35 */

36 public class ParsedClassInfo
37     extends AbstractClassInfo
38     {
39     ParsedClassInfo(ClassManager classManager, File JavaDoc classFile)
40         throws IOException JavaDoc, ClassParseException
41         {
42         super(classManager);
43         try { parse(new ClassParser(classFile.getPath()).parse()); }
44         catch(ClassFormatError JavaDoc cfe)
45             { throw new ClassParseException(cfe); }
46         }
47     
48     ParsedClassInfo(ClassManager classManager, InputStream JavaDoc classFileStream)
49         throws IOException JavaDoc, ClassParseException
50         {
51         super(classManager);
52         try { parse(new ClassParser(classFileStream, null).parse()); }
53         catch(ClassFormatError JavaDoc cfe)
54             { throw new ClassParseException(cfe); }
55         }
56     
57     private void parse(JavaClass classFile)
58         throws ClassParseException
59         {
60         parseClassName(classFile);
61         parseFlags(classFile);
62         parseAccess(classFile);
63         parseExtends(classFile);
64         parseImplements(classFile);
65         parseReferences(classFile);
66         }
67     
68     private void parseClassName(JavaClass classFile)
69         { fullClassName = classFile.getClassName(); }
70     
71     public String JavaDoc getFullName()
72         { return fullClassName; }
73     
74     public boolean isComplete()
75         { return true; }
76     
77     private void parseFlags(JavaClass classFile)
78         throws ClassParseException
79         {
80         isInterface = classFile.isInterface();
81         isAbstract = classFile.isAbstract();
82         isFinal = classFile.isFinal();
83         }
84
85     private void parseAccess(JavaClass classFile)
86         throws ClassParseException
87         {
88         if(getFullName().indexOf('$') == -1) //! will break many synthetic classes!
89
accessModifier = translateAccess(classFile);
90         else
91             {
92             Attribute[] attributes = classFile.getAttributes();
93             String JavaDoc classNameRaw = classFile.getClassName().replace('.', '/');
94             for(int a = 0; a < attributes.length; a++)
95                 if(attributes[a] instanceof InnerClasses)
96                     {
97                     InnerClass[] inners = ((InnerClasses) attributes[a]).getInnerClasses();
98                     for(int i = 0; i < inners.length; i++)
99                         {
100                         String JavaDoc innerClassNameRaw = classFile.getConstantPool().getConstantString(
101                             inners[i].getInnerClassIndex(), org.apache.bcel.Constants.CONSTANT_Class);
102                         if(innerClassNameRaw.equals(classNameRaw))
103                             {
104                             if(accessModifier != null)
105                                 throw new ClassParseException("Found multiple inner class attributes for " + this, classFile);
106                             accessModifier = translateAccess(new AccessFlags(inners[i].getInnerAccessFlags()) { });
107                             }
108                         }
109                     }
110             if(accessModifier == null)
111                 throw new ClassParseException("Could not find any class attributes for " + this, classFile);
112             }
113         }
114         
115     public boolean isInterface() { return isInterface; }
116     public boolean isAbstract() { return isAbstract; }
117     public boolean isFinal() { return isFinal; }
118
119     public AccessModifier getAccessModifier()
120         { return accessModifier; }
121
122     private void parseExtends(JavaClass classFile)
123         throws ClassParseException
124         { extendsClass = getSafeClassInfo(classFile.getSuperclassName()); }
125     
126     public ClassInfo getExtends()
127         { return extendsClass; }
128     
129     private void parseImplements(JavaClass classFile)
130         throws ClassParseException
131         {
132         implementsClasses = new TreeSet();
133         String JavaDoc[] names = classFile.getInterfaceNames();
134         for(int n = 0; n < names.length; n++)
135             implementsClasses.add(getSafeClassInfo(names[n]));
136         implementsClasses = Collections.unmodifiableSet(implementsClasses);
137         }
138     
139     public Set/*<ClassInfo>*/ getImplements()
140         { return implementsClasses; }
141     
142     private void parseReferences(JavaClass classFile)
143         throws ClassParseException
144         {
145         references = new CompositeMultiMap(TreeMap.class, HashSet.class);
146         parseConstantPoolReferences(classFile);
147         parseMethodReferences(classFile);
148         parseFieldReferences(classFile);
149         references = InnigCollections.unmodifiableMultiMap(references);
150         }
151     
152     private void parseConstantPoolReferences(JavaClass classFile)
153         throws ClassParseException
154         {
155         // Add accessed classes from constant pool entries
156
ConstantPool constantPool = classFile.getConstantPool();
157         Constant[] constants = constantPool.getConstantPool();
158         for(int a = 1; a < constants.length; a++)
159             if(constants[a] instanceof ConstantClass)
160                 addReference(
161                     new Reference(
162                         this,
163                         getSafeClassInfo(
164                             constantPool.constantToString(constants[a])),
165                         ReferenceType.CONSTANT_POOL,
166                         null,
167                         null));
168         }
169     
170     private void parseMethodReferences(JavaClass classFile)
171         throws ClassParseException
172         {
173         // Add yet more accessed classes from method & field signatures
174
Method[] methods = classFile.getMethods();
175         for(int m = 0; m < methods.length; m++)
176             {
177             Method method = methods[m];
178             AccessModifier methodAccess = translateAccess(method);
179             
180             List paramsAndReturn =
181                 ClassNameTranslator.signatureToClassNames(
182                     method.getSignature());
183             if(paramsAndReturn.isEmpty())
184                 throw new ClassParseException(
185                     "unable to read types for method " + fullClassName + '.' + method.getName(), classFile);
186             
187             for(Iterator i = paramsAndReturn.iterator(); i.hasNext(); )
188                 {
189                 String JavaDoc refTo = (String JavaDoc) i.next();
190                 addReference(
191                     new Reference(
192                         this,
193                         getSafeClassInfo(refTo, method.getSignature()),
194                         i.hasNext() ? ReferenceType.METHOD_PARAM
195                                     : ReferenceType.METHOD_RETURNS,
196                         method.getName(),
197                         methodAccess));
198                 }
199             
200             if(method.getExceptionTable() != null)
201                 {
202                 String JavaDoc[] exceptionNames = method.getExceptionTable().getExceptionNames();
203                 for(int e = 0; e < exceptionNames.length; e++)
204                     addReference(
205                         new Reference(
206                             this,
207                             getSafeClassInfo(exceptionNames[e]),
208                             ReferenceType.METHOD_THROWS,
209                             method.getName(),
210                             methodAccess));
211                 }
212             }
213         }
214     
215     private void parseFieldReferences(JavaClass classFile)
216         throws ClassParseException
217         {
218         Field[] fields = classFile.getFields();
219         for(int a = 0; a < fields.length; a++)
220             {
221             Field field = fields[a];
222             List types =
223                 ClassNameTranslator.signatureToClassNames(
224                     field.getSignature());
225             if(types.size() != 1)
226                 throw new ClassParseException(
227                     "expected one type for field " + fullClassName + '.' + field.getName()
228                     + "; got: " + types + " (signature is \"" + field.getSignature() + "\")",
229                     classFile);
230
231             addReference(
232                 new Reference(
233                     this,
234                     getSafeClassInfo((String JavaDoc) types.get(0), field.getSignature()),
235                     ReferenceType.FIELD_SIGNATURE,
236                     field.getName(),
237                     translateAccess(field)));
238             }
239         }
240         
241     private AccessModifier translateAccess(AccessFlags accessFlags)
242         throws ClassParseException
243         {
244         if(accessFlags.isPublic())
245             return AccessModifier.PUBLIC;
246         else if(accessFlags.isProtected())
247             return AccessModifier.PROTECTED;
248         else if(accessFlags.isPrivate())
249             return AccessModifier.PRIVATE;
250         else
251             return AccessModifier.PACKAGE;
252         }
253     
254     private ClassInfo getSafeClassInfo(String JavaDoc className)
255         throws ClassParseException
256         { return getSafeClassInfo(ClassNameTranslator.typeConstantToClassName(className), className); }
257     
258     private ClassInfo getSafeClassInfo(String JavaDoc className, String JavaDoc unparsedClassName)
259         throws ClassParseException
260         {
261         if(!ClassNameTranslator.isJavaIdentifier(className))
262             throw new ClassParseException("unable to parse class name / signature: \"" + unparsedClassName + "\" (got \"" + className + "\")");
263         return getClassManager().getClassInfo(className);
264         }
265     
266     private void addReference(Reference ref)
267         { references.put(ref.getTo(), ref); }
268     
269     public MultiMap/*<ClassInfo,Reference>*/ getReferences()
270         { return references; }
271     
272     private String JavaDoc fullClassName;
273     private boolean isInterface, isAbstract, isFinal;
274     private AccessModifier accessModifier;
275     private ClassInfo extendsClass;
276     private Set/*<ClassInfo>*/ implementsClasses;
277     private MultiMap/*<ClassInfo,Reference>*/ references;
278     }
279
280
Popular Tags