1 20 21 package net.innig.macker.structure; 22 23 import net.innig.macker.util.ClassNameTranslator; 24 25 import java.io.File ; 26 import java.io.InputStream ; 27 import java.io.IOException ; 28 import java.util.*; 29 import net.innig.collect.*; 30 31 import org.apache.bcel.classfile.*; 32 33 36 public class ParsedClassInfo 37 extends AbstractClassInfo 38 { 39 ParsedClassInfo(ClassManager classManager, File classFile) 40 throws IOException , ClassParseException 41 { 42 super(classManager); 43 try { parse(new ClassParser(classFile.getPath()).parse()); } 44 catch(ClassFormatError cfe) 45 { throw new ClassParseException(cfe); } 46 } 47 48 ParsedClassInfo(ClassManager classManager, InputStream classFileStream) 49 throws IOException , ClassParseException 50 { 51 super(classManager); 52 try { parse(new ClassParser(classFileStream, null).parse()); } 53 catch(ClassFormatError 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 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) accessModifier = translateAccess(classFile); 90 else 91 { 92 Attribute[] attributes = classFile.getAttributes(); 93 String 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 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 [] 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 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 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 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 refTo = (String ) 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 [] 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 ) 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 className) 255 throws ClassParseException 256 { return getSafeClassInfo(ClassNameTranslator.typeConstantToClassName(className), className); } 257 258 private ClassInfo getSafeClassInfo(String className, String 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 getReferences() 270 { return references; } 271 272 private String fullClassName; 273 private boolean isInterface, isAbstract, isFinal; 274 private AccessModifier accessModifier; 275 private ClassInfo extendsClass; 276 private Set implementsClasses; 277 private MultiMap references; 278 } 279 280 | Popular Tags |