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