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, ClassLoader.getPlatformClassLoader()); 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 515 // Collection 516 static class java_util_Collection_PersistenceDelegate extends DefaultPersistenceDelegate { 517 protected void initialize(Class<?> type, Object oldInstance, Object newInstance, Encoder out) { 518 java.util.Collection<?> oldO = (java.util.Collection)oldInstance; 519 java.util.Collection<?> newO = (java.util.Collection)newInstance; 520 521 if (newO.size() != 0) { 522 invokeStatement(oldInstance, "clear", new Object[]{}, out); 523 } 524 for (Iterator<?> i = oldO.iterator(); i.hasNext();) { 525 invokeStatement(oldInstance, "add", new Object[]{i.next()}, out); 526 } 527 } 528 } 529 530 // List 531 static class java_util_List_PersistenceDelegate extends DefaultPersistenceDelegate { 532 protected void initialize(Class<?> type, Object oldInstance, Object newInstance, Encoder out) { 533 java.util.List<?> oldO = (java.util.List<?>)oldInstance; 534 java.util.List<?> newO = (java.util.List<?>)newInstance; 535 int oldSize = oldO.size(); 536 int newSize = (newO == null) ? 0 : newO.size(); 537 if (oldSize < newSize) { 538 invokeStatement(oldInstance, "clear", new Object[]{}, out); 539 newSize = 0; 540 } 541 for (int i = 0; i < newSize; i++) { 542 Object index = i; 543 544 Expression oldGetExp = new Expression(oldInstance, "get", new Object[]{index}); 545 Expression newGetExp = new Expression(newInstance, "get", new Object[]{index}); 546 try { 547 Object oldValue = oldGetExp.getValue(); 548 Object newValue = newGetExp.getValue(); 549 out.writeExpression(oldGetExp); 550 if (!Objects.equals(newValue, out.get(oldValue))) { 551 invokeStatement(oldInstance, "set", new Object[]{index, oldValue}, out); 552 } 553 } 554 catch (Exception e) { 555 out.getExceptionListener().exceptionThrown(e); 556 } 557 } 558 for (int i = newSize; i < oldSize; i++) { 559 invokeStatement(oldInstance, "add", new Object[]{oldO.get(i)}, out); 560 } 561 } 562 } 563 564 565 // Map 566 static class java_util_Map_PersistenceDelegate extends DefaultPersistenceDelegate { 567 protected void initialize(Class<?> type, Object oldInstance, Object newInstance, Encoder out) { 568 // System.out.println("Initializing: " + newInstance); 569 java.util.Map<?,?> oldMap = (java.util.Map)oldInstance; 570 java.util.Map<?,?> newMap = (java.util.Map)newInstance; 571 // Remove the new elements. 572 // Do this first otherwise we undo the adding work. 573 if (newMap != null) { 574 for (Object newKey : newMap.keySet().toArray()) { 575 // PENDING: This "key" is not in the right environment. 576 if (!oldMap.containsKey(newKey)) { 577 invokeStatement(oldInstance, "remove", new Object[]{newKey}, out); 578 } 579 } 580 } 581 // Add the new elements. 582 for ( Object oldKey : oldMap.keySet() ) { 583 Expression oldGetExp = new Expression(oldInstance, "get", new Object[]{oldKey}); 584 // Pending: should use newKey. 585 Expression newGetExp = new Expression(newInstance, "get", new Object[]{oldKey}); 586 try { 587 Object oldValue = oldGetExp.getValue(); 588 Object newValue = newGetExp.getValue(); 589 out.writeExpression(oldGetExp); 590 if (!Objects.equals(newValue, out.get(oldValue))) { 591 invokeStatement(oldInstance, "put", new Object[]{oldKey, oldValue}, out); 592 } else if ((newValue == null) && !newMap.containsKey(oldKey)) { 593 // put oldValue(=null?) if oldKey is absent in newMap 594 invokeStatement(oldInstance, "put", new Object[]{oldKey, oldValue}, out); 595 } 596 } 597 catch (Exception e) { 598 out.getExceptionListener().exceptionThrown(e); 599 } 600 } 601 } 602 } 603 604 static final class java_util_AbstractCollection_PersistenceDelegate extends java_util_Collection_PersistenceDelegate {} 605 static final class java_util_AbstractList_PersistenceDelegate extends java_util_List_PersistenceDelegate {} 606 static final class java_util_AbstractMap_PersistenceDelegate extends java_util_Map_PersistenceDelegate {} 607 static final class java_util_Hashtable_PersistenceDelegate extends java_util_Map_PersistenceDelegate {} 608 609 610 // Beans 611 static final class java_beans_beancontext_BeanContextSupport_PersistenceDelegate extends java_util_Collection_PersistenceDelegate {} 612 613 // AWT 614 615 /** 616 * The persistence delegate for {@link Insets}. 617 * It is impossible to use {@link DefaultPersistenceDelegate} 618 * because this class does not have any properties. 619 * 620 * @author Sergey A. Malenkov 621 */ 622 static final class java_awt_Insets_PersistenceDelegate extends PersistenceDelegate { 623 protected boolean mutatesTo(Object oldInstance, Object newInstance) { 624 return oldInstance.equals(newInstance); 625 } 626 627 protected Expression instantiate(Object oldInstance, Encoder out) { 628 Insets insets = (Insets) oldInstance; 629 Object[] args = new Object[] { 630 insets.top, 631 insets.left, 632 insets.bottom, 633 insets.right, 634 }; 635 return new Expression(insets, insets.getClass(), "new", args); 636 } 637 } 638 639 /** 640 * The persistence delegate for {@link Font}. 641 * It is impossible to use {@link DefaultPersistenceDelegate} 642 * because size of the font can be float value. 643 * 644 * @author Sergey A. Malenkov 645 */ 646 static final class java_awt_Font_PersistenceDelegate extends PersistenceDelegate { 647 protected boolean mutatesTo(Object oldInstance, Object newInstance) { 648 return oldInstance.equals(newInstance); 649 } 650 651 protected Expression instantiate(Object oldInstance, Encoder out) { 652 Font font = (Font) oldInstance; 653 654 int count = 0; 655 String family = null; 656 int style = Font.PLAIN; 657 int size = 12; 658 659 Map<TextAttribute, ?> basic = font.getAttributes(); 660 Map<TextAttribute, Object> clone = new HashMap<>(basic.size()); 661 for (TextAttribute key : basic.keySet()) { 662 Object value = basic.get(key); 663 if (value != null) { 664 clone.put(key, value); 665 } 666 if (key == TextAttribute.FAMILY) { 667 if (value instanceof String) { 668 count++; 669 family = (String) value; 670 } 671 } 672 else if (key == TextAttribute.WEIGHT) { 673 if (TextAttribute.WEIGHT_REGULAR.equals(value)) { 674 count++; 675 } else if (TextAttribute.WEIGHT_BOLD.equals(value)) { 676 count++; 677 style |= Font.BOLD; 678 } 679 } 680 else if (key == TextAttribute.POSTURE) { 681 if (TextAttribute.POSTURE_REGULAR.equals(value)) { 682 count++; 683 } else if (TextAttribute.POSTURE_OBLIQUE.equals(value)) { 684 count++; 685 style |= Font.ITALIC; 686 } 687 } else if (key == TextAttribute.SIZE) { 688 if (value instanceof Number) { 689 Number number = (Number) value; 690 size = number.intValue(); 691 if (size == number.floatValue()) { 692 count++; 693 } 694 } 695 } 696 } 697 Class<?> type = font.getClass(); 698 if (count == clone.size()) { 699 return new Expression(font, type, "new", new Object[]{family, style, size}); 700 } 701 if (type == Font.class) { 702 return new Expression(font, type, "getFont", new Object[]{clone}); 703 } 704 return new Expression(font, type, "new", new Object[]{Font.getFont(clone)}); 705 } 706 } 707 708 /** 709 * The persistence delegate for {@link AWTKeyStroke}. 710 * It is impossible to use {@link DefaultPersistenceDelegate} 711 * because this class have no public constructor. 712 * 713 * @author Sergey A. Malenkov 714 */ 715 static final class java_awt_AWTKeyStroke_PersistenceDelegate extends PersistenceDelegate { 716 protected boolean mutatesTo(Object oldInstance, Object newInstance) { 717 return oldInstance.equals(newInstance); 718 } 719 720 protected Expression instantiate(Object oldInstance, Encoder out) { 721 AWTKeyStroke key = (AWTKeyStroke) oldInstance; 722 723 char ch = key.getKeyChar(); 724 int code = key.getKeyCode(); 725 int mask = key.getModifiers(); 726 boolean onKeyRelease = key.isOnKeyRelease(); 727 728 Object[] args = null; 729 if (ch == KeyEvent.CHAR_UNDEFINED) { 730 args = !onKeyRelease 731 ? new Object[]{code, mask} 732 : new Object[]{code, mask, onKeyRelease}; 733 } else if (code == KeyEvent.VK_UNDEFINED) { 734 if (!onKeyRelease) { 735 args = (mask == 0) 736 ? new Object[]{ch} 737 : new Object[]{ch, mask}; 738 } else if (mask == 0) { 739 args = new Object[]{ch, onKeyRelease}; 740 } 741 } 742 if (args == null) { 743 throw new IllegalStateException("Unsupported KeyStroke: " + key); 744 } 745 Class<?> type = key.getClass(); 746 String name = type.getName(); 747 // get short name of the class 748 int index = name.lastIndexOf('.') + 1; 749 if (index > 0) { 750 name = name.substring(index); 751 } 752 return new Expression( key, type, "get" + name, args ); 753 } 754 } 755 756 static class StaticFieldsPersistenceDelegate extends PersistenceDelegate { 757 protected void installFields(Encoder out, Class<?> cls) { 758 if (Modifier.isPublic(cls.getModifiers()) && isPackageAccessible(cls)) { 759 Field fields[] = cls.getFields(); 760 for(int i = 0; i < fields.length; i++) { 761 Field field = fields[i]; 762 // Don't install primitives, their identity will not be preserved 763 // by wrapping. 764 if (Object.class.isAssignableFrom(field.getType())) { 765 out.writeExpression(new Expression(field, "get", new Object[]{null})); 766 } 767 } 768 } 769 } 770 771 protected Expression instantiate(Object oldInstance, Encoder out) { 772 throw new RuntimeException("Unrecognized instance: " + oldInstance); 773 } 774 775 public void writeObject(Object oldInstance, Encoder out) { 776 if (out.getAttribute(this) == null) { 777 out.setAttribute(this, Boolean.TRUE); 778 installFields(out, oldInstance.getClass()); 779 } 780 super.writeObject(oldInstance, out); 781 } 782 } 783 784 // SystemColor 785 static final class java_awt_SystemColor_PersistenceDelegate extends StaticFieldsPersistenceDelegate {} 786 787 // TextAttribute 788 static final class java_awt_font_TextAttribute_PersistenceDelegate extends StaticFieldsPersistenceDelegate {} 789 790 // MenuShortcut 791 static final class java_awt_MenuShortcut_PersistenceDelegate extends PersistenceDelegate { 792 protected boolean mutatesTo(Object oldInstance, Object newInstance) { 793 return oldInstance.equals(newInstance); 794 } 795 796 protected Expression instantiate(Object oldInstance, Encoder out) { 797 java.awt.MenuShortcut m = (java.awt.MenuShortcut)oldInstance; 798 return new Expression(oldInstance, m.getClass(), "new", 799 new Object[]{m.getKey(), Boolean.valueOf(m.usesShiftModifier())}); 800 } 801 } 802 803 // Component 804 static final class java_awt_Component_PersistenceDelegate extends DefaultPersistenceDelegate { 805 protected void initialize(Class<?> type, Object oldInstance, Object newInstance, Encoder out) { 806 super.initialize(type, oldInstance, newInstance, out); 807 java.awt.Component c = (java.awt.Component)oldInstance; 808 java.awt.Component c2 = (java.awt.Component)newInstance; 809 // The "background", "foreground" and "font" properties. 810 // The foreground and font properties of Windows change from 811 // null to defined values after the Windows are made visible - 812 // special case them for now. 813 if (!(oldInstance instanceof java.awt.Window)) { 814 Object oldBackground = c.isBackgroundSet() ? c.getBackground() : null; 815 Object newBackground = c2.isBackgroundSet() ? c2.getBackground() : null; 816 if (!Objects.equals(oldBackground, newBackground)) { 817 invokeStatement(oldInstance, "setBackground", new Object[] { oldBackground }, out); 818 } 819 Object oldForeground = c.isForegroundSet() ? c.getForeground() : null; 820 Object newForeground = c2.isForegroundSet() ? c2.getForeground() : null; 821 if (!Objects.equals(oldForeground, newForeground)) { 822 invokeStatement(oldInstance, "setForeground", new Object[] { oldForeground }, out); 823 } 824 Object oldFont = c.isFontSet() ? c.getFont() : null; 825 Object newFont = c2.isFontSet() ? c2.getFont() : null; 826 if (!Objects.equals(oldFont, newFont)) { 827 invokeStatement(oldInstance, "setFont", new Object[] { oldFont }, out); 828 } 829 } 830 831 // Bounds 832 java.awt.Container p = c.getParent(); 833 if (p == null || p.getLayout() == null) { 834 // Use the most concise construct. 835 boolean locationCorrect = c.getLocation().equals(c2.getLocation()); 836 boolean sizeCorrect = c.getSize().equals(c2.getSize()); 837 if (!locationCorrect && !sizeCorrect) { 838 invokeStatement(oldInstance, "setBounds", new Object[]{c.getBounds()}, out); 839 } 840 else if (!locationCorrect) { 841 invokeStatement(oldInstance, "setLocation", new Object[]{c.getLocation()}, out); 842 } 843 else if (!sizeCorrect) { 844 invokeStatement(oldInstance, "setSize", new Object[]{c.getSize()}, out); 845 } 846 } 847 } 848 } 849 850 // Container 851 static final class java_awt_Container_PersistenceDelegate extends DefaultPersistenceDelegate { 852 protected void initialize(Class<?> type, Object oldInstance, Object newInstance, Encoder out) { 853 super.initialize(type, oldInstance, newInstance, out); 854 // Ignore the children of a JScrollPane. 855 // Pending(milne) find a better way to do this. 856 if (oldInstance instanceof javax.swing.JScrollPane) { 857 return; 858 } 859 java.awt.Container oldC = (java.awt.Container)oldInstance; 860 java.awt.Component[] oldChildren = oldC.getComponents(); 861 java.awt.Container newC = (java.awt.Container)newInstance; 862 java.awt.Component[] newChildren = (newC == null) ? new java.awt.Component[0] : newC.getComponents(); 863 864 BorderLayout layout = ( oldC.getLayout() instanceof BorderLayout ) 865 ? ( BorderLayout )oldC.getLayout() 866 : null; 867 868 JLayeredPane oldLayeredPane = (oldInstance instanceof JLayeredPane) 869 ? (JLayeredPane) oldInstance 870 : null; 871 872 // Pending. Assume all the new children are unaltered. 873 for(int i = newChildren.length; i < oldChildren.length; i++) { 874 Object[] args = ( layout != null ) 875 ? new Object[] {oldChildren[i], layout.getConstraints( oldChildren[i] )} 876 : (oldLayeredPane != null) 877 ? new Object[] {oldChildren[i], oldLayeredPane.getLayer(oldChildren[i]), Integer.valueOf(-1)} 878 : new Object[] {oldChildren[i]}; 879 880 invokeStatement(oldInstance, "add", args, out); 881 } 882 } 883 } 884 885 // Choice 886 static final class java_awt_Choice_PersistenceDelegate extends DefaultPersistenceDelegate { 887 protected void initialize(Class<?> type, Object oldInstance, Object newInstance, Encoder out) { 888 super.initialize(type, oldInstance, newInstance, out); 889 java.awt.Choice m = (java.awt.Choice)oldInstance; 890 java.awt.Choice n = (java.awt.Choice)newInstance; 891 for (int i = n.getItemCount(); i < m.getItemCount(); i++) { 892 invokeStatement(oldInstance, "add", new Object[]{m.getItem(i)}, out); 893 } 894 } 895 } 896 897 // Menu 898 static final class java_awt_Menu_PersistenceDelegate extends DefaultPersistenceDelegate { 899 protected void initialize(Class<?> type, Object oldInstance, Object newInstance, Encoder out) { 900 super.initialize(type, oldInstance, newInstance, out); 901 java.awt.Menu m = (java.awt.Menu)oldInstance; 902 java.awt.Menu n = (java.awt.Menu)newInstance; 903 for (int i = n.getItemCount(); i < m.getItemCount(); i++) { 904 invokeStatement(oldInstance, "add", new Object[]{m.getItem(i)}, out); 905 } 906 } 907 } 908 909 // MenuBar 910 static final class java_awt_MenuBar_PersistenceDelegate extends DefaultPersistenceDelegate { 911 protected void initialize(Class<?> type, Object oldInstance, Object newInstance, Encoder out) { 912 super.initialize(type, oldInstance, newInstance, out); 913 java.awt.MenuBar m = (java.awt.MenuBar)oldInstance; 914 java.awt.MenuBar n = (java.awt.MenuBar)newInstance; 915 for (int i = n.getMenuCount(); i < m.getMenuCount(); i++) { 916 invokeStatement(oldInstance, "add", new Object[]{m.getMenu(i)}, out); 917 } 918 } 919 } 920 921 // List 922 static final class java_awt_List_PersistenceDelegate extends DefaultPersistenceDelegate { 923 protected void initialize(Class<?> type, Object oldInstance, Object newInstance, Encoder out) { 924 super.initialize(type, oldInstance, newInstance, out); 925 java.awt.List m = (java.awt.List)oldInstance; 926 java.awt.List n = (java.awt.List)newInstance; 927 for (int i = n.getItemCount(); i < m.getItemCount(); i++) { 928 invokeStatement(oldInstance, "add", new Object[]{m.getItem(i)}, out); 929 } 930 } 931 } 932 933 934 // LayoutManagers 935 936 // BorderLayout 937 static final class java_awt_BorderLayout_PersistenceDelegate extends DefaultPersistenceDelegate { 938 private static final String[] CONSTRAINTS = { 939 BorderLayout.NORTH, 940 BorderLayout.SOUTH, 941 BorderLayout.EAST, 942 BorderLayout.WEST, 943 BorderLayout.CENTER, 944 BorderLayout.PAGE_START, 945 BorderLayout.PAGE_END, 946 BorderLayout.LINE_START, 947 BorderLayout.LINE_END, 948 }; 949 @Override 950 protected void initialize(Class<?> type, Object oldInstance, 951 Object newInstance, Encoder out) { 952 super.initialize(type, oldInstance, newInstance, out); 953 BorderLayout oldLayout = (BorderLayout) oldInstance; 954 BorderLayout newLayout = (BorderLayout) newInstance; 955 for (String constraints : CONSTRAINTS) { 956 Object oldC = oldLayout.getLayoutComponent(constraints); 957 Object newC = newLayout.getLayoutComponent(constraints); 958 // Pending, assume any existing elements are OK. 959 if (oldC != null && newC == null) { 960 invokeStatement(oldInstance, "addLayoutComponent", 961 new Object[] { oldC, constraints }, out); 962 } 963 } 964 } 965 } 966 967 // CardLayout 968 static final class java_awt_CardLayout_PersistenceDelegate extends DefaultPersistenceDelegate { 969 protected void initialize(Class<?> type, Object oldInstance, 970 Object newInstance, Encoder out) { 971 super.initialize(type, oldInstance, newInstance, out); 972 if (getVector(newInstance).isEmpty()) { 973 for (Object card : getVector(oldInstance)) { 974 Object[] args = {MetaData.getPrivateFieldValue(card, "java.awt.CardLayout$Card.name"), 975 MetaData.getPrivateFieldValue(card, "java.awt.CardLayout$Card.comp")}; 976 invokeStatement(oldInstance, "addLayoutComponent", args, out); 977 } 978 } 979 } 980 protected boolean mutatesTo(Object oldInstance, Object newInstance) { 981 return super.mutatesTo(oldInstance, newInstance) && getVector(newInstance).isEmpty(); 982 } 983 private static Vector<?> getVector(Object instance) { 984 return (Vector<?>) MetaData.getPrivateFieldValue(instance, "java.awt.CardLayout.vector"); 985 } 986 } 987 988 // GridBagLayout 989 static final class java_awt_GridBagLayout_PersistenceDelegate extends DefaultPersistenceDelegate { 990 protected void initialize(Class<?> type, Object oldInstance, 991 Object newInstance, Encoder out) { 992 super.initialize(type, oldInstance, newInstance, out); 993 if (getHashtable(newInstance).isEmpty()) { 994 for (Map.Entry<?,?> entry : getHashtable(oldInstance).entrySet()) { 995 Object[] args = {entry.getKey(), entry.getValue()}; 996 invokeStatement(oldInstance, "addLayoutComponent", args, out); 997 } 998 } 999 } 1000 protected boolean mutatesTo(Object oldInstance, Object newInstance) { 1001 return super.mutatesTo(oldInstance, newInstance) && getHashtable(newInstance).isEmpty(); 1002 } 1003 private static Hashtable<?,?> getHashtable(Object instance) { 1004 return (Hashtable<?,?>) MetaData.getPrivateFieldValue(instance, "java.awt.GridBagLayout.comptable"); 1005 } 1006 } 1007 1008 // Swing 1009 1010 // JFrame (If we do this for Window instead of JFrame, the setVisible call 1011 // will be issued before we have added all the children to the JFrame and 1012 // will appear blank). 1013 static final class javax_swing_JFrame_PersistenceDelegate extends DefaultPersistenceDelegate { 1014 protected void initialize(Class<?> type, Object oldInstance, Object newInstance, Encoder out) { 1015 super.initialize(type, oldInstance, newInstance, out); 1016 java.awt.Window oldC = (java.awt.Window)oldInstance; 1017 java.awt.Window newC = (java.awt.Window)newInstance; 1018 boolean oldV = oldC.isVisible(); 1019 boolean newV = newC.isVisible(); 1020 if (newV != oldV) { 1021 // false means: don't execute this statement at write time. 1022 boolean executeStatements = out.executeStatements; 1023 out.executeStatements = false; 1024 invokeStatement(oldInstance, "setVisible", new Object[]{Boolean.valueOf(oldV)}, out); 1025 out.executeStatements = executeStatements; 1026 } 1027 } 1028 } 1029 1030 // Models 1031 1032 // DefaultListModel 1033 static final class javax_swing_DefaultListModel_PersistenceDelegate extends DefaultPersistenceDelegate { 1034 protected void initialize(Class<?> type, Object oldInstance, Object newInstance, Encoder out) { 1035 // Note, the "size" property will be set here. 1036 super.initialize(type, oldInstance, newInstance, out); 1037 javax.swing.DefaultListModel<?> m = (javax.swing.DefaultListModel<?>)oldInstance; 1038 javax.swing.DefaultListModel<?> n = (javax.swing.DefaultListModel<?>)newInstance; 1039 for (int i = n.getSize(); i < m.getSize(); i++) { 1040 invokeStatement(oldInstance, "add", // Can also use "addElement". 1041 new Object[]{m.getElementAt(i)}, out); 1042 } 1043 } 1044 } 1045 1046 // DefaultComboBoxModel 1047 static final class javax_swing_DefaultComboBoxModel_PersistenceDelegate extends DefaultPersistenceDelegate { 1048 protected void initialize(Class<?> type, Object oldInstance, Object newInstance, Encoder out) { 1049 super.initialize(type, oldInstance, newInstance, out); 1050 javax.swing.DefaultComboBoxModel<?> m = (javax.swing.DefaultComboBoxModel<?>)oldInstance; 1051 for (int i = 0; i < m.getSize(); i++) { 1052 invokeStatement(oldInstance, "addElement", new Object[]{m.getElementAt(i)}, out); 1053 } 1054 } 1055 } 1056 1057 1058 // DefaultMutableTreeNode 1059 static final class javax_swing_tree_DefaultMutableTreeNode_PersistenceDelegate extends DefaultPersistenceDelegate { 1060 protected void initialize(Class<?> type, Object oldInstance, Object 1061 newInstance, Encoder out) { 1062 super.initialize(type, oldInstance, newInstance, out); 1063 javax.swing.tree.DefaultMutableTreeNode m = 1064 (javax.swing.tree.DefaultMutableTreeNode)oldInstance; 1065 javax.swing.tree.DefaultMutableTreeNode n = 1066 (javax.swing.tree.DefaultMutableTreeNode)newInstance; 1067 for (int i = n.getChildCount(); i < m.getChildCount(); i++) { 1068 invokeStatement(oldInstance, "add", new 1069 Object[]{m.getChildAt(i)}, out); 1070 } 1071 } 1072 } 1073 1074 // ToolTipManager 1075 static final class javax_swing_ToolTipManager_PersistenceDelegate extends PersistenceDelegate { 1076 protected Expression instantiate(Object oldInstance, Encoder out) { 1077 return new Expression(oldInstance, javax.swing.ToolTipManager.class, 1078 "sharedInstance", new Object[]{}); 1079 } 1080 } 1081 1082 // JTabbedPane 1083 static final class javax_swing_JTabbedPane_PersistenceDelegate extends DefaultPersistenceDelegate { 1084 protected void initialize(Class<?> type, Object oldInstance, Object newInstance, Encoder out) { 1085 super.initialize(type, oldInstance, newInstance, out); 1086 javax.swing.JTabbedPane p = (javax.swing.JTabbedPane)oldInstance; 1087 for (int i = 0; i < p.getTabCount(); i++) { 1088 invokeStatement(oldInstance, "addTab", 1089 new Object[]{ 1090 p.getTitleAt(i), 1091 p.getIconAt(i), 1092 p.getComponentAt(i)}, out); 1093 } 1094 } 1095 } 1096 1097 // Box 1098 static final class javax_swing_Box_PersistenceDelegate extends DefaultPersistenceDelegate { 1099 protected boolean mutatesTo(Object oldInstance, Object newInstance) { 1100 return super.mutatesTo(oldInstance, newInstance) && getAxis(oldInstance).equals(getAxis(newInstance)); 1101 } 1102 1103 protected Expression instantiate(Object oldInstance, Encoder out) { 1104 return new Expression(oldInstance, oldInstance.getClass(), "new", new Object[] {getAxis(oldInstance)}); 1105 } 1106 1107 private Integer getAxis(Object object) { 1108 Box box = (Box) object; 1109 return (Integer) MetaData.getPrivateFieldValue(box.getLayout(), "javax.swing.BoxLayout.axis"); 1110 } 1111 } 1112 1113 // JMenu 1114 // Note that we do not need to state the initialiser for 1115 // JMenuItems since the getComponents() method defined in 1116 // Container will return all of the sub menu items that 1117 // need to be added to the menu item. 1118 // Not so for JMenu apparently. 1119 static final class javax_swing_JMenu_PersistenceDelegate extends DefaultPersistenceDelegate { 1120 protected void initialize(Class<?> type, Object oldInstance, Object newInstance, Encoder out) { 1121 super.initialize(type, oldInstance, newInstance, out); 1122 javax.swing.JMenu m = (javax.swing.JMenu)oldInstance; 1123 java.awt.Component[] c = m.getMenuComponents(); 1124 for (int i = 0; i < c.length; i++) { 1125 invokeStatement(oldInstance, "add", new Object[]{c[i]}, out); 1126 } 1127 } 1128 } 1129 1130 /** 1131 * The persistence delegate for {@link MatteBorder}. 1132 * It is impossible to use {@link DefaultPersistenceDelegate} 1133 * because this class does not have writable properties. 1134 * 1135 * @author Sergey A. Malenkov 1136 */ 1137 static final class javax_swing_border_MatteBorder_PersistenceDelegate extends PersistenceDelegate { 1138 protected Expression instantiate(Object oldInstance, Encoder out) { 1139 MatteBorder border = (MatteBorder) oldInstance; 1140 Insets insets = border.getBorderInsets(); 1141 Object object = border.getTileIcon(); 1142 if (object == null) { 1143 object = border.getMatteColor(); 1144 } 1145 Object[] args = new Object[] { 1146 insets.top, 1147 insets.left, 1148 insets.bottom, 1149 insets.right, 1150 object, 1151 }; 1152 return new Expression(border, border.getClass(), "new", args); 1153 } 1154 } 1155 1156 /* XXX - doens't seem to work. Debug later. 1157 static final class javax_swing_JMenu_PersistenceDelegate extends DefaultPersistenceDelegate { 1158 protected void initialize(Class<?> type, Object oldInstance, Object newInstance, Encoder out) { 1159 super.initialize(type, oldInstance, newInstance, out); 1160 javax.swing.JMenu m = (javax.swing.JMenu)oldInstance; 1161 javax.swing.JMenu n = (javax.swing.JMenu)newInstance; 1162 for (int i = n.getItemCount(); i < m.getItemCount(); i++) { 1163 invokeStatement(oldInstance, "add", new Object[]{m.getItem(i)}, out); 1164 } 1165 } 1166 } 1167 */ 1168 1169 /** 1170 * The persistence delegate for {@link PrintColorUIResource}. 1171 * It is impossible to use {@link DefaultPersistenceDelegate} 1172 * because this class has special rule for serialization: 1173 * it should be converted to {@link ColorUIResource}. 1174 * 1175 * @see PrintColorUIResource#writeReplace 1176 * 1177 * @author Sergey A. Malenkov 1178 */ 1179 static final class sun_swing_PrintColorUIResource_PersistenceDelegate extends PersistenceDelegate { 1180 protected boolean mutatesTo(Object oldInstance, Object newInstance) { 1181 return oldInstance.equals(newInstance); 1182 } 1183 1184 protected Expression instantiate(Object oldInstance, Encoder out) { 1185 Color color = (Color) oldInstance; 1186 Object[] args = new Object[] {color.getRGB()}; 1187 return new Expression(color, ColorUIResource.class, "new", args); 1188 } 1189 } 1190 1191 private static final Map<String,Field> fields = Collections.synchronizedMap(new WeakHashMap<String, Field>()); 1192 private static Hashtable<String, PersistenceDelegate> internalPersistenceDelegates = new Hashtable<>(); 1193 1194 private static PersistenceDelegate nullPersistenceDelegate = new NullPersistenceDelegate(); 1195 private static PersistenceDelegate enumPersistenceDelegate = new EnumPersistenceDelegate(); 1196 private static PersistenceDelegate primitivePersistenceDelegate = new PrimitivePersistenceDelegate(); 1197 private static PersistenceDelegate defaultPersistenceDelegate = new DefaultPersistenceDelegate(); 1198 private static PersistenceDelegate arrayPersistenceDelegate; 1199 private static PersistenceDelegate proxyPersistenceDelegate; 1200 1201 static { 1202 1203 internalPersistenceDelegates.put("java.net.URI", 1204 new PrimitivePersistenceDelegate()); 1205 1206 // it is possible because MatteBorder is assignable from MatteBorderUIResource 1207 internalPersistenceDelegates.put("javax.swing.plaf.BorderUIResource$MatteBorderUIResource", 1208 new javax_swing_border_MatteBorder_PersistenceDelegate()); 1209 1210 // it is possible because FontUIResource is supported by java_awt_Font_PersistenceDelegate 1211 internalPersistenceDelegates.put("javax.swing.plaf.FontUIResource", 1212 new java_awt_Font_PersistenceDelegate()); 1213 1214 // it is possible because KeyStroke is supported by java_awt_AWTKeyStroke_PersistenceDelegate 1215 internalPersistenceDelegates.put("javax.swing.KeyStroke", 1216 new java_awt_AWTKeyStroke_PersistenceDelegate()); 1217 1218 internalPersistenceDelegates.put("java.sql.Date", new java_util_Date_PersistenceDelegate()); 1219 internalPersistenceDelegates.put("java.sql.Time", new java_util_Date_PersistenceDelegate()); 1220 } 1221 1222 @SuppressWarnings("rawtypes") 1223 public static synchronized PersistenceDelegate getPersistenceDelegate(Class type) { 1224 if (type == null) { 1225 return nullPersistenceDelegate; 1226 } 1227 if (Enum.class.isAssignableFrom(type)) { 1228 return enumPersistenceDelegate; 1229 } 1230 if (null != XMLEncoder.primitiveTypeFor(type)) { 1231 return primitivePersistenceDelegate; 1232 } 1233 // The persistence delegate for arrays is non-trivial; instantiate it lazily. 1234 if (type.isArray()) { 1235 if (arrayPersistenceDelegate == null) { 1236 arrayPersistenceDelegate = new ArrayPersistenceDelegate(); 1237 } 1238 return arrayPersistenceDelegate; 1239 } 1240 // Handle proxies lazily for backward compatibility with 1.2. 1241 try { 1242 if (java.lang.reflect.Proxy.isProxyClass(type)) { 1243 if (proxyPersistenceDelegate == null) { 1244 proxyPersistenceDelegate = new ProxyPersistenceDelegate(); 1245 } 1246 return proxyPersistenceDelegate; 1247 } 1248 } 1249 catch(Exception e) {} 1250 // else if (type.getDeclaringClass() != null) { 1251 // return new DefaultPersistenceDelegate(new String[]{"this$0"}); 1252 // } 1253 1254 String typeName = type.getName(); 1255 PersistenceDelegate pd = (PersistenceDelegate)getBeanAttribute(type, "persistenceDelegate"); 1256 if (pd == null) { 1257 pd = internalPersistenceDelegates.get(typeName); 1258 if (pd != null) { 1259 return pd; 1260 } 1261 internalPersistenceDelegates.put(typeName, defaultPersistenceDelegate); 1262 try { 1263 String name = type.getName(); 1264 Class<?> c = Class.forName("java.beans.MetaData$" + name.replace('.', '_') 1265 + "_PersistenceDelegate"); 1266 pd = (PersistenceDelegate)c.getDeclaredConstructor().newInstance(); 1267 internalPersistenceDelegates.put(typeName, pd); 1268 } 1269 catch (ClassNotFoundException e) { 1270 String[] properties = getConstructorProperties(type); 1271 if (properties != null) { 1272 pd = new DefaultPersistenceDelegate(properties); 1273 internalPersistenceDelegates.put(typeName, pd); 1274 } 1275 } 1276 catch (Exception e) { 1277 System.err.println("Internal error: " + e); 1278 } 1279 } 1280 1281 return (pd != null) ? pd : defaultPersistenceDelegate; 1282 } 1283 1284 private static String[] getConstructorProperties(Class<?> type) { 1285 String[] names = null; 1286 int length = 0; 1287 for (Constructor<?> constructor : type.getConstructors()) { 1288 String[] value = getAnnotationValue(constructor); 1289 if ((value != null) && (length < value.length) && isValid(constructor, value)) { 1290 names = value; 1291 length = value.length; 1292 } 1293 } 1294 return names; 1295 } 1296 1297 private static String[] getAnnotationValue(Constructor<?> constructor) { 1298 ConstructorProperties annotation = constructor.getAnnotation(ConstructorProperties.class); 1299 return (annotation != null) 1300 ? annotation.value() 1301 : null; 1302 } 1303 1304 private static boolean isValid(Constructor<?> constructor, String[] names) { 1305 Class<?>[] parameters = constructor.getParameterTypes(); 1306 if (names.length != parameters.length) { 1307 return false; 1308 } 1309 for (String name : names) { 1310 if (name == null) { 1311 return false; 1312 } 1313 } 1314 return true; 1315 } 1316 1317 private static Object getBeanAttribute(Class<?> type, String attribute) { 1318 try { 1319 return Introspector.getBeanInfo(type).getBeanDescriptor().getValue(attribute); 1320 } catch (IntrospectionException exception) { 1321 return null; 1322 } 1323 } 1324 1325 static Object getPrivateFieldValue(Object instance, String name) { 1326 Field field = fields.get(name); 1327 if (field == null) { 1328 int index = name.lastIndexOf('.'); 1329 final String className = name.substring(0, index); 1330 final String fieldName = name.substring(1 + index); 1331 field = AccessController.doPrivileged(new PrivilegedAction<Field>() { 1332 public Field run() { 1333 try { 1334 Field field = Class.forName(className).getDeclaredField(fieldName); 1335 field.setAccessible(true); 1336 return field; 1337 } 1338 catch (ClassNotFoundException exception) { 1339 throw new IllegalStateException("Could not find class", exception); 1340 } 1341 catch (NoSuchFieldException exception) { 1342 throw new IllegalStateException("Could not find field", exception); 1343 } 1344 } 1345 }); 1346 fields.put(name, field); 1347 } 1348 try { 1349 return field.get(instance); 1350 } 1351 catch (IllegalAccessException exception) { 1352 throw new IllegalStateException("Could not get value of the field", exception); 1353 } 1354 } 1355 } --- EOF ---