1 30 package org.objectweb.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 org.objectweb.asm.ClassAdapter; 42 import org.objectweb.asm.ClassVisitor; 43 import org.objectweb.asm.FieldVisitor; 44 import org.objectweb.asm.MethodVisitor; 45 import org.objectweb.asm.Opcodes; 46 47 105 public class SerialVersionUIDAdder extends ClassAdapter { 106 107 110 protected boolean computeSVUID; 111 112 115 protected boolean hasSVUID; 116 117 120 protected int access; 121 122 125 protected String name; 126 127 130 protected String [] interfaces; 131 132 136 protected Collection svuidFields; 137 138 141 protected boolean hasStaticInitializer; 142 143 146 protected Collection svuidConstructors; 147 148 151 protected Collection svuidMethods; 152 153 159 public SerialVersionUIDAdder(final ClassVisitor cv) { 160 super(cv); 161 svuidFields = new ArrayList (); 162 svuidConstructors = new ArrayList (); 163 svuidMethods = new ArrayList (); 164 } 165 166 170 174 public void visit( 175 final int version, 176 final int access, 177 final String name, 178 final String signature, 179 final String superName, 180 final String [] interfaces) 181 { 182 computeSVUID = (access & Opcodes.ACC_INTERFACE) == 0; 183 184 if (computeSVUID) { 185 this.name = name; 186 this.access = access; 187 this.interfaces = interfaces; 188 } 189 190 super.visit(version, access, name, signature, superName, interfaces); 191 } 192 193 197 public MethodVisitor visitMethod( 198 final int access, 199 final String name, 200 final String desc, 201 final String signature, 202 final String [] exceptions) 203 { 204 if (computeSVUID) { 205 if (name.equals("<clinit>")) { 206 hasStaticInitializer = true; 207 } 208 215 int mods = access 216 & (Opcodes.ACC_PUBLIC | Opcodes.ACC_PRIVATE 217 | Opcodes.ACC_PROTECTED | Opcodes.ACC_STATIC 218 | Opcodes.ACC_FINAL | Opcodes.ACC_SYNCHRONIZED 219 | Opcodes.ACC_NATIVE | Opcodes.ACC_ABSTRACT | Opcodes.ACC_STRICT); 220 221 if ((access & Opcodes.ACC_PRIVATE) == 0) { 223 if (name.equals("<init>")) { 224 svuidConstructors.add(new Item(name, mods, desc)); 225 } else if (!name.equals("<clinit>")) { 226 svuidMethods.add(new Item(name, mods, desc)); 227 } 228 } 229 } 230 231 return cv.visitMethod(access, name, desc, signature, exceptions); 232 } 233 234 238 public FieldVisitor visitField( 239 final int access, 240 final String name, 241 final String desc, 242 final String signature, 243 final Object value) 244 { 245 if (computeSVUID) { 246 if (name.equals("serialVersionUID")) { 247 computeSVUID = false; 249 hasSVUID = true; 250 } 251 257 int mods = access 258 & (Opcodes.ACC_PUBLIC | Opcodes.ACC_PRIVATE 259 | Opcodes.ACC_PROTECTED | Opcodes.ACC_STATIC 260 | Opcodes.ACC_FINAL | Opcodes.ACC_VOLATILE | Opcodes.ACC_TRANSIENT); 261 262 if (((access & Opcodes.ACC_PRIVATE) == 0) 263 || ((access & (Opcodes.ACC_STATIC | Opcodes.ACC_TRANSIENT)) == 0)) 264 { 265 svuidFields.add(new Item(name, mods, desc)); 266 } 267 } 268 269 return super.visitField(access, name, desc, signature, value); 270 } 271 272 275 public void visitEnd() { 276 if (computeSVUID && !hasSVUID) { 278 try { 279 cv.visitField(Opcodes.ACC_FINAL + Opcodes.ACC_STATIC, 280 "serialVersionUID", 281 "J", 282 null, 283 new Long (computeSVUID())); 284 } catch (Throwable e) { 285 throw new RuntimeException ("Error while computing SVUID for " 286 + name, e); 287 } 288 } 289 290 super.visitEnd(); 291 } 292 293 297 306 protected long computeSVUID() throws IOException , NoSuchAlgorithmException { 307 if (hasSVUID) { 308 return 0; 309 } 310 311 ByteArrayOutputStream bos = null; 312 DataOutputStream dos = null; 313 long svuid = 0; 314 315 try { 316 bos = new ByteArrayOutputStream (); 317 dos = new DataOutputStream (bos); 318 319 322 dos.writeUTF(name.replace('/', '.')); 323 324 327 dos.writeInt(access 328 & (Opcodes.ACC_PUBLIC | Opcodes.ACC_FINAL 329 | Opcodes.ACC_INTERFACE | Opcodes.ACC_ABSTRACT)); 330 331 335 Arrays.sort(interfaces); 336 for (int i = 0; i < interfaces.length; i++) { 337 dos.writeUTF(interfaces[i].replace('/', '.')); 338 } 339 340 351 writeItems(svuidFields, dos, false); 352 353 360 if (hasStaticInitializer) { 361 dos.writeUTF("<clinit>"); 362 dos.writeInt(Opcodes.ACC_STATIC); 363 dos.writeUTF("()V"); 364 } 366 372 writeItems(svuidConstructors, dos, true); 373 374 380 writeItems(svuidMethods, dos, true); 381 382 dos.flush(); 383 384 389 MessageDigest md = MessageDigest.getInstance("SHA"); 390 391 404 byte[] hashBytes = md.digest(bos.toByteArray()); 405 for (int i = Math.min(hashBytes.length, 8) - 1; i >= 0; i--) { 406 svuid = (svuid << 8) | (hashBytes[i] & 0xFF); 407 } 408 } finally { 409 if (dos != null) { 411 dos.close(); 412 } 413 } 414 415 return svuid; 416 } 417 418 426 private void writeItems( 427 final Collection itemCollection, 428 final DataOutputStream dos, 429 final boolean dotted) throws IOException 430 { 431 int size = itemCollection.size(); 432 Item items[] = (Item[]) itemCollection.toArray(new Item[size]); 433 Arrays.sort(items); 434 for (int i = 0; i < size; i++) { 435 dos.writeUTF(items[i].name); 436 dos.writeInt(items[i].access); 437 dos.writeUTF(dotted 438 ? items[i].desc.replace('/', '.') 439 : items[i].desc); 440 } 441 } 442 443 447 static class Item implements Comparable { 448 449 String name; 450 451 int access; 452 453 String desc; 454 455 Item(final String name, final int access, final String desc) { 456 this.name = name; 457 this.access = access; 458 this.desc = desc; 459 } 460 461 public int compareTo(final Object o) { 462 Item other = (Item) o; 463 int retVal = name.compareTo(other.name); 464 if (retVal == 0) { 465 retVal = desc.compareTo(other.desc); 466 } 467 return retVal; 468 } 469 } 470 } 471 | Popular Tags |