1 45 package org.openejb.util.io; 46 47 import java.io.Externalizable ; 48 import java.io.IOException ; 49 import java.io.ObjectStreamClass ; 50 import java.io.ObjectStreamConstants ; 51 import java.io.ObjectStreamField ; 52 import java.io.Serializable ; 53 import java.lang.reflect.AccessibleObject ; 54 import java.lang.reflect.Field ; 55 import java.lang.reflect.Method ; 56 import java.lang.reflect.Modifier ; 57 import java.security.AccessController ; 58 import java.security.PrivilegedAction ; 59 import java.util.Arrays ; 60 61 public class ClassDescriptor implements java.io.Serializable , ObjectStreamConstants { 62 63 private static final ObjectStreamField [] serialPersistentFields = ObjectStreamClass.NO_FIELDS; 64 65 66 protected ClassDescriptor(Class clazz, ClassDescriptor superdesc, boolean serializable, boolean externalizable){ 67 68 if (externalizable) serializable = false; 69 70 this.forClass = clazz; 71 this.superdesc = superdesc; 72 this.serializable = serializable; 73 this.externalizable = externalizable; 74 this.name = forClass.getName(); 75 76 81 insertDescriptorFor(this); 82 83 if (externalizable) fields = NO_FIELDS; 84 else if (serializable) AccessController.doPrivileged(new AccessibleFieldInitializer(this)); 85 86 AccessController.doPrivileged(new SerializationPropertiesReflector(this)); 87 88 if (hasWriteObjectMethod) flags |= ObjectStreamConstants.SC_WRITE_METHOD; 89 if (serializable) flags |= ObjectStreamConstants.SC_SERIALIZABLE; 90 if (externalizable) flags |= ObjectStreamConstants.SC_EXTERNALIZABLE; 91 } 92 93 protected int flags = 0; 94 protected void writeClassInfo(ObjectOutputStream out) throws IOException { 95 out.writeByte(flags); 96 out.writeShort(fields.length); 97 98 for (int i=0; i < fields.length; i++) fields[i].writeDesc(out); 99 } 100 101 107 private boolean serializable; 108 private boolean externalizable; 109 110 113 protected boolean isSerializable() { 114 return serializable; 115 } 116 117 120 protected boolean isExternalizable() { 121 return externalizable; 122 } 123 124 protected boolean isNonSerializable() { 125 return ! (externalizable || serializable); 126 } 127 128 129 134 138 139 public static final FieldDescriptor[] NO_FIELDS = new FieldDescriptor[0]; 140 protected FieldDescriptor[] fields; 141 142 public FieldDescriptor[] getFields(){ 143 return fields; 144 } 145 146 public void setFields(FieldDescriptor[] fields){ 147 this.fields = fields; 148 } 149 150 156 private boolean hasWriteObjectMethod; 157 private boolean hasReadObjectMethod; 158 private Method writeObjectMethod; 159 private Method readObjectMethod; 160 161 public boolean hasWriteObjectMethod(){ 162 return hasWriteObjectMethod; 163 } 164 165 public void hasWriteObjectMethod(boolean b){ 166 hasWriteObjectMethod = b; 167 } 168 169 public Method getWriteObjectMethod(){ 170 return writeObjectMethod; 171 } 172 173 protected void setWriteObjectMethod(Method method){ 174 writeObjectMethod = method; 175 hasWriteObjectMethod = (method != null); 176 } 177 178 public boolean hasReadObjectMethod(){ 179 return hasReadObjectMethod; 180 } 181 182 public void hasReadObjectMethod(boolean b){ 183 hasReadObjectMethod = b; 184 } 185 186 public Method getReadObjectMethod(){ 187 return readObjectMethod; 188 } 189 190 protected void setReadObjectMethod(Method method){ 191 readObjectMethod = method; 192 hasReadObjectMethod = (method != null); 193 } 194 195 200 203 private long suid; 204 205 209 public long getSerialVersionUID() { 210 return suid; 211 } 212 213 protected void setSerialVersionUID(long suid){ 214 this.suid = suid; 215 } 216 217 220 private String name; 221 222 225 public String getName() { 226 return name; 227 } 228 229 232 private Class forClass; 233 234 238 public Class forClass() { 239 return forClass; 240 } 241 242 245 private ClassDescriptor superdesc; 246 247 250 protected ClassDescriptor getSuperclass() { 251 return superdesc; 252 } 253 254 257 protected void setSuperclass(ClassDescriptor s) { 258 superdesc = s; 259 } 260 261 264 public String toString() { 265 StringBuffer sb = new StringBuffer (); 266 267 sb.append(name); 268 sb.append(": static final long serialVersionUID = "); 269 sb.append(Long.toString(suid)); 270 sb.append("L;"); 271 return sb.toString(); 272 } 273 274 public static StringBuffer getSignature(Class clazz) { 275 StringBuffer buf = new StringBuffer (); 276 return getSignature(clazz, buf); 277 } 278 279 public static StringBuffer getSignature(Class clazz, StringBuffer buf) { 280 if (clazz.isPrimitive()) { 281 if (clazz == Integer.TYPE) buf.append('I'); 282 else if (clazz == Byte.TYPE) buf.append('B'); 283 else if (clazz == Long.TYPE) buf.append('J'); 284 else if (clazz == Float.TYPE) buf.append('F'); 285 else if (clazz == Double.TYPE) buf.append('D'); 286 else if (clazz == Short.TYPE) buf.append('S'); 287 else if (clazz == Character.TYPE) buf.append('C'); 288 else if (clazz == Boolean.TYPE) buf.append('Z'); 289 else if (clazz == Void.TYPE) buf.append('V'); 290 } 291 else if (clazz.isArray()) { 292 Class cl = clazz; 293 while (cl.isArray()) { 294 buf.append('['); 295 cl = cl.getComponentType(); 296 } 297 buf.append(getSignature(cl).toString()); 298 } 299 else { 300 buf.append('L'); 301 buf.append(clazz.getName().replace('.', '/')); 302 buf.append(';'); 303 } 304 return buf; 305 } 306 307 313 public static ClassDescriptor lookup(Class clazz){ 314 ClassDescriptor desc = lookupInternal(clazz); 315 if (desc.isSerializable() || desc.isExternalizable()) return desc; 316 return null; 317 } 318 319 323 static ClassDescriptor lookupInternal(Class clazz) { 324 327 ClassDescriptor desc = null; 328 synchronized (descriptorFor) { 329 330 desc = findDescriptorFor(clazz); 331 if (desc != null) { 332 return desc; 333 } 334 335 336 boolean serializable = Serializable .class.isAssignableFrom(clazz); 337 338 341 ClassDescriptor superdesc = null; 342 if (serializable) { 343 Class superclass = clazz.getSuperclass(); 344 if (superclass != null) 345 superdesc = lookup(superclass); 346 } 347 348 352 boolean externalizable = false; 353 if (serializable) { 354 externalizable = 355 ((superdesc != null) && superdesc.isExternalizable()) || 356 Externalizable .class.isAssignableFrom(clazz); 357 if (externalizable) { 358 serializable = false; 359 } 360 } 361 362 365 desc = new ClassDescriptor(clazz, superdesc, 366 serializable, externalizable); 367 } 368 return desc; 369 } 370 371 372 373 380 private static ClassDescriptor findDescriptorFor(Class clazz) { 381 382 int hash = clazz.hashCode(); 383 int index = (hash & 0x7FFFFFFF) % descriptorFor.length; 384 ClassDescriptorEntry e; 385 ClassDescriptorEntry prev; 386 387 388 while ((e = descriptorFor[index]) != null && e.get() == null) { 389 descriptorFor[index] = e.next; 390 } 391 392 395 prev = e; 396 while (e != null ) { 397 ClassDescriptor desc = (ClassDescriptor)(e.get()); 398 if (desc == null) { 399 prev.next = e.next; 401 } else { 402 if (desc.forClass == clazz) 403 return desc; 404 prev = e; 405 } 406 e = e.next; 407 } 408 return null; 409 } 410 411 414 private static void insertDescriptorFor(ClassDescriptor desc) { 415 if (findDescriptorFor(desc.forClass) != null) { 417 return; 418 } 419 420 int hash = desc.forClass.hashCode(); 421 int index = (hash & 0x7FFFFFFF) % descriptorFor.length; 422 ClassDescriptorEntry e = new ClassDescriptorEntry(desc); 423 e.next = descriptorFor[index]; 424 descriptorFor[index] = e; 425 } 426 427 431 private static class ClassDescriptorEntry extends java.lang.ref.SoftReference { 432 ClassDescriptorEntry next; 433 434 ClassDescriptorEntry(ClassDescriptor c) { 435 super(c); 436 } 437 } 438 439 static private ClassDescriptorEntry[] descriptorFor = new ClassDescriptorEntry[61]; 440 441 static final Class [] OIS_ARGS = {java.io.ObjectInputStream .class}; 451 static final Class [] OOS_ARGS = {java.io.ObjectOutputStream .class}; 452 private class SerializationPropertiesReflector implements PrivilegedAction { 453 454 455 ClassDescriptor desc; 456 457 public SerializationPropertiesReflector(ClassDescriptor desc){ 458 this.desc = desc; 459 } 460 461 public Object run() { 462 try { 463 Field field = null; 464 field = desc.forClass().getDeclaredField("serialVersionUID"); 465 int modifiers = field.getModifiers(); 466 if (Modifier.isStatic(modifiers) && Modifier.isFinal(modifiers)) { 467 field.setAccessible(true); 468 desc.setSerialVersionUID(field.getLong(desc.forClass())); 469 } 470 else desc.setSerialVersionUID(computeSerialVersionUID(desc.forClass())); 471 472 } 473 catch (NoSuchFieldException ex) { desc.setSerialVersionUID(computeSerialVersionUID(desc.forClass())); } 474 catch (IllegalAccessException ex) { desc.setSerialVersionUID(computeSerialVersionUID(desc.forClass())); } 475 476 if (serializable) { 477 desc.setWriteObjectMethod(getDeclaredMethod("writeObject", 478 ClassDescriptor.OOS_ARGS, 479 Modifier.PRIVATE, 480 Modifier.STATIC)); 481 482 desc.setWriteObjectMethod(getDeclaredMethod("readObject", 483 ClassDescriptor.OIS_ARGS, 484 Modifier.PRIVATE, 485 Modifier.STATIC)); 486 } 487 return null; 488 } 489 490 private Method getDeclaredMethod(String methodName, Class [] args, int requiredModifierMask, int disallowedModifierMask) { 491 Method method = null; 492 try { 493 method = forClass.getDeclaredMethod(methodName, args); 494 if (method != null) { 495 int mods = method.getModifiers(); 496 if ((mods & disallowedModifierMask) != 0 || (mods & requiredModifierMask) != requiredModifierMask) 497 method = null; 498 else method.setAccessible(true); 499 500 } 501 } 502 catch (NoSuchMethodException e) { } 503 return method; 504 } 505 506 private long computeSerialVersionUID(Class clazz){ 507 510 return 42L; 511 } 512 513 } 514 515 private static class AccessibleFieldInitializer implements PrivilegedAction { 525 526 ClassDescriptor desc; 527 528 public AccessibleFieldInitializer(ClassDescriptor desc){ 529 this.desc = desc; 530 } 531 532 533 public Object run() { 534 FieldDescriptor[] fields = getDeclaredSerialPersistentFields(desc.forClass()); 535 if (fields == null) fields = reflectForFields(desc.forClass()); 536 537 if (fields.length > 1) Arrays.sort(fields); 538 539 desc.setFields(fields); 540 return null; 541 } 542 543 private FieldDescriptor[] getDeclaredSerialPersistentFields(Class clazz) throws SecurityException { 544 java.lang.reflect.Field [] tmpFields = null; 545 ObjectStreamField [] outputStreamFields; 546 547 try { 548 Field serialPersistentFields = clazz.getDeclaredField("serialPersistentFields"); 549 550 if (!Modifier.isPrivate(serialPersistentFields.getModifiers())) return null; 551 552 serialPersistentFields.setAccessible(true); 553 554 561 562 outputStreamFields = (ObjectStreamField [])serialPersistentFields.get(clazz); 563 tmpFields = new Field [outputStreamFields.length]; 564 565 } 566 catch (NoSuchFieldException e) { return null; } 567 catch (IllegalAccessException e) { return null; } 568 catch (IllegalArgumentException e) { return null; } 569 570 573 Field reflectedField; 574 int validFields = 0; 575 for (int i = outputStreamFields.length-1; i >= 0; i--){ 576 try { 577 reflectedField = clazz.getDeclaredField(outputStreamFields[i].getName()); 578 if (outputStreamFields[i].getType() == reflectedField.getType()) { 579 reflectedField.setAccessible(true); 580 tmpFields[validFields++] = reflectedField; 581 } 582 } 583 catch (NoSuchFieldException e) { } 584 } 585 586 FieldDescriptor[] validFieldDescriptors = new FieldDescriptor[validFields]; 587 588 for (validFields-- ; validFields >= 0; validFields--){ 589 validFieldDescriptors[validFields] = new FieldDescriptor(tmpFields[validFields]); 590 } 591 592 return validFieldDescriptors; 593 } 594 595 598 private FieldDescriptor[] reflectForFields(Class clazz) { 599 600 Field [] allFields = clazz.getDeclaredFields(); 601 AccessibleObject.setAccessible(allFields, true); 602 Field [] tmpFields = new Field [allFields.length]; 603 604 int validFields = 0, modifiers; 605 606 for (int i = 0; i < allFields.length; i++) { 607 modifiers = allFields[i].getModifiers(); 608 if (!Modifier.isStatic(modifiers) && !Modifier.isTransient(modifiers)) 609 tmpFields[validFields++] = allFields[i]; 610 } 611 612 FieldDescriptor[] validFieldDescriptors = new FieldDescriptor[validFields]; 613 614 for (validFields-- ; validFields >= 0; validFields--){ 615 validFieldDescriptors[validFields] = new FieldDescriptor(tmpFields[validFields]); 616 } 617 618 return validFieldDescriptors; 619 } 620 } 621 622 } | Popular Tags |