1 /* 2 * Copyright (c) 2000, 2009, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 package java.beans; 26 27 import com.sun.beans.finder.PrimitiveWrapperMap; 28 29 import java.awt.AWTKeyStroke; 30 import java.awt.BorderLayout; 31 import java.awt.Dimension; 32 import java.awt.Color; 33 import java.awt.Font; 34 import java.awt.GridBagConstraints; 35 import java.awt.Insets; 36 import java.awt.Point; 37 import java.awt.Rectangle; 38 import java.awt.event.KeyEvent; 39 import java.awt.font.TextAttribute; 40 41 import java.lang.reflect.Array; 42 import java.lang.reflect.Constructor; 43 import java.lang.reflect.Field; 44 import java.lang.reflect.Method; 45 import java.lang.reflect.InvocationTargetException; 46 47 import java.security.AccessController; 48 import java.security.PrivilegedAction; 49 50 import java.util.*; 51 52 import javax.swing.Box; 53 import javax.swing.JLayeredPane; 54 import javax.swing.border.MatteBorder; 55 import javax.swing.plaf.ColorUIResource; 56 57 import sun.swing.PrintColorUIResource; 58 59 /* 60 * Like the <code>Intropector</code>, the <code>MetaData</code> class 61 * contains <em>meta</em> objects that describe the way 62 * classes should express their state in terms of their 63 * own public APIs. 64 * 65 * @see java.beans.Intropector 66 * 67 * @author Philip Milne 68 * @author Steve Langley 69 */ 70 71 class NullPersistenceDelegate extends PersistenceDelegate { 72 // Note this will be called by all classes when they reach the 73 // top of their superclass chain. 74 protected void initialize(Class<?> type, Object oldInstance, Object newInstance, Encoder out) { 75 } 76 protected Expression instantiate(Object oldInstance, Encoder out) { return null; } 77 78 public void writeObject(Object oldInstance, Encoder out) { 79 // System.out.println("NullPersistenceDelegate:writeObject " + oldInstance); 80 } 81 } 82 83 /** 84 * The persistence delegate for <CODE>enum</CODE> classes. 85 * 86 * @author Sergey A. Malenkov 87 */ 88 class EnumPersistenceDelegate extends PersistenceDelegate { 89 protected boolean mutatesTo(Object oldInstance, Object newInstance) { 90 return oldInstance == newInstance; 91 } 92 93 protected Expression instantiate(Object oldInstance, Encoder out) { 94 Enum e = (Enum) oldInstance; 95 return new Expression(e, Enum.class, "valueOf", new Object[]{e.getDeclaringClass(), e.name()}); 96 } 97 } 98 99 class PrimitivePersistenceDelegate extends PersistenceDelegate { 100 protected boolean mutatesTo(Object oldInstance, Object newInstance) { 101 return oldInstance.equals(newInstance); 102 } 103 104 protected Expression instantiate(Object oldInstance, Encoder out) { 105 return new Expression(oldInstance, oldInstance.getClass(), 106 "new", new Object[]{oldInstance.toString()}); 107 } 108 } 109 110 class ArrayPersistenceDelegate extends PersistenceDelegate { 111 protected boolean mutatesTo(Object oldInstance, Object newInstance) { 112 return (newInstance != null && 113 oldInstance.getClass() == newInstance.getClass() && // Also ensures the subtype is correct. 114 Array.getLength(oldInstance) == Array.getLength(newInstance)); 115 } 116 117 protected Expression instantiate(Object oldInstance, Encoder out) { 118 // System.out.println("instantiate: " + type + " " + oldInstance); 119 Class oldClass = oldInstance.getClass(); 120 return new Expression(oldInstance, Array.class, "newInstance", 121 new Object[]{oldClass.getComponentType(), 122 new Integer(Array.getLength(oldInstance))}); 123 } 124 125 protected void initialize(Class<?> type, Object oldInstance, Object newInstance, Encoder out) { 126 int n = Array.getLength(oldInstance); 127 for (int i = 0; i < n; i++) { 128 Object index = new Integer(i); 129 // Expression oldGetExp = new Expression(Array.class, "get", new Object[]{oldInstance, index}); 130 // Expression newGetExp = new Expression(Array.class, "get", new Object[]{newInstance, index}); 131 Expression oldGetExp = new Expression(oldInstance, "get", new Object[]{index}); 132 Expression newGetExp = new Expression(newInstance, "get", new Object[]{index}); 133 try { 134 Object oldValue = oldGetExp.getValue(); 135 Object newValue = newGetExp.getValue(); 136 out.writeExpression(oldGetExp); 137 if (!MetaData.equals(newValue, out.get(oldValue))) { 138 // System.out.println("Not equal: " + newGetExp + " != " + actualGetExp); 139 // invokeStatement(Array.class, "set", new Object[]{oldInstance, index, oldValue}, out); 140 DefaultPersistenceDelegate.invokeStatement(oldInstance, "set", new Object[]{index, oldValue}, out); 141 } 142 } 143 catch (Exception e) { 144 // System.err.println("Warning:: failed to write: " + oldGetExp); 145 out.getExceptionListener().exceptionThrown(e); 146 } 147 } 148 } 149 } 150 151 class ProxyPersistenceDelegate extends PersistenceDelegate { 152 protected Expression instantiate(Object oldInstance, Encoder out) { 153 Class type = oldInstance.getClass(); 154 java.lang.reflect.Proxy p = (java.lang.reflect.Proxy)oldInstance; 155 // This unappealing hack is not required but makes the 156 // representation of EventHandlers much more concise. 157 java.lang.reflect.InvocationHandler ih = java.lang.reflect.Proxy.getInvocationHandler(p); 158 if (ih instanceof EventHandler) { 159 EventHandler eh = (EventHandler)ih; 160 Vector args = new Vector(); 161 args.add(type.getInterfaces()[0]); 162 args.add(eh.getTarget()); 163 args.add(eh.getAction()); 164 if (eh.getEventPropertyName() != null) { 165 args.add(eh.getEventPropertyName()); 166 } 167 if (eh.getListenerMethodName() != null) { 168 args.setSize(4); 169 args.add(eh.getListenerMethodName()); 170 } 171 return new Expression(oldInstance, 172 EventHandler.class, 173 "create", 174 args.toArray()); 175 } 176 return new Expression(oldInstance, 177 java.lang.reflect.Proxy.class, 178 "newProxyInstance", 179 new Object[]{type.getClassLoader(), 180 type.getInterfaces(), 181 ih}); 182 } 183 } 184 185 // Strings 186 class java_lang_String_PersistenceDelegate extends PersistenceDelegate { 187 protected Expression instantiate(Object oldInstance, Encoder out) { return null; } 188 189 public void writeObject(Object oldInstance, Encoder out) { 190 // System.out.println("NullPersistenceDelegate:writeObject " + oldInstance); 191 } 192 } 193 194 // Classes 195 class java_lang_Class_PersistenceDelegate extends PersistenceDelegate { 196 protected boolean mutatesTo(Object oldInstance, Object newInstance) { 197 return oldInstance.equals(newInstance); 198 } 199 200 protected Expression instantiate(Object oldInstance, Encoder out) { 201 Class c = (Class)oldInstance; 202 // As of 1.3 it is not possible to call Class.forName("int"), 203 // so we have to generate different code for primitive types. 204 // This is needed for arrays whose subtype may be primitive. 205 if (c.isPrimitive()) { 206 Field field = null; 207 try { 208 field = PrimitiveWrapperMap.getType(c.getName()).getDeclaredField("TYPE"); 209 } catch (NoSuchFieldException ex) { 210 System.err.println("Unknown primitive type: " + c); 211 } 212 return new Expression(oldInstance, field, "get", new Object[]{null}); 213 } 214 else if (oldInstance == String.class) { 215 return new Expression(oldInstance, "", "getClass", new Object[]{}); 216 } 217 else if (oldInstance == Class.class) { 218 return new Expression(oldInstance, String.class, "getClass", new Object[]{}); 219 } 220 else { 221 Expression newInstance = new Expression(oldInstance, Class.class, "forName", new Object[] { c.getName() }); 222 newInstance.loader = c.getClassLoader(); 223 return newInstance; 224 } 225 } 226 } 227 228 // Fields 229 class java_lang_reflect_Field_PersistenceDelegate extends PersistenceDelegate { 230 protected boolean mutatesTo(Object oldInstance, Object newInstance) { 231 return oldInstance.equals(newInstance); 232 } 233 234 protected Expression instantiate(Object oldInstance, Encoder out) { 235 Field f = (Field)oldInstance; 236 return new Expression(oldInstance, 237 f.getDeclaringClass(), 238 "getField", 239 new Object[]{f.getName()}); 240 } 241 } 242 243 // Methods 244 class java_lang_reflect_Method_PersistenceDelegate extends PersistenceDelegate { 245 protected boolean mutatesTo(Object oldInstance, Object newInstance) { 246 return oldInstance.equals(newInstance); 247 } 248 249 protected Expression instantiate(Object oldInstance, Encoder out) { 250 Method m = (Method)oldInstance; 251 return new Expression(oldInstance, 252 m.getDeclaringClass(), 253 "getMethod", 254 new Object[]{m.getName(), m.getParameterTypes()}); 255 } 256 } 257 258 // Dates 259 260 /** 261 * The persistence delegate for <CODE>java.util.Date</CODE> classes. 262 * Do not extend DefaultPersistenceDelegate to improve performance and 263 * to avoid problems with <CODE>java.sql.Date</CODE>, 264 * <CODE>java.sql.Time</CODE> and <CODE>java.sql.Timestamp</CODE>. 265 * 266 * @author Sergey A. Malenkov 267 */ 268 class java_util_Date_PersistenceDelegate extends PersistenceDelegate { 269 protected boolean mutatesTo(Object oldInstance, Object newInstance) { 270 if (!super.mutatesTo(oldInstance, newInstance)) { 271 return false; 272 } 273 Date oldDate = (Date)oldInstance; 274 Date newDate = (Date)newInstance; 275 276 return oldDate.getTime() == newDate.getTime(); 277 } 278 279 protected Expression instantiate(Object oldInstance, Encoder out) { 280 Date date = (Date)oldInstance; 281 return new Expression(date, date.getClass(), "new", new Object[] {date.getTime()}); 282 } 283 } 284 285 /** 286 * The persistence delegate for <CODE>java.sql.Timestamp</CODE> classes. 287 * It supports nanoseconds. 288 * 289 * @author Sergey A. Malenkov 290 */ 291 final class java_sql_Timestamp_PersistenceDelegate extends java_util_Date_PersistenceDelegate { 292 private static final Method getNanosMethod = getNanosMethod(); 293 294 private static Method getNanosMethod() { 295 try { 296 Class<?> c = Class.forName("java.sql.Timestamp", true, null); 297 return c.getMethod("getNanos"); 298 } catch (ClassNotFoundException e) { 299 return null; 300 } catch (NoSuchMethodException e) { 301 throw new AssertionError(e); 302 } 303 } 304 305 /** 306 * Invoke Timstamp getNanos. 307 */ 308 private static int getNanos(Object obj) { 309 if (getNanosMethod == null) 310 throw new AssertionError("Should not get here"); 311 try { 312 return (Integer)getNanosMethod.invoke(obj); 313 } catch (InvocationTargetException e) { 314 Throwable cause = e.getCause(); 315 if (cause instanceof RuntimeException) 316 throw (RuntimeException)cause; 317 if (cause instanceof Error) 318 throw (Error)cause; 319 throw new AssertionError(e); 320 } catch (IllegalAccessException iae) { 321 throw new AssertionError(iae); 322 } 323 } 324 325 protected void initialize(Class<?> type, Object oldInstance, Object newInstance, Encoder out) { 326 // assumes oldInstance and newInstance are Timestamps 327 int nanos = getNanos(oldInstance); 328 if (nanos != getNanos(newInstance)) { 329 out.writeStatement(new Statement(oldInstance, "setNanos", new Object[] {nanos})); 330 } 331 } 332 } 333 334 // Collections 335 336 /* 337 The Hashtable and AbstractMap classes have no common ancestor yet may 338 be handled with a single persistence delegate: one which uses the methods 339 of the Map insterface exclusively. Attatching the persistence delegates 340 to the interfaces themselves is fraught however since, in the case of 341 the Map, both the AbstractMap and HashMap classes are declared to 342 implement the Map interface, leaving the obvious implementation prone 343 to repeating their initialization. These issues and questions around 344 the ordering of delegates attached to interfaces have lead us to 345 ignore any delegates attached to interfaces and force all persistence 346 delegates to be registered with concrete classes. 347 */ 348 349 /** 350 * The base class for persistence delegates for inner classes 351 * that can be created using {@link Collections}. 352 * 353 * @author Sergey A. Malenkov 354 */ 355 abstract class java_util_Collections extends PersistenceDelegate { 356 protected boolean mutatesTo(Object oldInstance, Object newInstance) { 357 if (!super.mutatesTo(oldInstance, newInstance)) { 358 return false; 359 } 360 if ((oldInstance instanceof List) || (oldInstance instanceof Set) || (oldInstance instanceof Map)) { 361 return oldInstance.equals(newInstance); 362 } 363 Collection oldC = (Collection) oldInstance; 364 Collection newC = (Collection) newInstance; 365 return (oldC.size() == newC.size()) && oldC.containsAll(newC); 366 } 367 368 static final class EmptyList_PersistenceDelegate extends java_util_Collections { 369 protected Expression instantiate(Object oldInstance, Encoder out) { 370 return new Expression(oldInstance, Collections.class, "emptyList", null); 371 } 372 } 373 374 static final class EmptySet_PersistenceDelegate extends java_util_Collections { 375 protected Expression instantiate(Object oldInstance, Encoder out) { 376 return new Expression(oldInstance, Collections.class, "emptySet", null); 377 } 378 } 379 380 static final class EmptyMap_PersistenceDelegate extends java_util_Collections { 381 protected Expression instantiate(Object oldInstance, Encoder out) { 382 return new Expression(oldInstance, Collections.class, "emptyMap", null); 383 } 384 } 385 386 static final class SingletonList_PersistenceDelegate extends java_util_Collections { 387 protected Expression instantiate(Object oldInstance, Encoder out) { 388 List list = (List) oldInstance; 389 return new Expression(oldInstance, Collections.class, "singletonList", new Object[]{list.get(0)}); 390 } 391 } 392 393 static final class SingletonSet_PersistenceDelegate extends java_util_Collections { 394 protected Expression instantiate(Object oldInstance, Encoder out) { 395 Set set = (Set) oldInstance; 396 return new Expression(oldInstance, Collections.class, "singleton", new Object[]{set.iterator().next()}); 397 } 398 } 399 400 static final class SingletonMap_PersistenceDelegate extends java_util_Collections { 401 protected Expression instantiate(Object oldInstance, Encoder out) { 402 Map map = (Map) oldInstance; 403 Object key = map.keySet().iterator().next(); 404 return new Expression(oldInstance, Collections.class, "singletonMap", new Object[]{key, map.get(key)}); 405 } 406 } 407 408 static final class UnmodifiableCollection_PersistenceDelegate extends java_util_Collections { 409 protected Expression instantiate(Object oldInstance, Encoder out) { 410 List list = new ArrayList((Collection) oldInstance); 411 return new Expression(oldInstance, Collections.class, "unmodifiableCollection", new Object[]{list}); 412 } 413 } 414 415 static final class UnmodifiableList_PersistenceDelegate extends java_util_Collections { 416 protected Expression instantiate(Object oldInstance, Encoder out) { 417 List list = new LinkedList((Collection) oldInstance); 418 return new Expression(oldInstance, Collections.class, "unmodifiableList", new Object[]{list}); 419 } 420 } 421 422 static final class UnmodifiableRandomAccessList_PersistenceDelegate extends java_util_Collections { 423 protected Expression instantiate(Object oldInstance, Encoder out) { 424 List list = new ArrayList((Collection) oldInstance); 425 return new Expression(oldInstance, Collections.class, "unmodifiableList", new Object[]{list}); 426 } 427 } 428 429 static final class UnmodifiableSet_PersistenceDelegate extends java_util_Collections { 430 protected Expression instantiate(Object oldInstance, Encoder out) { 431 Set set = new HashSet((Set) oldInstance); 432 return new Expression(oldInstance, Collections.class, "unmodifiableSet", new Object[]{set}); 433 } 434 } 435 436 static final class UnmodifiableSortedSet_PersistenceDelegate extends java_util_Collections { 437 protected Expression instantiate(Object oldInstance, Encoder out) { 438 SortedSet set = new TreeSet((SortedSet) oldInstance); 439 return new Expression(oldInstance, Collections.class, "unmodifiableSortedSet", new Object[]{set}); 440 } 441 } 442 443 static final class UnmodifiableMap_PersistenceDelegate extends java_util_Collections { 444 protected Expression instantiate(Object oldInstance, Encoder out) { 445 Map map = new HashMap((Map) oldInstance); 446 return new Expression(oldInstance, Collections.class, "unmodifiableMap", new Object[]{map}); 447 } 448 } 449 450 static final class UnmodifiableSortedMap_PersistenceDelegate extends java_util_Collections { 451 protected Expression instantiate(Object oldInstance, Encoder out) { 452 SortedMap map = new TreeMap((SortedMap) oldInstance); 453 return new Expression(oldInstance, Collections.class, "unmodifiableSortedMap", new Object[]{map}); 454 } 455 } 456 457 static final class SynchronizedCollection_PersistenceDelegate extends java_util_Collections { 458 protected Expression instantiate(Object oldInstance, Encoder out) { 459 List list = new ArrayList((Collection) oldInstance); 460 return new Expression(oldInstance, Collections.class, "synchronizedCollection", new Object[]{list}); 461 } 462 } 463 464 static final class SynchronizedList_PersistenceDelegate extends java_util_Collections { 465 protected Expression instantiate(Object oldInstance, Encoder out) { 466 List list = new LinkedList((Collection) oldInstance); 467 return new Expression(oldInstance, Collections.class, "synchronizedList", new Object[]{list}); 468 } 469 } 470 471 static final class SynchronizedRandomAccessList_PersistenceDelegate extends java_util_Collections { 472 protected Expression instantiate(Object oldInstance, Encoder out) { 473 List list = new ArrayList((Collection) oldInstance); 474 return new Expression(oldInstance, Collections.class, "synchronizedList", new Object[]{list}); 475 } 476 } 477 478 static final class SynchronizedSet_PersistenceDelegate extends java_util_Collections { 479 protected Expression instantiate(Object oldInstance, Encoder out) { 480 Set set = new HashSet((Set) oldInstance); 481 return new Expression(oldInstance, Collections.class, "synchronizedSet", new Object[]{set}); 482 } 483 } 484 485 static final class SynchronizedSortedSet_PersistenceDelegate extends java_util_Collections { 486 protected Expression instantiate(Object oldInstance, Encoder out) { 487 SortedSet set = new TreeSet((SortedSet) oldInstance); 488 return new Expression(oldInstance, Collections.class, "synchronizedSortedSet", new Object[]{set}); 489 } 490 } 491 492 static final class SynchronizedMap_PersistenceDelegate extends java_util_Collections { 493 protected Expression instantiate(Object oldInstance, Encoder out) { 494 Map map = new HashMap((Map) oldInstance); 495 return new Expression(oldInstance, Collections.class, "synchronizedMap", new Object[]{map}); 496 } 497 } 498 499 static final class SynchronizedSortedMap_PersistenceDelegate extends java_util_Collections { 500 protected Expression instantiate(Object oldInstance, Encoder out) { 501 SortedMap map = new TreeMap((SortedMap) oldInstance); 502 return new Expression(oldInstance, Collections.class, "synchronizedSortedMap", new Object[]{map}); 503 } 504 } 505 506 static final class CheckedCollection_PersistenceDelegate extends java_util_Collections { 507 protected Expression instantiate(Object oldInstance, Encoder out) { 508 Object type = MetaData.getPrivateFieldValue(oldInstance, "java.util.Collections$CheckedCollection.type"); 509 List list = new ArrayList((Collection) oldInstance); 510 return new Expression(oldInstance, Collections.class, "checkedCollection", new Object[]{list, type}); 511 } 512 } 513 514 static final class CheckedList_PersistenceDelegate extends java_util_Collections { 515 protected Expression instantiate(Object oldInstance, Encoder out) { 516 Object type = MetaData.getPrivateFieldValue(oldInstance, "java.util.Collections$CheckedCollection.type"); 517 List list = new LinkedList((Collection) oldInstance); 518 return new Expression(oldInstance, Collections.class, "checkedList", new Object[]{list, type}); 519 } 520 } 521 522 static final class CheckedRandomAccessList_PersistenceDelegate extends java_util_Collections { 523 protected Expression instantiate(Object oldInstance, Encoder out) { 524 Object type = MetaData.getPrivateFieldValue(oldInstance, "java.util.Collections$CheckedCollection.type"); 525 List list = new ArrayList((Collection) oldInstance); 526 return new Expression(oldInstance, Collections.class, "checkedList", new Object[]{list, type}); 527 } 528 } 529 530 static final class CheckedSet_PersistenceDelegate extends java_util_Collections { 531 protected Expression instantiate(Object oldInstance, Encoder out) { 532 Object type = MetaData.getPrivateFieldValue(oldInstance, "java.util.Collections$CheckedCollection.type"); 533 Set set = new HashSet((Set) oldInstance); 534 return new Expression(oldInstance, Collections.class, "checkedSet", new Object[]{set, type}); 535 } 536 } 537 538 static final class CheckedSortedSet_PersistenceDelegate extends java_util_Collections { 539 protected Expression instantiate(Object oldInstance, Encoder out) { 540 Object type = MetaData.getPrivateFieldValue(oldInstance, "java.util.Collections$CheckedCollection.type"); 541 SortedSet set = new TreeSet((SortedSet) oldInstance); 542 return new Expression(oldInstance, Collections.class, "checkedSortedSet", new Object[]{set, type}); 543 } 544 } 545 546 static final class CheckedMap_PersistenceDelegate extends java_util_Collections { 547 protected Expression instantiate(Object oldInstance, Encoder out) { 548 Object keyType = MetaData.getPrivateFieldValue(oldInstance, "java.util.Collections$CheckedMap.keyType"); 549 Object valueType = MetaData.getPrivateFieldValue(oldInstance, "java.util.Collections$CheckedMap.valueType"); 550 Map map = new HashMap((Map) oldInstance); 551 return new Expression(oldInstance, Collections.class, "checkedMap", new Object[]{map, keyType, valueType}); 552 } 553 } 554 555 static final class CheckedSortedMap_PersistenceDelegate extends java_util_Collections { 556 protected Expression instantiate(Object oldInstance, Encoder out) { 557 Object keyType = MetaData.getPrivateFieldValue(oldInstance, "java.util.Collections$CheckedMap.keyType"); 558 Object valueType = MetaData.getPrivateFieldValue(oldInstance, "java.util.Collections$CheckedMap.valueType"); 559 SortedMap map = new TreeMap((SortedMap) oldInstance); 560 return new Expression(oldInstance, Collections.class, "checkedSortedMap", new Object[]{map, keyType, valueType}); 561 } 562 } 563 } 564 565 /** 566 * The persistence delegate for <CODE>java.util.EnumMap</CODE> classes. 567 * 568 * @author Sergey A. Malenkov 569 */ 570 class java_util_EnumMap_PersistenceDelegate extends PersistenceDelegate { 571 protected boolean mutatesTo(Object oldInstance, Object newInstance) { 572 return super.mutatesTo(oldInstance, newInstance) && (getType(oldInstance) == getType(newInstance)); 573 } 574 575 protected Expression instantiate(Object oldInstance, Encoder out) { 576 return new Expression(oldInstance, EnumMap.class, "new", new Object[] {getType(oldInstance)}); 577 } 578 579 private static Object getType(Object instance) { 580 return MetaData.getPrivateFieldValue(instance, "java.util.EnumMap.keyType"); 581 } 582 } 583 584 /** 585 * The persistence delegate for <CODE>java.util.EnumSet</CODE> classes. 586 * 587 * @author Sergey A. Malenkov 588 */ 589 class java_util_EnumSet_PersistenceDelegate extends PersistenceDelegate { 590 protected boolean mutatesTo(Object oldInstance, Object newInstance) { 591 return super.mutatesTo(oldInstance, newInstance) && (getType(oldInstance) == getType(newInstance)); 592 } 593 594 protected Expression instantiate(Object oldInstance, Encoder out) { 595 return new Expression(oldInstance, EnumSet.class, "noneOf", new Object[] {getType(oldInstance)}); 596 } 597 598 private static Object getType(Object instance) { 599 return MetaData.getPrivateFieldValue(instance, "java.util.EnumSet.elementType"); 600 } 601 } 602 603 // Collection 604 class java_util_Collection_PersistenceDelegate extends DefaultPersistenceDelegate { 605 protected void initialize(Class<?> type, Object oldInstance, Object newInstance, Encoder out) { 606 java.util.Collection oldO = (java.util.Collection)oldInstance; 607 java.util.Collection newO = (java.util.Collection)newInstance; 608 609 if (newO.size() != 0) { 610 invokeStatement(oldInstance, "clear", new Object[]{}, out); 611 } 612 for (Iterator i = oldO.iterator(); i.hasNext();) { 613 invokeStatement(oldInstance, "add", new Object[]{i.next()}, out); 614 } 615 } 616 } 617 618 // List 619 class java_util_List_PersistenceDelegate extends DefaultPersistenceDelegate { 620 protected void initialize(Class<?> type, Object oldInstance, Object newInstance, Encoder out) { 621 java.util.List oldO = (java.util.List)oldInstance; 622 java.util.List newO = (java.util.List)newInstance; 623 int oldSize = oldO.size(); 624 int newSize = (newO == null) ? 0 : newO.size(); 625 if (oldSize < newSize) { 626 invokeStatement(oldInstance, "clear", new Object[]{}, out); 627 newSize = 0; 628 } 629 for (int i = 0; i < newSize; i++) { 630 Object index = new Integer(i); 631 632 Expression oldGetExp = new Expression(oldInstance, "get", new Object[]{index}); 633 Expression newGetExp = new Expression(newInstance, "get", new Object[]{index}); 634 try { 635 Object oldValue = oldGetExp.getValue(); 636 Object newValue = newGetExp.getValue(); 637 out.writeExpression(oldGetExp); 638 if (!MetaData.equals(newValue, out.get(oldValue))) { 639 invokeStatement(oldInstance, "set", new Object[]{index, oldValue}, out); 640 } 641 } 642 catch (Exception e) { 643 out.getExceptionListener().exceptionThrown(e); 644 } 645 } 646 for (int i = newSize; i < oldSize; i++) { 647 invokeStatement(oldInstance, "add", new Object[]{oldO.get(i)}, out); 648 } 649 } 650 } 651 652 653 // Map 654 class java_util_Map_PersistenceDelegate extends DefaultPersistenceDelegate { 655 protected void initialize(Class<?> type, Object oldInstance, Object newInstance, Encoder out) { 656 // System.out.println("Initializing: " + newInstance); 657 java.util.Map oldMap = (java.util.Map)oldInstance; 658 java.util.Map newMap = (java.util.Map)newInstance; 659 // Remove the new elements. 660 // Do this first otherwise we undo the adding work. 661 if (newMap != null) { 662 for (Object newKey : newMap.keySet().toArray()) { 663 // PENDING: This "key" is not in the right environment. 664 if (!oldMap.containsKey(newKey)) { 665 invokeStatement(oldInstance, "remove", new Object[]{newKey}, out); 666 } 667 } 668 } 669 // Add the new elements. 670 for ( Object oldKey : oldMap.keySet() ) { 671 Expression oldGetExp = new Expression(oldInstance, "get", new Object[]{oldKey}); 672 // Pending: should use newKey. 673 Expression newGetExp = new Expression(newInstance, "get", new Object[]{oldKey}); 674 try { 675 Object oldValue = oldGetExp.getValue(); 676 Object newValue = newGetExp.getValue(); 677 out.writeExpression(oldGetExp); 678 if (!MetaData.equals(newValue, out.get(oldValue))) { 679 invokeStatement(oldInstance, "put", new Object[]{oldKey, oldValue}, out); 680 } else if ((newValue == null) && !newMap.containsKey(oldKey)) { 681 // put oldValue(=null?) if oldKey is absent in newMap 682 invokeStatement(oldInstance, "put", new Object[]{oldKey, oldValue}, out); 683 } 684 } 685 catch (Exception e) { 686 out.getExceptionListener().exceptionThrown(e); 687 } 688 } 689 } 690 } 691 692 class java_util_AbstractCollection_PersistenceDelegate extends java_util_Collection_PersistenceDelegate {} 693 class java_util_AbstractList_PersistenceDelegate extends java_util_List_PersistenceDelegate {} 694 class java_util_AbstractMap_PersistenceDelegate extends java_util_Map_PersistenceDelegate {} 695 class java_util_Hashtable_PersistenceDelegate extends java_util_Map_PersistenceDelegate {} 696 697 698 // Beans 699 class java_beans_beancontext_BeanContextSupport_PersistenceDelegate extends java_util_Collection_PersistenceDelegate {} 700 701 // AWT 702 703 /** 704 * The persistence delegate for {@link Insets}. 705 * It is impossible to use {@link DefaultPersistenceDelegate} 706 * because this class does not have any properties. 707 * 708 * @author Sergey A. Malenkov 709 */ 710 final class java_awt_Insets_PersistenceDelegate extends PersistenceDelegate { 711 protected boolean mutatesTo(Object oldInstance, Object newInstance) { 712 return oldInstance.equals(newInstance); 713 } 714 715 protected Expression instantiate(Object oldInstance, Encoder out) { 716 Insets insets = (Insets) oldInstance; 717 Object[] args = new Object[] { 718 insets.top, 719 insets.left, 720 insets.bottom, 721 insets.right, 722 }; 723 return new Expression(insets, insets.getClass(), "new", args); 724 } 725 } 726 727 /** 728 * The persistence delegate for {@link Font}. 729 * It is impossible to use {@link DefaultPersistenceDelegate} 730 * because size of the font can be float value. 731 * 732 * @author Sergey A. Malenkov 733 */ 734 final class java_awt_Font_PersistenceDelegate extends PersistenceDelegate { 735 protected boolean mutatesTo(Object oldInstance, Object newInstance) { 736 return oldInstance.equals(newInstance); 737 } 738 739 protected Expression instantiate(Object oldInstance, Encoder out) { 740 Font font = (Font) oldInstance; 741 742 int count = 0; 743 String family = null; 744 int style = Font.PLAIN; 745 int size = 12; 746 747 Map basic = font.getAttributes(); 748 Map clone = new HashMap(basic.size()); 749 for (Object key : basic.keySet()) { 750 Object value = basic.get(key); 751 if (value != null) { 752 clone.put(key, value); 753 } 754 if (key == TextAttribute.FAMILY) { 755 if (value instanceof String) { 756 count++; 757 family = (String) value; 758 } 759 } 760 else if (key == TextAttribute.WEIGHT) { 761 if (TextAttribute.WEIGHT_REGULAR.equals(value)) { 762 count++; 763 } else if (TextAttribute.WEIGHT_BOLD.equals(value)) { 764 count++; 765 style |= Font.BOLD; 766 } 767 } 768 else if (key == TextAttribute.POSTURE) { 769 if (TextAttribute.POSTURE_REGULAR.equals(value)) { 770 count++; 771 } else if (TextAttribute.POSTURE_OBLIQUE.equals(value)) { 772 count++; 773 style |= Font.ITALIC; 774 } 775 } else if (key == TextAttribute.SIZE) { 776 if (value instanceof Number) { 777 Number number = (Number) value; 778 size = number.intValue(); 779 if (size == number.floatValue()) { 780 count++; 781 } 782 } 783 } 784 } 785 Class type = font.getClass(); 786 if (count == clone.size()) { 787 return new Expression(font, type, "new", new Object[]{family, style, size}); 788 } 789 if (type == Font.class) { 790 return new Expression(font, type, "getFont", new Object[]{clone}); 791 } 792 return new Expression(font, type, "new", new Object[]{Font.getFont(clone)}); 793 } 794 } 795 796 /** 797 * The persistence delegate for {@link AWTKeyStroke}. 798 * It is impossible to use {@link DefaultPersistenceDelegate} 799 * because this class have no public constructor. 800 * 801 * @author Sergey A. Malenkov 802 */ 803 final class java_awt_AWTKeyStroke_PersistenceDelegate extends PersistenceDelegate { 804 protected boolean mutatesTo(Object oldInstance, Object newInstance) { 805 return oldInstance.equals(newInstance); 806 } 807 808 protected Expression instantiate(Object oldInstance, Encoder out) { 809 AWTKeyStroke key = (AWTKeyStroke) oldInstance; 810 811 char ch = key.getKeyChar(); 812 int code = key.getKeyCode(); 813 int mask = key.getModifiers(); 814 boolean onKeyRelease = key.isOnKeyRelease(); 815 816 Object[] args = null; 817 if (ch == KeyEvent.CHAR_UNDEFINED) { 818 args = !onKeyRelease 819 ? new Object[]{code, mask} 820 : new Object[]{code, mask, onKeyRelease}; 821 } else if (code == KeyEvent.VK_UNDEFINED) { 822 if (!onKeyRelease) { 823 args = (mask == 0) 824 ? new Object[]{ch} 825 : new Object[]{ch, mask}; 826 } else if (mask == 0) { 827 args = new Object[]{ch, onKeyRelease}; 828 } 829 } 830 if (args == null) { 831 throw new IllegalStateException("Unsupported KeyStroke: " + key); 832 } 833 Class type = key.getClass(); 834 String name = type.getName(); 835 // get short name of the class 836 int index = name.lastIndexOf('.') + 1; 837 if (index > 0) { 838 name = name.substring(index); 839 } 840 return new Expression( key, type, "get" + name, args ); 841 } 842 } 843 844 class StaticFieldsPersistenceDelegate extends PersistenceDelegate { 845 protected void installFields(Encoder out, Class<?> cls) { 846 Field fields[] = cls.getFields(); 847 for(int i = 0; i < fields.length; i++) { 848 Field field = fields[i]; 849 // Don't install primitives, their identity will not be preserved 850 // by wrapping. 851 if (Object.class.isAssignableFrom(field.getType())) { 852 out.writeExpression(new Expression(field, "get", new Object[]{null})); 853 } 854 } 855 } 856 857 protected Expression instantiate(Object oldInstance, Encoder out) { 858 throw new RuntimeException("Unrecognized instance: " + oldInstance); 859 } 860 861 public void writeObject(Object oldInstance, Encoder out) { 862 if (out.getAttribute(this) == null) { 863 out.setAttribute(this, Boolean.TRUE); 864 installFields(out, oldInstance.getClass()); 865 } 866 super.writeObject(oldInstance, out); 867 } 868 } 869 870 // SystemColor 871 class java_awt_SystemColor_PersistenceDelegate extends StaticFieldsPersistenceDelegate {} 872 873 // TextAttribute 874 class java_awt_font_TextAttribute_PersistenceDelegate extends StaticFieldsPersistenceDelegate {} 875 876 // MenuShortcut 877 class java_awt_MenuShortcut_PersistenceDelegate extends PersistenceDelegate { 878 protected boolean mutatesTo(Object oldInstance, Object newInstance) { 879 return oldInstance.equals(newInstance); 880 } 881 882 protected Expression instantiate(Object oldInstance, Encoder out) { 883 java.awt.MenuShortcut m = (java.awt.MenuShortcut)oldInstance; 884 return new Expression(oldInstance, m.getClass(), "new", 885 new Object[]{new Integer(m.getKey()), Boolean.valueOf(m.usesShiftModifier())}); 886 } 887 } 888 889 // Component 890 class java_awt_Component_PersistenceDelegate extends DefaultPersistenceDelegate { 891 protected void initialize(Class<?> type, Object oldInstance, Object newInstance, Encoder out) { 892 super.initialize(type, oldInstance, newInstance, out); 893 java.awt.Component c = (java.awt.Component)oldInstance; 894 java.awt.Component c2 = (java.awt.Component)newInstance; 895 // The "background", "foreground" and "font" properties. 896 // The foreground and font properties of Windows change from 897 // null to defined values after the Windows are made visible - 898 // special case them for now. 899 if (!(oldInstance instanceof java.awt.Window)) { 900 Object oldBackground = c.isBackgroundSet() ? c.getBackground() : null; 901 Object newBackground = c2.isBackgroundSet() ? c2.getBackground() : null; 902 if (!MetaData.equals(oldBackground, newBackground)) { 903 invokeStatement(oldInstance, "setBackground", new Object[] { oldBackground }, out); 904 } 905 Object oldForeground = c.isForegroundSet() ? c.getForeground() : null; 906 Object newForeground = c2.isForegroundSet() ? c2.getForeground() : null; 907 if (!MetaData.equals(oldForeground, newForeground)) { 908 invokeStatement(oldInstance, "setForeground", new Object[] { oldForeground }, out); 909 } 910 Object oldFont = c.isFontSet() ? c.getFont() : null; 911 Object newFont = c2.isFontSet() ? c2.getFont() : null; 912 if (!MetaData.equals(oldFont, newFont)) { 913 invokeStatement(oldInstance, "setFont", new Object[] { oldFont }, out); 914 } 915 } 916 917 // Bounds 918 java.awt.Container p = c.getParent(); 919 if (p == null || p.getLayout() == null) { 920 // Use the most concise construct. 921 boolean locationCorrect = c.getLocation().equals(c2.getLocation()); 922 boolean sizeCorrect = c.getSize().equals(c2.getSize()); 923 if (!locationCorrect && !sizeCorrect) { 924 invokeStatement(oldInstance, "setBounds", new Object[]{c.getBounds()}, out); 925 } 926 else if (!locationCorrect) { 927 invokeStatement(oldInstance, "setLocation", new Object[]{c.getLocation()}, out); 928 } 929 else if (!sizeCorrect) { 930 invokeStatement(oldInstance, "setSize", new Object[]{c.getSize()}, out); 931 } 932 } 933 } 934 } 935 936 // Container 937 class java_awt_Container_PersistenceDelegate extends DefaultPersistenceDelegate { 938 protected void initialize(Class<?> type, Object oldInstance, Object newInstance, Encoder out) { 939 super.initialize(type, oldInstance, newInstance, out); 940 // Ignore the children of a JScrollPane. 941 // Pending(milne) find a better way to do this. 942 if (oldInstance instanceof javax.swing.JScrollPane) { 943 return; 944 } 945 java.awt.Container oldC = (java.awt.Container)oldInstance; 946 java.awt.Component[] oldChildren = oldC.getComponents(); 947 java.awt.Container newC = (java.awt.Container)newInstance; 948 java.awt.Component[] newChildren = (newC == null) ? new java.awt.Component[0] : newC.getComponents(); 949 950 BorderLayout layout = ( oldC.getLayout() instanceof BorderLayout ) 951 ? ( BorderLayout )oldC.getLayout() 952 : null; 953 954 JLayeredPane oldLayeredPane = (oldInstance instanceof JLayeredPane) 955 ? (JLayeredPane) oldInstance 956 : null; 957 958 // Pending. Assume all the new children are unaltered. 959 for(int i = newChildren.length; i < oldChildren.length; i++) { 960 Object[] args = ( layout != null ) 961 ? new Object[] {oldChildren[i], layout.getConstraints( oldChildren[i] )} 962 : (oldLayeredPane != null) 963 ? new Object[] {oldChildren[i], oldLayeredPane.getLayer(oldChildren[i]), Integer.valueOf(-1)} 964 : new Object[] {oldChildren[i]}; 965 966 invokeStatement(oldInstance, "add", args, out); 967 } 968 } 969 } 970 971 // Choice 972 class java_awt_Choice_PersistenceDelegate extends DefaultPersistenceDelegate { 973 protected void initialize(Class<?> type, Object oldInstance, Object newInstance, Encoder out) { 974 super.initialize(type, oldInstance, newInstance, out); 975 java.awt.Choice m = (java.awt.Choice)oldInstance; 976 java.awt.Choice n = (java.awt.Choice)newInstance; 977 for (int i = n.getItemCount(); i < m.getItemCount(); i++) { 978 invokeStatement(oldInstance, "add", new Object[]{m.getItem(i)}, out); 979 } 980 } 981 } 982 983 // Menu 984 class java_awt_Menu_PersistenceDelegate extends DefaultPersistenceDelegate { 985 protected void initialize(Class<?> type, Object oldInstance, Object newInstance, Encoder out) { 986 super.initialize(type, oldInstance, newInstance, out); 987 java.awt.Menu m = (java.awt.Menu)oldInstance; 988 java.awt.Menu n = (java.awt.Menu)newInstance; 989 for (int i = n.getItemCount(); i < m.getItemCount(); i++) { 990 invokeStatement(oldInstance, "add", new Object[]{m.getItem(i)}, out); 991 } 992 } 993 } 994 995 // MenuBar 996 class java_awt_MenuBar_PersistenceDelegate extends DefaultPersistenceDelegate { 997 protected void initialize(Class<?> type, Object oldInstance, Object newInstance, Encoder out) { 998 super.initialize(type, oldInstance, newInstance, out); 999 java.awt.MenuBar m = (java.awt.MenuBar)oldInstance; 1000 java.awt.MenuBar n = (java.awt.MenuBar)newInstance; 1001 for (int i = n.getMenuCount(); i < m.getMenuCount(); i++) { 1002 invokeStatement(oldInstance, "add", new Object[]{m.getMenu(i)}, out); 1003 } 1004 } 1005 } 1006 1007 // List 1008 class java_awt_List_PersistenceDelegate extends DefaultPersistenceDelegate { 1009 protected void initialize(Class<?> type, Object oldInstance, Object newInstance, Encoder out) { 1010 super.initialize(type, oldInstance, newInstance, out); 1011 java.awt.List m = (java.awt.List)oldInstance; 1012 java.awt.List n = (java.awt.List)newInstance; 1013 for (int i = n.getItemCount(); i < m.getItemCount(); i++) { 1014 invokeStatement(oldInstance, "add", new Object[]{m.getItem(i)}, out); 1015 } 1016 } 1017 } 1018 1019 1020 // LayoutManagers 1021 1022 // BorderLayout 1023 class java_awt_BorderLayout_PersistenceDelegate extends DefaultPersistenceDelegate { 1024 private static final String[] CONSTRAINTS = { 1025 BorderLayout.NORTH, 1026 BorderLayout.SOUTH, 1027 BorderLayout.EAST, 1028 BorderLayout.WEST, 1029 BorderLayout.CENTER, 1030 BorderLayout.PAGE_START, 1031 BorderLayout.PAGE_END, 1032 BorderLayout.LINE_START, 1033 BorderLayout.LINE_END, 1034 }; 1035 @Override 1036 protected void initialize(Class<?> type, Object oldInstance, 1037 Object newInstance, Encoder out) { 1038 super.initialize(type, oldInstance, newInstance, out); 1039 BorderLayout oldLayout = (BorderLayout) oldInstance; 1040 BorderLayout newLayout = (BorderLayout) newInstance; 1041 for (String constraints : CONSTRAINTS) { 1042 Object oldC = oldLayout.getLayoutComponent(constraints); 1043 Object newC = newLayout.getLayoutComponent(constraints); 1044 // Pending, assume any existing elements are OK. 1045 if (oldC != null && newC == null) { 1046 invokeStatement(oldInstance, "addLayoutComponent", 1047 new Object[] { oldC, constraints }, out); 1048 } 1049 } 1050 } 1051 } 1052 1053 // CardLayout 1054 class java_awt_CardLayout_PersistenceDelegate extends DefaultPersistenceDelegate { 1055 protected void initialize(Class<?> type, Object oldInstance, 1056 Object newInstance, Encoder out) { 1057 super.initialize(type, oldInstance, newInstance, out); 1058 Hashtable tab = (Hashtable)ReflectionUtils.getPrivateField(oldInstance, 1059 java.awt.CardLayout.class, 1060 "tab", 1061 out.getExceptionListener()); 1062 if (tab != null) { 1063 for(Enumeration e = tab.keys(); e.hasMoreElements();) { 1064 Object child = e.nextElement(); 1065 invokeStatement(oldInstance, "addLayoutComponent", 1066 new Object[]{child, (String)tab.get(child)}, out); 1067 } 1068 } 1069 } 1070 } 1071 1072 // GridBagLayout 1073 class java_awt_GridBagLayout_PersistenceDelegate extends DefaultPersistenceDelegate { 1074 protected void initialize(Class<?> type, Object oldInstance, 1075 Object newInstance, Encoder out) { 1076 super.initialize(type, oldInstance, newInstance, out); 1077 Hashtable comptable = (Hashtable)ReflectionUtils.getPrivateField(oldInstance, 1078 java.awt.GridBagLayout.class, 1079 "comptable", 1080 out.getExceptionListener()); 1081 if (comptable != null) { 1082 for(Enumeration e = comptable.keys(); e.hasMoreElements();) { 1083 Object child = e.nextElement(); 1084 invokeStatement(oldInstance, "addLayoutComponent", 1085 new Object[]{child, comptable.get(child)}, out); 1086 } 1087 } 1088 } 1089 } 1090 1091 // Swing 1092 1093 // JFrame (If we do this for Window instead of JFrame, the setVisible call 1094 // will be issued before we have added all the children to the JFrame and 1095 // will appear blank). 1096 class javax_swing_JFrame_PersistenceDelegate extends DefaultPersistenceDelegate { 1097 protected void initialize(Class<?> type, Object oldInstance, Object newInstance, Encoder out) { 1098 super.initialize(type, oldInstance, newInstance, out); 1099 java.awt.Window oldC = (java.awt.Window)oldInstance; 1100 java.awt.Window newC = (java.awt.Window)newInstance; 1101 boolean oldV = oldC.isVisible(); 1102 boolean newV = newC.isVisible(); 1103 if (newV != oldV) { 1104 // false means: don't execute this statement at write time. 1105 boolean executeStatements = out.executeStatements; 1106 out.executeStatements = false; 1107 invokeStatement(oldInstance, "setVisible", new Object[]{Boolean.valueOf(oldV)}, out); 1108 out.executeStatements = executeStatements; 1109 } 1110 } 1111 } 1112 1113 // Models 1114 1115 // DefaultListModel 1116 class javax_swing_DefaultListModel_PersistenceDelegate extends DefaultPersistenceDelegate { 1117 protected void initialize(Class<?> type, Object oldInstance, Object newInstance, Encoder out) { 1118 // Note, the "size" property will be set here. 1119 super.initialize(type, oldInstance, newInstance, out); 1120 javax.swing.DefaultListModel m = (javax.swing.DefaultListModel)oldInstance; 1121 javax.swing.DefaultListModel n = (javax.swing.DefaultListModel)newInstance; 1122 for (int i = n.getSize(); i < m.getSize(); i++) { 1123 invokeStatement(oldInstance, "add", // Can also use "addElement". 1124 new Object[]{m.getElementAt(i)}, out); 1125 } 1126 } 1127 } 1128 1129 // DefaultComboBoxModel 1130 class javax_swing_DefaultComboBoxModel_PersistenceDelegate extends DefaultPersistenceDelegate { 1131 protected void initialize(Class<?> type, Object oldInstance, Object newInstance, Encoder out) { 1132 super.initialize(type, oldInstance, newInstance, out); 1133 javax.swing.DefaultComboBoxModel m = (javax.swing.DefaultComboBoxModel)oldInstance; 1134 for (int i = 0; i < m.getSize(); i++) { 1135 invokeStatement(oldInstance, "addElement", new Object[]{m.getElementAt(i)}, out); 1136 } 1137 } 1138 } 1139 1140 1141 // DefaultMutableTreeNode 1142 class javax_swing_tree_DefaultMutableTreeNode_PersistenceDelegate extends DefaultPersistenceDelegate { 1143 protected void initialize(Class<?> type, Object oldInstance, Object 1144 newInstance, Encoder out) { 1145 super.initialize(type, oldInstance, newInstance, out); 1146 javax.swing.tree.DefaultMutableTreeNode m = 1147 (javax.swing.tree.DefaultMutableTreeNode)oldInstance; 1148 javax.swing.tree.DefaultMutableTreeNode n = 1149 (javax.swing.tree.DefaultMutableTreeNode)newInstance; 1150 for (int i = n.getChildCount(); i < m.getChildCount(); i++) { 1151 invokeStatement(oldInstance, "add", new 1152 Object[]{m.getChildAt(i)}, out); 1153 } 1154 } 1155 } 1156 1157 // ToolTipManager 1158 class javax_swing_ToolTipManager_PersistenceDelegate extends PersistenceDelegate { 1159 protected Expression instantiate(Object oldInstance, Encoder out) { 1160 return new Expression(oldInstance, javax.swing.ToolTipManager.class, 1161 "sharedInstance", new Object[]{}); 1162 } 1163 } 1164 1165 // JTabbedPane 1166 class javax_swing_JTabbedPane_PersistenceDelegate extends DefaultPersistenceDelegate { 1167 protected void initialize(Class<?> type, Object oldInstance, Object newInstance, Encoder out) { 1168 super.initialize(type, oldInstance, newInstance, out); 1169 javax.swing.JTabbedPane p = (javax.swing.JTabbedPane)oldInstance; 1170 for (int i = 0; i < p.getTabCount(); i++) { 1171 invokeStatement(oldInstance, "addTab", 1172 new Object[]{ 1173 p.getTitleAt(i), 1174 p.getIconAt(i), 1175 p.getComponentAt(i)}, out); 1176 } 1177 } 1178 } 1179 1180 // Box 1181 class javax_swing_Box_PersistenceDelegate extends DefaultPersistenceDelegate { 1182 protected boolean mutatesTo(Object oldInstance, Object newInstance) { 1183 return super.mutatesTo(oldInstance, newInstance) && getAxis(oldInstance).equals(getAxis(newInstance)); 1184 } 1185 1186 protected Expression instantiate(Object oldInstance, Encoder out) { 1187 return new Expression(oldInstance, oldInstance.getClass(), "new", new Object[] {getAxis(oldInstance)}); 1188 } 1189 1190 private Integer getAxis(Object object) { 1191 Box box = (Box) object; 1192 return (Integer) MetaData.getPrivateFieldValue(box.getLayout(), "javax.swing.BoxLayout.axis"); 1193 } 1194 } 1195 1196 // JMenu 1197 // Note that we do not need to state the initialiser for 1198 // JMenuItems since the getComponents() method defined in 1199 // Container will return all of the sub menu items that 1200 // need to be added to the menu item. 1201 // Not so for JMenu apparently. 1202 class javax_swing_JMenu_PersistenceDelegate extends DefaultPersistenceDelegate { 1203 protected void initialize(Class<?> type, Object oldInstance, Object newInstance, Encoder out) { 1204 super.initialize(type, oldInstance, newInstance, out); 1205 javax.swing.JMenu m = (javax.swing.JMenu)oldInstance; 1206 java.awt.Component[] c = m.getMenuComponents(); 1207 for (int i = 0; i < c.length; i++) { 1208 invokeStatement(oldInstance, "add", new Object[]{c[i]}, out); 1209 } 1210 } 1211 } 1212 1213 /** 1214 * The persistence delegate for {@link MatteBorder}. 1215 * It is impossible to use {@link DefaultPersistenceDelegate} 1216 * because this class does not have writable properties. 1217 * 1218 * @author Sergey A. Malenkov 1219 */ 1220 final class javax_swing_border_MatteBorder_PersistenceDelegate extends PersistenceDelegate { 1221 protected Expression instantiate(Object oldInstance, Encoder out) { 1222 MatteBorder border = (MatteBorder) oldInstance; 1223 Insets insets = border.getBorderInsets(); 1224 Object object = border.getTileIcon(); 1225 if (object == null) { 1226 object = border.getMatteColor(); 1227 } 1228 Object[] args = new Object[] { 1229 insets.top, 1230 insets.left, 1231 insets.bottom, 1232 insets.right, 1233 object, 1234 }; 1235 return new Expression(border, border.getClass(), "new", args); 1236 } 1237 } 1238 1239 /* XXX - doens't seem to work. Debug later. 1240 class javax_swing_JMenu_PersistenceDelegate extends DefaultPersistenceDelegate { 1241 protected void initialize(Class<?> type, Object oldInstance, Object newInstance, Encoder out) { 1242 super.initialize(type, oldInstance, newInstance, out); 1243 javax.swing.JMenu m = (javax.swing.JMenu)oldInstance; 1244 javax.swing.JMenu n = (javax.swing.JMenu)newInstance; 1245 for (int i = n.getItemCount(); i < m.getItemCount(); i++) { 1246 invokeStatement(oldInstance, "add", new Object[]{m.getItem(i)}, out); 1247 } 1248 } 1249 } 1250 */ 1251 1252 /** 1253 * The persistence delegate for {@link PrintColorUIResource}. 1254 * It is impossible to use {@link DefaultPersistenceDelegate} 1255 * because this class has special rule for serialization: 1256 * it should be converted to {@link ColorUIResource}. 1257 * 1258 * @see PrintColorUIResource#writeReplace 1259 * 1260 * @author Sergey A. Malenkov 1261 */ 1262 final class sun_swing_PrintColorUIResource_PersistenceDelegate extends PersistenceDelegate { 1263 protected boolean mutatesTo(Object oldInstance, Object newInstance) { 1264 return oldInstance.equals(newInstance); 1265 } 1266 1267 protected Expression instantiate(Object oldInstance, Encoder out) { 1268 Color color = (Color) oldInstance; 1269 Object[] args = new Object[] {color.getRGB()}; 1270 return new Expression(color, ColorUIResource.class, "new", args); 1271 } 1272 } 1273 1274 class MetaData { 1275 private static final Map<String,Field> fields = Collections.synchronizedMap(new WeakHashMap<String, Field>()); 1276 private static Hashtable internalPersistenceDelegates = new Hashtable(); 1277 1278 private static PersistenceDelegate nullPersistenceDelegate = new NullPersistenceDelegate(); 1279 private static PersistenceDelegate enumPersistenceDelegate = new EnumPersistenceDelegate(); 1280 private static PersistenceDelegate primitivePersistenceDelegate = new PrimitivePersistenceDelegate(); 1281 private static PersistenceDelegate defaultPersistenceDelegate = new DefaultPersistenceDelegate(); 1282 private static PersistenceDelegate arrayPersistenceDelegate; 1283 private static PersistenceDelegate proxyPersistenceDelegate; 1284 1285 static { 1286 1287 internalPersistenceDelegates.put("java.net.URI", 1288 new PrimitivePersistenceDelegate()); 1289 1290 // it is possible because MatteBorder is assignable from MatteBorderUIResource 1291 internalPersistenceDelegates.put("javax.swing.plaf.BorderUIResource$MatteBorderUIResource", 1292 new javax_swing_border_MatteBorder_PersistenceDelegate()); 1293 1294 // it is possible because FontUIResource is supported by java_awt_Font_PersistenceDelegate 1295 internalPersistenceDelegates.put("javax.swing.plaf.FontUIResource", 1296 new java_awt_Font_PersistenceDelegate()); 1297 1298 // it is possible because KeyStroke is supported by java_awt_AWTKeyStroke_PersistenceDelegate 1299 internalPersistenceDelegates.put("javax.swing.KeyStroke", 1300 new java_awt_AWTKeyStroke_PersistenceDelegate()); 1301 1302 internalPersistenceDelegates.put("java.sql.Date", new java_util_Date_PersistenceDelegate()); 1303 internalPersistenceDelegates.put("java.sql.Time", new java_util_Date_PersistenceDelegate()); 1304 1305 internalPersistenceDelegates.put("java.util.JumboEnumSet", new java_util_EnumSet_PersistenceDelegate()); 1306 internalPersistenceDelegates.put("java.util.RegularEnumSet", new java_util_EnumSet_PersistenceDelegate()); 1307 } 1308 1309 /*pp*/ static boolean equals(Object o1, Object o2) { 1310 return (o1 == null) ? (o2 == null) : o1.equals(o2); 1311 } 1312 1313 public synchronized static PersistenceDelegate getPersistenceDelegate(Class type) { 1314 if (type == null) { 1315 return nullPersistenceDelegate; 1316 } 1317 if (Enum.class.isAssignableFrom(type)) { 1318 return enumPersistenceDelegate; 1319 } 1320 if (ReflectionUtils.isPrimitive(type)) { 1321 return primitivePersistenceDelegate; 1322 } 1323 // The persistence delegate for arrays is non-trivial; instantiate it lazily. 1324 if (type.isArray()) { 1325 if (arrayPersistenceDelegate == null) { 1326 arrayPersistenceDelegate = new ArrayPersistenceDelegate(); 1327 } 1328 return arrayPersistenceDelegate; 1329 } 1330 // Handle proxies lazily for backward compatibility with 1.2. 1331 try { 1332 if (java.lang.reflect.Proxy.isProxyClass(type)) { 1333 if (proxyPersistenceDelegate == null) { 1334 proxyPersistenceDelegate = new ProxyPersistenceDelegate(); 1335 } 1336 return proxyPersistenceDelegate; 1337 } 1338 } 1339 catch(Exception e) {} 1340 // else if (type.getDeclaringClass() != null) { 1341 // return new DefaultPersistenceDelegate(new String[]{"this$0"}); 1342 // } 1343 1344 String typeName = type.getName(); 1345 PersistenceDelegate pd = (PersistenceDelegate)getBeanAttribute(type, "persistenceDelegate"); 1346 if (pd == null) { 1347 pd = (PersistenceDelegate)internalPersistenceDelegates.get(typeName); 1348 if (pd != null) { 1349 return pd; 1350 } 1351 internalPersistenceDelegates.put(typeName, defaultPersistenceDelegate); 1352 try { 1353 String name = type.getName(); 1354 Class c = Class.forName("java.beans." + name.replace('.', '_') 1355 + "_PersistenceDelegate"); 1356 pd = (PersistenceDelegate)c.newInstance(); 1357 internalPersistenceDelegates.put(typeName, pd); 1358 } 1359 catch (ClassNotFoundException e) { 1360 String[] properties = getConstructorProperties(type); 1361 if (properties != null) { 1362 pd = new DefaultPersistenceDelegate(properties); 1363 internalPersistenceDelegates.put(typeName, pd); 1364 } 1365 } 1366 catch (Exception e) { 1367 System.err.println("Internal error: " + e); 1368 } 1369 } 1370 1371 return (pd != null) ? pd : defaultPersistenceDelegate; 1372 } 1373 1374 private static String[] getConstructorProperties(Class type) { 1375 String[] names = null; 1376 int length = 0; 1377 for (Constructor<?> constructor : type.getConstructors()) { 1378 String[] value = getAnnotationValue(constructor); 1379 if ((value != null) && (length < value.length) && isValid(constructor, value)) { 1380 names = value; 1381 length = value.length; 1382 } 1383 } 1384 return names; 1385 } 1386 1387 private static String[] getAnnotationValue(Constructor<?> constructor) { 1388 ConstructorProperties annotation = constructor.getAnnotation(ConstructorProperties.class); 1389 return (annotation != null) 1390 ? annotation.value() 1391 : null; 1392 } 1393 1394 private static boolean isValid(Constructor<?> constructor, String[] names) { 1395 Class[] parameters = constructor.getParameterTypes(); 1396 if (names.length != parameters.length) { 1397 return false; 1398 } 1399 for (String name : names) { 1400 if (name == null) { 1401 return false; 1402 } 1403 } 1404 return true; 1405 } 1406 1407 private static Object getBeanAttribute(Class type, String attribute) { 1408 try { 1409 return Introspector.getBeanInfo(type).getBeanDescriptor().getValue(attribute); 1410 } catch (IntrospectionException exception) { 1411 return null; 1412 } 1413 } 1414 1415 static Object getPrivateFieldValue(Object instance, String name) { 1416 Field field = fields.get(name); 1417 if (field == null) { 1418 int index = name.lastIndexOf('.'); 1419 final String className = name.substring(0, index); 1420 final String fieldName = name.substring(1 + index); 1421 field = AccessController.doPrivileged(new PrivilegedAction<Field>() { 1422 public Field run() { 1423 try { 1424 Field field = Class.forName(className).getDeclaredField(fieldName); 1425 field.setAccessible(true); 1426 return field; 1427 } 1428 catch (ClassNotFoundException exception) { 1429 throw new IllegalStateException("Could not find class", exception); 1430 } 1431 catch (NoSuchFieldException exception) { 1432 throw new IllegalStateException("Could not find field", exception); 1433 } 1434 } 1435 }); 1436 fields.put(name, field); 1437 } 1438 try { 1439 return field.get(instance); 1440 } 1441 catch (IllegalAccessException exception) { 1442 throw new IllegalStateException("Could not get value of the field", exception); 1443 } 1444 } 1445 }