1 4 package com.tc.aspectwerkz.transform.inlining.weaver; 5 6 import com.tc.asm.*; 7 8 import com.tc.aspectwerkz.transform.InstrumentationContext; 9 import com.tc.aspectwerkz.transform.inlining.AsmHelper; 10 import com.tc.aspectwerkz.reflect.ClassInfo; 11 import com.tc.aspectwerkz.reflect.ClassInfoHelper; 12 13 import java.io.IOException ; 14 import java.io.DataOutputStream ; 15 import java.io.ByteArrayOutputStream ; 16 import java.util.Collection ; 17 import java.util.ArrayList ; 18 import java.util.Arrays ; 19 import java.security.NoSuchAlgorithmException ; 20 import java.security.MessageDigest ; 21 22 32 public class SerialVersionUidVisitor extends ClassAdapter implements Opcodes { 33 34 public static final String CLINIT = "<clinit>"; 35 public static final String INIT = "<init>"; 36 public static final String SVUID_NAME = "serialVersionUID"; 37 38 41 protected boolean m_computeSVUID = true; 42 43 46 protected boolean m_hadSVUID = false; 47 48 51 protected long m_SVUID; 52 53 56 protected String m_className; 57 58 61 protected int m_access; 62 63 66 protected String [] m_interfaces; 67 68 72 protected Collection m_svuidFields = new ArrayList (); 73 74 77 protected boolean m_hasStaticInitializer = false; 78 79 82 protected Collection m_svuidConstructors = new ArrayList (); 83 84 87 protected Collection m_svuidMethods = new ArrayList (); 88 89 95 public static long calculateSerialVersionUID(Class klass) { 96 try { 97 ClassReader cr = new ClassReader(klass.getName()); 98 ClassWriter cw = AsmHelper.newClassWriter(true); 99 SerialVersionUidVisitor sv = new SerialVersionUidVisitor(cw); 100 cr.accept(sv, true); 101 return sv.m_SVUID; 102 } catch (IOException e) { 103 throw new RuntimeException (e); 104 } 105 } 106 107 private SerialVersionUidVisitor(final ClassVisitor cv) { 108 super(cv); 109 } 110 111 115 public void visit(int version, int access, 116 String name, String signature, String superName, 117 String [] interfaces) { 118 if (mayNeedSerialVersionUid(access)) { 120 m_className = name; 121 m_access = access; 122 m_interfaces = interfaces; 123 } 124 125 super.visit(version, access, name, signature, superName, interfaces); 127 } 128 129 133 public MethodVisitor visitMethod(int access, 134 String name, String desc, String signature, 135 String [] exceptions) { 136 if (m_computeSVUID) { 138 139 if (name.equals(CLINIT)) { 141 m_hasStaticInitializer = true; 142 } else { 143 if ((access & ACC_PRIVATE) == 0) { 145 if (name.equals(INIT)) { 146 m_svuidConstructors.add(new MethodItem(name, access, desc)); 147 } else { 148 m_svuidMethods.add(new MethodItem(name, access, desc)); 149 } 150 } 151 } 152 153 } 154 155 return cv.visitMethod(access, name, desc, signature, exceptions); 157 } 158 159 163 public FieldVisitor visitField(int access, String name, String desc, String signature, Object value) { 164 if (m_computeSVUID) { 166 167 if (name.equals(SVUID_NAME)) { 169 m_hadSVUID = true; 170 m_computeSVUID = false; 172 m_SVUID = ((Long ) value).longValue(); 173 } 174 175 179 if (((access & ACC_PRIVATE) == 0) || 180 ((access & (ACC_STATIC | ACC_TRANSIENT)) == 0)) { 181 m_svuidFields.add(new FieldItem(name, access, desc)); 182 } 183 184 } 185 186 return super.visitField(access, name, desc, signature, value); 188 } 189 190 193 public void visitEnd() { 194 if (m_computeSVUID) { 195 if (!m_hadSVUID) { 197 try { 198 m_SVUID = computeSVUID(); 199 } catch (Throwable e) { 200 throw new RuntimeException ("Error while computing SVUID for " + m_className, e); 201 } 202 } 203 } 204 205 super.visitEnd(); 207 } 208 209 protected boolean mayNeedSerialVersionUid(int access) { 210 return true; 211 } 219 220 227 protected long computeSVUID() throws IOException , NoSuchAlgorithmException { 228 ByteArrayOutputStream bos = null; 229 DataOutputStream dos = null; 230 long svuid = 0; 231 232 try { 233 234 bos = new ByteArrayOutputStream (); 235 dos = new DataOutputStream (bos); 236 237 240 dos.writeUTF(m_className.replace('/', '.')); 241 242 245 int classMods = m_access & (ACC_PUBLIC | ACC_FINAL | ACC_INTERFACE | ACC_ABSTRACT); 246 dos.writeInt(classMods); 247 248 251 Arrays.sort(m_interfaces); 252 for (int i = 0; i < m_interfaces.length; i++) { 253 String ifs = m_interfaces[i].replace('/', '.'); 254 dos.writeUTF(ifs); 255 } 256 257 268 writeItems(m_svuidFields, dos, false); 269 270 277 if (m_hasStaticInitializer) { 278 dos.writeUTF("<clinit>"); 279 dos.writeInt(ACC_STATIC); 280 dos.writeUTF("()V"); 281 } 282 283 289 writeItems(m_svuidConstructors, dos, true); 290 291 297 writeItems(m_svuidMethods, dos, true); 298 299 dos.flush(); 300 301 305 MessageDigest md = MessageDigest.getInstance("SHA"); 306 307 322 byte[] hashBytes = md.digest(bos.toByteArray()); 323 for (int i = Math.min(hashBytes.length, 8) - 1; i >= 0; i--) { 324 svuid = (svuid << 8) | (hashBytes[i] & 0xFF); 325 } 326 327 } finally { 328 if (dos != null) { 330 dos.close(); 331 } 332 } 333 334 return svuid; 335 } 336 337 345 protected void writeItems(Collection itemCollection, 346 DataOutputStream dos, 347 boolean dotted) throws IOException { 348 int size = itemCollection.size(); 349 Item items[] = new Item[size]; 350 items = (Item[]) itemCollection.toArray(items); 351 Arrays.sort(items); 352 353 for (int i = 0; i < size; i++) { 354 items[i].write(dos, dotted); 355 } 356 } 357 358 361 private static abstract class Item implements Comparable { 362 private String m_name; 363 private int m_access; 364 private String m_desc; 365 366 Item(String name, int access, String desc) { 367 m_name = name; 368 m_access = access; 369 m_desc = desc; 370 } 371 372 protected abstract int filterAccess(int access); 374 375 public int compareTo(Object o) { 376 Item other = (Item) o; 377 int retVal = m_name.compareTo(other.m_name); 378 if (retVal == 0) { 379 retVal = m_desc.compareTo(other.m_desc); 380 } 381 return retVal; 382 } 383 384 void write(DataOutputStream dos, boolean dotted) throws IOException { 385 dos.writeUTF(m_name); 386 dos.writeInt(filterAccess(m_access)); 387 if (dotted) { 388 dos.writeUTF(m_desc.replace('/', '.')); 389 } else { 390 dos.writeUTF(m_desc); 391 } 392 } 393 } 394 395 398 private static class FieldItem extends Item { 399 FieldItem(String name, int access, String desc) { 400 super(name, access, desc); 401 } 402 403 protected int filterAccess(int access) { 404 return access & (ACC_PUBLIC | ACC_PRIVATE | ACC_PROTECTED | ACC_STATIC | ACC_FINAL 405 | ACC_VOLATILE | ACC_TRANSIENT); 406 } 407 } 408 409 412 private static class MethodItem extends Item { 413 MethodItem(String name, int access, String desc) { 414 super(name, access, desc); 415 } 416 417 protected int filterAccess(int access) { 418 return access & (ACC_PUBLIC | ACC_PRIVATE | ACC_PROTECTED | ACC_STATIC | ACC_FINAL 419 | ACC_SYNCHRONIZED | ACC_NATIVE | ACC_ABSTRACT | ACC_STRICT); 420 } 421 } 422 423 428 public static class Add extends ClassAdapter { 429 430 private InstrumentationContext m_ctx; 431 private ClassInfo m_classInfo; 432 433 public Add(ClassVisitor classVisitor, InstrumentationContext ctx, ClassInfo classInfo) { 434 super(classVisitor); 435 m_ctx = (InstrumentationContext) ctx; 436 m_classInfo = classInfo; 437 } 438 439 public void visitEnd() { 440 if (ClassInfoHelper.implementsInterface(m_classInfo, "java.io.Serializable")) { 441 ClassReader cr = new ClassReader(m_ctx.getInitialBytecode()); 442 ClassWriter cw = AsmHelper.newClassWriter(true); 443 SerialVersionUidVisitor sv = new SerialVersionUidVisitor(cw); 444 cr.accept(sv, true); 445 if (sv.m_computeSVUID && !sv.m_hadSVUID) { 446 cv.visitField(ACC_FINAL + ACC_STATIC, SVUID_NAME, "J", null, new Long (sv.m_SVUID)); 447 } 448 } 449 super.visitEnd(); 450 } 451 } 452 } 453 | Popular Tags |