1 8 package org.codehaus.aspectwerkz.transform.inlining.weaver; 9 10 import org.objectweb.asm.ClassVisitor; 11 import org.objectweb.asm.ClassAdapter; 12 import org.objectweb.asm.Constants; 13 import org.objectweb.asm.CodeVisitor; 14 import org.objectweb.asm.Attribute; 15 import org.objectweb.asm.ClassReader; 16 import org.objectweb.asm.ClassWriter; 17 import org.codehaus.aspectwerkz.transform.Context; 18 import org.codehaus.aspectwerkz.transform.inlining.ContextImpl; 19 import org.codehaus.aspectwerkz.transform.inlining.AsmHelper; 20 import org.codehaus.aspectwerkz.reflect.ClassInfo; 21 import org.codehaus.aspectwerkz.reflect.ClassInfoHelper; 22 23 import java.io.IOException ; 24 import java.io.DataOutputStream ; 25 import java.io.ByteArrayOutputStream ; 26 import java.util.Collection ; 27 import java.util.ArrayList ; 28 import java.util.Arrays ; 29 import java.security.NoSuchAlgorithmException ; 30 import java.security.MessageDigest ; 31 32 41 public class SerialVersionUidVisitor extends ClassAdapter implements Constants { 42 43 public static final String CLINIT = "<clinit>"; 44 public static final String INIT = "<init>"; 45 public static final String SVUID_NAME = "serialVersionUID"; 46 47 50 protected boolean m_computeSVUID = true; 51 52 55 protected boolean m_hadSVUID = false; 56 57 60 protected long m_SVUID; 61 62 65 protected String m_className; 66 67 70 protected int m_access; 71 72 75 protected String [] m_interfaces; 76 77 81 protected Collection m_svuidFields = new ArrayList (); 82 83 86 protected boolean m_hasStaticInitializer = false; 87 88 91 protected Collection m_svuidConstructors = new ArrayList (); 92 93 96 protected Collection m_svuidMethods = new ArrayList (); 97 98 103 public static long calculateSerialVersionUID(Class klass) { 104 try { 105 ClassReader cr = new ClassReader(klass.getName()); 106 ClassWriter cw = AsmHelper.newClassWriter(true); 107 SerialVersionUidVisitor sv = new SerialVersionUidVisitor(cw); 108 cr.accept(sv, true); 109 return sv.m_SVUID; 110 } catch (IOException e) { 111 throw new RuntimeException (e); 112 } 113 } 114 115 private SerialVersionUidVisitor(final ClassVisitor cv) { 116 super(cv); 117 } 118 119 123 public void visit(int version, int access, 124 String name, String superName, 125 String [] interfaces, String sourceFile) { 126 if (mayNeedSerialVersionUid(access)) { 128 m_className = name; 129 m_access = access; 130 m_interfaces = interfaces; 131 } 132 133 super.visit(version, access, name, superName, interfaces, sourceFile); 135 } 136 137 141 public CodeVisitor visitMethod(int access, 142 String name, String desc, 143 String [] exceptions, Attribute attrs) { 144 if (m_computeSVUID) { 146 147 if (name.equals(CLINIT)) { 149 m_hasStaticInitializer = true; 150 } else { 151 if ((access & ACC_PRIVATE) == 0) { 153 if (name.equals(INIT)) { 154 m_svuidConstructors.add(new MethodItem(name, access, desc)); 155 } else { 156 m_svuidMethods.add(new MethodItem(name, access, desc)); 157 } 158 } 159 } 160 161 } 162 163 return cv.visitMethod(access, name, desc, exceptions, attrs); 165 } 166 167 171 public void visitField(int access, String name, String desc, 172 Object value, Attribute attrs) { 173 if (m_computeSVUID) { 175 176 if (name.equals(SVUID_NAME)) { 178 m_hadSVUID = true; 179 m_computeSVUID = false; 181 m_SVUID = ((Long ) value).longValue(); 182 } 183 184 188 if (((access & ACC_PRIVATE) == 0) || 189 ((access & (ACC_STATIC | ACC_TRANSIENT)) == 0)) { 190 m_svuidFields.add(new FieldItem(name, access, desc)); 191 } 192 193 } 194 195 super.visitField(access, name, desc, value, attrs); 197 } 198 199 202 public void visitEnd() { 203 if (m_computeSVUID) { 204 if (!m_hadSVUID) { 206 try { 207 m_SVUID = computeSVUID(); 208 } catch (Throwable e) { 209 throw new RuntimeException ("Error while computing SVUID for " + m_className, e); 210 } 211 } 212 } 213 214 super.visitEnd(); 216 } 217 218 protected boolean mayNeedSerialVersionUid(int access) { 219 return true; 220 } 228 229 236 protected long computeSVUID() throws IOException , NoSuchAlgorithmException { 237 ByteArrayOutputStream bos = null; 238 DataOutputStream dos = null; 239 long svuid = 0; 240 241 try { 242 243 bos = new ByteArrayOutputStream (); 244 dos = new DataOutputStream (bos); 245 246 249 dos.writeUTF(m_className.replace('/', '.')); 250 251 254 int classMods = m_access & (ACC_PUBLIC | ACC_FINAL | ACC_INTERFACE | ACC_ABSTRACT); 255 dos.writeInt(classMods); 256 257 260 Arrays.sort(m_interfaces); 261 for (int i = 0; i < m_interfaces.length; i++) { 262 String ifs = m_interfaces[i].replace('/', '.'); 263 dos.writeUTF(ifs); 264 } 265 266 277 writeItems(m_svuidFields, dos, false); 278 279 286 if (m_hasStaticInitializer) { 287 dos.writeUTF("<clinit>"); 288 dos.writeInt(ACC_STATIC); 289 dos.writeUTF("()V"); 290 } 291 292 298 writeItems(m_svuidConstructors, dos, true); 299 300 306 writeItems(m_svuidMethods, dos, true); 307 308 dos.flush(); 309 310 314 MessageDigest md = MessageDigest.getInstance("SHA"); 315 316 331 byte[] hashBytes = md.digest(bos.toByteArray()); 332 for (int i = Math.min(hashBytes.length, 8) - 1; i >= 0; i--) { 333 svuid = (svuid << 8) | (hashBytes[i] & 0xFF); 334 } 335 336 } finally { 337 if (dos != null) { 339 dos.close(); 340 } 341 } 342 343 return svuid; 344 } 345 346 354 protected void writeItems(Collection itemCollection, 355 DataOutputStream dos, 356 boolean dotted) throws IOException { 357 int size = itemCollection.size(); 358 Item items[] = new Item[size]; 359 items = (Item[]) itemCollection.toArray(items); 360 Arrays.sort(items); 361 362 for (int i = 0; i < size; i++) { 363 items[i].write(dos, dotted); 364 } 365 } 366 367 370 private static abstract class Item implements Comparable { 371 private String m_name; 372 private int m_access; 373 private String m_desc; 374 375 Item(String name, int access, String desc) { 376 m_name = name; 377 m_access = access; 378 m_desc = desc; 379 } 380 381 protected abstract int filterAccess(int access); 383 384 public int compareTo(Object o) { 385 Item other = (Item) o; 386 int retVal = m_name.compareTo(other.m_name); 387 if (retVal == 0) { 388 retVal = m_desc.compareTo(other.m_desc); 389 } 390 return retVal; 391 } 392 393 void write(DataOutputStream dos, boolean dotted) throws IOException { 394 dos.writeUTF(m_name); 395 dos.writeInt(filterAccess(m_access)); 396 if (dotted) { 397 dos.writeUTF(m_desc.replace('/', '.')); 398 } else { 399 dos.writeUTF(m_desc); 400 } 401 } 402 } 403 404 407 private static class FieldItem extends Item { 408 FieldItem(String name, int access, String desc) { 409 super(name, access, desc); 410 } 411 412 protected int filterAccess(int access) { 413 return access & (ACC_PUBLIC | ACC_PRIVATE | ACC_PROTECTED | ACC_STATIC | ACC_FINAL 414 | ACC_VOLATILE | ACC_TRANSIENT); 415 } 416 } 417 418 421 private static class MethodItem extends Item { 422 MethodItem(String name, int access, String desc) { 423 super(name, access, desc); 424 } 425 426 protected int filterAccess(int access) { 427 return access & (ACC_PUBLIC | ACC_PRIVATE | ACC_PROTECTED | ACC_STATIC | ACC_FINAL 428 | ACC_SYNCHRONIZED | ACC_NATIVE | ACC_ABSTRACT | ACC_STRICT); 429 } 430 } 431 432 437 public static class Add extends ClassAdapter { 438 439 private ContextImpl m_ctx; 440 private ClassInfo m_classInfo; 441 442 public Add(ClassVisitor classVisitor, Context ctx, ClassInfo classInfo) { 443 super(classVisitor); 444 m_ctx = (ContextImpl) ctx; 445 m_classInfo = classInfo; 446 } 447 448 public void visitEnd() { 449 if (ClassInfoHelper.implementsInterface(m_classInfo, "java.io.Serializable")) { 450 ClassReader cr = new ClassReader(m_ctx.getInitialBytecode()); 451 ClassWriter cw = AsmHelper.newClassWriter(true); 452 SerialVersionUidVisitor sv = new SerialVersionUidVisitor(cw); 453 cr.accept(sv, true); 454 if (sv.m_computeSVUID && !sv.m_hadSVUID) { 455 cv.visitField(ACC_FINAL + ACC_STATIC, SVUID_NAME, "J", new Long (sv.m_SVUID), null); 456 } 457 } 458 super.visitEnd(); 459 } 460 } 461 } 462 | Popular Tags |