1 30 package com.tc.asm.commons; 31 32 import java.io.ByteArrayOutputStream ; 33 import java.io.DataOutputStream ; 34 import java.io.IOException ; 35 import java.security.MessageDigest ; 36 import java.security.NoSuchAlgorithmException ; 37 import java.util.ArrayList ; 38 import java.util.Arrays ; 39 import java.util.Collection ; 40 41 import com.tc.asm.ClassAdapter; 42 import com.tc.asm.ClassVisitor; 43 import com.tc.asm.FieldVisitor; 44 import com.tc.asm.MethodVisitor; 45 import com.tc.asm.Opcodes; 46 47 114 public class SerialVersionUIDAdder extends ClassAdapter { 115 116 119 protected boolean computeSVUID; 120 121 124 protected boolean hasSVUID; 125 126 129 protected int access; 130 131 134 protected String name; 135 136 139 protected String [] interfaces; 140 141 145 protected Collection svuidFields; 146 147 150 protected boolean hasStaticInitializer; 151 152 155 protected Collection svuidConstructors; 156 157 160 protected Collection svuidMethods; 161 162 168 public SerialVersionUIDAdder(final ClassVisitor cv) { 169 super(cv); 170 svuidFields = new ArrayList (); 171 svuidConstructors = new ArrayList (); 172 svuidMethods = new ArrayList (); 173 } 174 175 179 183 public void visit( 184 final int version, 185 final int access, 186 final String name, 187 final String signature, 188 final String superName, 189 final String [] interfaces) 190 { 191 computeSVUID = (access & Opcodes.ACC_INTERFACE) == 0; 192 193 if (computeSVUID) { 194 this.name = name; 195 this.access = access; 196 this.interfaces = interfaces; 197 } 198 199 super.visit(version, access, name, signature, superName, interfaces); 200 } 201 202 206 public MethodVisitor visitMethod( 207 final int access, 208 final String name, 209 final String desc, 210 final String signature, 211 final String [] exceptions) 212 { 213 if (computeSVUID) { 214 if (name.equals("<clinit>")) { 215 hasStaticInitializer = true; 216 } 217 224 int mods = access 225 & (Opcodes.ACC_PUBLIC | Opcodes.ACC_PRIVATE 226 | Opcodes.ACC_PROTECTED | Opcodes.ACC_STATIC 227 | Opcodes.ACC_FINAL | Opcodes.ACC_SYNCHRONIZED 228 | Opcodes.ACC_NATIVE | Opcodes.ACC_ABSTRACT | Opcodes.ACC_STRICT); 229 230 if ((access & Opcodes.ACC_PRIVATE) == 0) { 232 if (name.equals("<init>")) { 233 svuidConstructors.add(new Item(name, mods, desc)); 234 } else if (!name.equals("<clinit>")) { 235 svuidMethods.add(new Item(name, mods, desc)); 236 } 237 } 238 } 239 240 return cv.visitMethod(access, name, desc, signature, exceptions); 241 } 242 243 247 public FieldVisitor visitField( 248 final int access, 249 final String name, 250 final String desc, 251 final String signature, 252 final Object value) 253 { 254 if (computeSVUID) { 255 if (name.equals("serialVersionUID")) { 256 computeSVUID = false; 258 hasSVUID = true; 259 } 260 266 int mods = access 267 & (Opcodes.ACC_PUBLIC | Opcodes.ACC_PRIVATE 268 | Opcodes.ACC_PROTECTED | Opcodes.ACC_STATIC 269 | Opcodes.ACC_FINAL | Opcodes.ACC_VOLATILE | Opcodes.ACC_TRANSIENT); 270 271 if (((access & Opcodes.ACC_PRIVATE) == 0) 272 || ((access & (Opcodes.ACC_STATIC | Opcodes.ACC_TRANSIENT)) == 0)) 273 { 274 svuidFields.add(new Item(name, mods, desc)); 275 } 276 } 277 278 return super.visitField(access, name, desc, signature, value); 279 } 280 281 284 public void visitEnd() { 285 if (computeSVUID && !hasSVUID) { 287 try { 288 cv.visitField(Opcodes.ACC_FINAL + Opcodes.ACC_STATIC, 289 "serialVersionUID", 290 "J", 291 null, 292 new Long (computeSVUID())); 293 } catch (Throwable e) { 294 throw new RuntimeException ("Error while computing SVUID for " 295 + name, e); 296 } 297 } 298 299 super.visitEnd(); 300 } 301 302 306 315 protected long computeSVUID() throws IOException , NoSuchAlgorithmException { 316 if (hasSVUID) { 317 return 0; 318 } 319 320 ByteArrayOutputStream bos = null; 321 DataOutputStream dos = null; 322 long svuid = 0; 323 324 try { 325 bos = new ByteArrayOutputStream (); 326 dos = new DataOutputStream (bos); 327 328 331 dos.writeUTF(name.replace('/', '.')); 332 333 336 dos.writeInt(access 337 & (Opcodes.ACC_PUBLIC | Opcodes.ACC_FINAL 338 | Opcodes.ACC_INTERFACE | Opcodes.ACC_ABSTRACT)); 339 340 344 Arrays.sort(interfaces); 345 for (int i = 0; i < interfaces.length; i++) { 346 dos.writeUTF(interfaces[i].replace('/', '.')); 347 } 348 349 360 writeItems(svuidFields, dos, false); 361 362 369 if (hasStaticInitializer) { 370 dos.writeUTF("<clinit>"); 371 dos.writeInt(Opcodes.ACC_STATIC); 372 dos.writeUTF("()V"); 373 } 375 381 writeItems(svuidConstructors, dos, true); 382 383 389 writeItems(svuidMethods, dos, true); 390 391 dos.flush(); 392 393 398 MessageDigest md = MessageDigest.getInstance("SHA"); 399 400 413 byte[] hashBytes = md.digest(bos.toByteArray()); 414 for (int i = Math.min(hashBytes.length, 8) - 1; i >= 0; i--) { 415 svuid = (svuid << 8) | (hashBytes[i] & 0xFF); 416 } 417 } finally { 418 if (dos != null) { 420 dos.close(); 421 } 422 } 423 424 return svuid; 425 } 426 427 435 private void writeItems( 436 final Collection itemCollection, 437 final DataOutputStream dos, 438 final boolean dotted) throws IOException 439 { 440 int size = itemCollection.size(); 441 Item items[] = (Item[]) itemCollection.toArray(new Item[size]); 442 Arrays.sort(items); 443 for (int i = 0; i < size; i++) { 444 dos.writeUTF(items[i].name); 445 dos.writeInt(items[i].access); 446 dos.writeUTF(dotted 447 ? items[i].desc.replace('/', '.') 448 : items[i].desc); 449 } 450 } 451 452 456 static class Item implements Comparable { 457 458 String name; 459 460 int access; 461 462 String desc; 463 464 Item(final String name, final int access, final String desc) { 465 this.name = name; 466 this.access = access; 467 this.desc = desc; 468 } 469 470 public int compareTo(final Object o) { 471 Item other = (Item) o; 472 int retVal = name.compareTo(other.name); 473 if (retVal == 0) { 474 retVal = desc.compareTo(other.desc); 475 } 476 return retVal; 477 } 478 } 479 } 480 | Popular Tags |