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