View Javadoc
1 package attrib4j.bcel; 2 3 import java.io.DataOutputStream; 4 import java.io.File; 5 import java.io.FileOutputStream; 6 import java.io.IOException; 7 import java.net.URLClassLoader; 8 import java.util.Arrays; 9 import java.util.StringTokenizer; 10 11 12 import org.apache.bcel.classfile.Attribute; 13 import org.apache.bcel.classfile.ConstantPool; 14 import org.apache.bcel.classfile.Field; 15 import org.apache.bcel.classfile.JavaClass; 16 import org.apache.bcel.classfile.Method; 17 import org.apache.bcel.classfile.Unknown; 18 import org.apache.bcel.generic.ClassGen; 19 import org.apache.bcel.generic.ConstantPoolGen; 20 import org.apache.bcel.generic.FieldGen; 21 import org.apache.bcel.generic.MethodGen; 22 23 24 import attrib4j.AttributeException; 25 import attrib4j.ClassAnnotator; 26 import attrib4j.Log; 27 28 29 import com.sun.javadoc.MethodDoc; 30 31 /*** 32 * @author Mark.Pollack 33 */ 34 public abstract class AbstractBCELClassAnnotator implements ClassAnnotator { 35 36 protected static Class createFromPackageSearch( 37 String baseClassname, 38 URLClassLoader classloader, 39 String[] attributePackages) 40 throws AttributeException { 41 42 boolean foundClass = false; 43 Class returnClass = null; 44 Exception returnException = null; 45 //TODO Use Set instead? 46 Log.debug("AbstractBCELClassAnnotator", "Creating from package search"); 47 for (int i = 0; i < attributePackages.length; i++) { 48 try { 49 Log.debug( 50 "AbstractBCELClassAnnotator", 51 "Trying with package name = " + attributePackages[i]); 52 returnClass = 53 Class.forName( 54 attributePackages[i] + "." + baseClassname, 55 true, 56 classloader); 57 foundClass = true; 58 break; 59 } catch (ClassNotFoundException e) { 60 try { 61 returnClass = 62 Class.forName( 63 attributePackages[i] 64 + "." 65 + baseClassname 66 + "Attribute", 67 true, 68 classloader); 69 foundClass = true; 70 } catch (ClassNotFoundException e2) { 71 returnException = e2; 72 } 73 } 74 } 75 if (!foundClass) { 76 if (returnException != null) { 77 throw new AttributeException(returnException); 78 } else { 79 throw new AttributeException( 80 "Could not create Attribute class " + baseClassname); 81 } 82 } else { 83 return returnClass; 84 } 85 } 86 87 /*** 88 * Internal routine to guess (and create) the parameter instance from 89 * the text passed in and the type it's supposed to be (from the 90 * constructor). This method handles String, Boolean, Byte, Short, 91 * Integer, Long, Float, and Double parameter types. 92 * 93 * @param ctorParamType The class of the positional parameter in the 94 * attribute constructor. 95 * @param paramText The string value of this paramemter as given in 96 * in the Javadoc tag. 97 * @return An instance of the correct parameter class initialized to 98 * the value specified by the parameter text. 99 */ 100 protected static Object guessParam(Class ctorParamType, String paramText) { 101 if (ctorParamType.equals(String.class)) { 102 if (paramText.startsWith("\"") && paramText.endsWith("\"")) { 103 return paramText.substring(1, paramText.length() - 1); 104 } 105 return null; 106 } 107 if (ctorParamType.equals(Boolean.class) 108 || ctorParamType.equals(boolean.class)) { 109 if (paramText.equals("true")) { 110 return new Boolean(true); 111 } 112 if (paramText.equals("false")) { 113 return new Boolean(false); 114 } 115 return null; 116 } 117 if (ctorParamType.equals(Byte.class) 118 || ctorParamType.equals(byte.class)) { 119 try { 120 return new Byte(paramText); 121 } catch (NumberFormatException pe) { 122 return null; 123 } 124 } 125 if (ctorParamType.equals(Short.class) 126 || ctorParamType.equals(short.class)) { 127 try { 128 return new Short(paramText); 129 } catch (NumberFormatException pe) { 130 return null; 131 } 132 } 133 if (ctorParamType.equals(Integer.class) 134 || ctorParamType.equals(int.class)) { 135 try { 136 return new Integer(paramText); 137 } catch (NumberFormatException pe) { 138 return null; 139 } 140 } 141 if (ctorParamType.equals(Long.class) 142 || ctorParamType.equals(long.class)) { 143 try { 144 return new Long(paramText); 145 } catch (NumberFormatException pe) { 146 return null; 147 } 148 } 149 if (ctorParamType.equals(Float.class) 150 || ctorParamType.equals(float.class)) { 151 try { 152 return new Float(paramText); 153 } catch (NumberFormatException pe) { 154 return null; 155 } 156 } 157 if (ctorParamType.equals(Double.class) 158 || ctorParamType.equals(double.class)) { 159 try { 160 return new Double(paramText); 161 } catch (NumberFormatException pe) { 162 return null; 163 } 164 } 165 166 return null; 167 } 168 169 /*** 170 * Internal routine to pick out a classname from text looking something 171 * like: 172 * "@attribute attrib4j.examples.attributes.DebugAttribute(true, 12)" 173 * 174 * @param fullAttributeText The text of the attribute javadoc tag. 175 * @return The classname to be created as parsed from the javadoc tag. 176 */ 177 protected static String parseAttributeClassName(String fullAttributeText) { 178 String cn; 179 if (fullAttributeText.indexOf("(") > -1) { 180 cn = 181 fullAttributeText 182 .substring(0, fullAttributeText.indexOf("(")) 183 .trim(); 184 } else { 185 cn = fullAttributeText; 186 } 187 return cn; 188 } 189 190 /*** 191 * Internal routine to pick out parameters from text looking something like 192 * "@attribute com.javageeks.attributes.DebugAttribute(true, 12)" 193 * 194 * @param fullAttributeText The text of the attribute javadoc tag. 195 * @return An array of positional parameters that will be used for 196 * for the constructor of the attribute. 197 */ 198 protected static String[] parseAttributeParams(String fullAttributeText) { 199 200 String[] p = new String[0]; 201 int paramsStart = fullAttributeText.indexOf("("); 202 //fixed small bug, was looking for the first index of the closing paren.. 203 int paramsEnd = fullAttributeText.lastIndexOf(")"); 204 205 if (paramsStart == -1 206 || // No ()'s at all 207 (paramsStart == (paramsEnd + 1))) { 208 // ()'s right next to each other 209 return p; 210 } else { 211 String paramText = 212 fullAttributeText.substring(paramsStart + 1, paramsEnd); 213 StringTokenizer st = new StringTokenizer(paramText, ","); 214 p = new String[st.countTokens()]; 215 int count = 0; 216 while (st.hasMoreTokens()) { 217 p[count++] = st.nextToken().trim(); 218 } 219 return p; 220 } 221 } 222 223 protected ClassGen _classGen; 224 225 protected ConstantPool _constantPool; 226 227 protected ConstantPoolGen _constantPoolGen; 228 229 protected JavaClass _javaClass; 230 231 /* (non-Javadoc) 232 * @see attrib4j.ClassAnnotator#createAttributeInstance(java.lang.String, java.net.URLClassLoader, java.lang.String[]) 233 */ 234 public abstract Object createAttributeInstance( 235 String text, 236 URLClassLoader classLoader, 237 String[] attributePackages); 238 239 240 public abstract byte[] createBytesFromAttribute(Object attribute); 241 242 /*** 243 * {@inheritDoc} 244 * @see attrib4j.ClassAnnotator#insertClassAttribute(java.lang.Object) 245 */ 246 public void insertClassAttribute(Object attribute) { 247 byte[] serializedAttribute = createBytesFromAttribute(attribute); 248 249 int nameIndex = _constantPoolGen.addUtf8("Custom"); 250 251 Attribute attr = 252 new Unknown( 253 nameIndex, 254 serializedAttribute.length, 255 serializedAttribute, 256 _constantPoolGen.getConstantPool()); 257 258 _classGen.addAttribute(attr); 259 260 } 261 262 263 /*** 264 * {@inheritDoc} 265 * @see attrib4j.ClassAnnotator#insertFieldAttribute(java.lang.String, java.lang.Object) 266 */ 267 public void insertFieldAttribute(String field, Object attribute) { 268 byte[] serializedAttribute = createBytesFromAttribute(attribute); 269 //get list of fields inthe class from bcel. 270 Field[] classfileField = _classGen.getFields(); 271 272 for (int i = 0; i < classfileField.length; i++) { 273 if (classfileField[i].getName().equals(field)) { 274 Log.debug( 275 "BCELClassAnnotator", 276 "Inserting attribute for fieldname = " + field); 277 FieldGen fieldGen = 278 new FieldGen(classfileField[i], _constantPoolGen); 279 int nameIndex = _constantPoolGen.addUtf8("Custom"); 280 Attribute attr = 281 new Unknown( 282 nameIndex, 283 serializedAttribute.length, 284 serializedAttribute, 285 _constantPoolGen.getConstantPool()); 286 fieldGen.addAttribute(attr); 287 Field newField = fieldGen.getField(); 288 _classGen.replaceField(classfileField[i], newField); 289 } 290 } 291 292 } 293 294 295 /*** 296 * {@inheritDoc} 297 * @see attrib4j.ClassAnnotator#insertMethodAttribute(com.sun.javadoc.MethodDoc, java.lang.Object) 298 */ 299 public void insertMethodAttribute(MethodDoc methodDoc, Object attribute) { 300 byte[] serializedAttribute = createBytesFromAttribute(attribute); 301 Log.debug("BCELClassAnnotator", "-------------"); 302 303 String[] methodParamTypes = new String[methodDoc.parameters().length]; 304 for (int i = 0; i < methodParamTypes.length; i++) { 305 methodParamTypes[i] = methodDoc.parameters()[i].typeName(); 306 } 307 308 //get list of methods in the class from bcel 309 Method[] classfileMethod = _classGen.getMethods(); 310 for (int i = 0; i < classfileMethod.length; i++) { 311 //Log.log("classfileMethod = " + classfileMethod[i].getName()); 312 //match classname 313 if (classfileMethod[i].getName().equals(methodDoc.name())) { 314 if (Arrays 315 .equals( 316 methodParamTypes, 317 DescriptorUtil.convertToJavaFormat( 318 classfileMethod[i].getSignature()))) { 319 Log.debug( 320 "BCELClassAnnotator", 321 "matched methodname = " + methodDoc.name()); 322 Log.debug( 323 "BCELClassAnnotator", 324 "BCEL classfileMethod sig = " 325 + classfileMethod[i].getSignature()); 326 Log.debug( 327 "BCELClassAnnotator", 328 "javadocMethod sig = " 329 + methodDoc.signature() 330 + " return type = " 331 + methodDoc.returnType().qualifiedTypeName()); 332 MethodGen methodGen = 333 new MethodGen( 334 classfileMethod[i], 335 _javaClass.getClassName(), 336 _constantPoolGen); 337 338 int nameIndex = _constantPoolGen.addUtf8("Custom"); 339 Attribute attr = 340 new Unknown( 341 nameIndex, 342 serializedAttribute.length, 343 serializedAttribute, 344 _constantPoolGen.getConstantPool()); 345 methodGen.addAttribute(attr); 346 Method newMethod = methodGen.getMethod(); 347 _classGen.replaceMethod(classfileMethod[i], newMethod); 348 } 349 } 350 } 351 Log.debug("BCELClassAnnotator", "-------------"); 352 } 353 354 355 public void write(String destDir) { 356 357 try { 358 _classGen.setConstantPool(_constantPoolGen); 359 //_classGen.setConstantPool(new ConstantPoolGen(_constantPool)); 360 JavaClass newJavaClass = _classGen.getJavaClass(); 361 362 String path = 363 destDir 364 + "/" 365 + newJavaClass.getClassName().replace('.', '/') 366 + ".class"; 367 File f = new File(path); 368 File parentFile = f.getParentFile(); 369 370 boolean exists = parentFile.exists(); 371 if (!exists) { 372 //Directory does not exist 373 //create all directories in the path 374 boolean success = parentFile.mkdirs(); 375 if (!success) { 376 //TODO: Introduce exception handling into interface? 377 //throw new AttributeException("Could not create directory " + parentFile.toString()); 378 Log.log( 379 "Could not create directory to write new .class file. " 380 + parentFile.toString(), 381 Log.CRITICAL, 382 this); 383 } 384 } 385 386 FileOutputStream fout = new FileOutputStream(path); 387 DataOutputStream out = new DataOutputStream(fout); 388 newJavaClass.dump(out); 389 fout.close(); 390 } catch (IOException ioEx) { 391 ioEx.printStackTrace(); 392 } 393 394 } 395 396 397 398 399 }

This page was automatically generated by Maven