Path: blob/aarch64-shenandoah-jdk8u272-b10/jdk/src/share/classes/java/beans/MetaData.java
38829 views
/*1* Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation. Oracle designates this7* particular file as subject to the "Classpath" exception as provided8* by Oracle in the LICENSE file that accompanied this code.9*10* This code is distributed in the hope that it will be useful, but WITHOUT11* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or12* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License13* version 2 for more details (a copy is included in the LICENSE file that14* accompanied this code).15*16* You should have received a copy of the GNU General Public License version17* 2 along with this work; if not, write to the Free Software Foundation,18* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.19*20* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA21* or visit www.oracle.com if you need additional information or have any22* questions.23*/24package java.beans;2526import com.sun.beans.finder.PrimitiveWrapperMap;2728import java.awt.AWTKeyStroke;29import java.awt.BorderLayout;30import java.awt.Dimension;31import java.awt.Color;32import java.awt.Font;33import java.awt.GridBagConstraints;34import java.awt.Insets;35import java.awt.Point;36import java.awt.Rectangle;37import java.awt.event.KeyEvent;38import java.awt.font.TextAttribute;3940import java.lang.reflect.Array;41import java.lang.reflect.Constructor;42import java.lang.reflect.Field;43import java.lang.reflect.Method;44import java.lang.reflect.Modifier;45import java.lang.reflect.InvocationTargetException;4647import java.security.AccessController;48import java.security.PrivilegedAction;4950import java.util.*;5152import javax.swing.Box;53import javax.swing.JLayeredPane;54import javax.swing.border.MatteBorder;55import javax.swing.plaf.ColorUIResource;5657import sun.swing.PrintColorUIResource;5859import static sun.reflect.misc.ReflectUtil.isPackageAccessible;6061/*62* Like the <code>Intropector</code>, the <code>MetaData</code> class63* contains <em>meta</em> objects that describe the way64* classes should express their state in terms of their65* own public APIs.66*67* @see java.beans.Intropector68*69* @author Philip Milne70* @author Steve Langley71*/72class MetaData {7374static final class NullPersistenceDelegate extends PersistenceDelegate {75// Note this will be called by all classes when they reach the76// top of their superclass chain.77protected void initialize(Class<?> type, Object oldInstance, Object newInstance, Encoder out) {78}79protected Expression instantiate(Object oldInstance, Encoder out) { return null; }8081public void writeObject(Object oldInstance, Encoder out) {82// System.out.println("NullPersistenceDelegate:writeObject " + oldInstance);83}84}8586/**87* The persistence delegate for <CODE>enum</CODE> classes.88*89* @author Sergey A. Malenkov90*/91static final class EnumPersistenceDelegate extends PersistenceDelegate {92protected boolean mutatesTo(Object oldInstance, Object newInstance) {93return oldInstance == newInstance;94}9596protected Expression instantiate(Object oldInstance, Encoder out) {97Enum<?> e = (Enum<?>) oldInstance;98return new Expression(e, Enum.class, "valueOf", new Object[]{e.getDeclaringClass(), e.name()});99}100}101102static final class PrimitivePersistenceDelegate extends PersistenceDelegate {103protected boolean mutatesTo(Object oldInstance, Object newInstance) {104return oldInstance.equals(newInstance);105}106107protected Expression instantiate(Object oldInstance, Encoder out) {108return new Expression(oldInstance, oldInstance.getClass(),109"new", new Object[]{oldInstance.toString()});110}111}112113static final class ArrayPersistenceDelegate extends PersistenceDelegate {114protected boolean mutatesTo(Object oldInstance, Object newInstance) {115return (newInstance != null &&116oldInstance.getClass() == newInstance.getClass() && // Also ensures the subtype is correct.117Array.getLength(oldInstance) == Array.getLength(newInstance));118}119120protected Expression instantiate(Object oldInstance, Encoder out) {121// System.out.println("instantiate: " + type + " " + oldInstance);122Class<?> oldClass = oldInstance.getClass();123return new Expression(oldInstance, Array.class, "newInstance",124new Object[]{oldClass.getComponentType(),125new Integer(Array.getLength(oldInstance))});126}127128protected void initialize(Class<?> type, Object oldInstance, Object newInstance, Encoder out) {129int n = Array.getLength(oldInstance);130for (int i = 0; i < n; i++) {131Object index = new Integer(i);132// Expression oldGetExp = new Expression(Array.class, "get", new Object[]{oldInstance, index});133// Expression newGetExp = new Expression(Array.class, "get", new Object[]{newInstance, index});134Expression oldGetExp = new Expression(oldInstance, "get", new Object[]{index});135Expression newGetExp = new Expression(newInstance, "get", new Object[]{index});136try {137Object oldValue = oldGetExp.getValue();138Object newValue = newGetExp.getValue();139out.writeExpression(oldGetExp);140if (!Objects.equals(newValue, out.get(oldValue))) {141// System.out.println("Not equal: " + newGetExp + " != " + actualGetExp);142// invokeStatement(Array.class, "set", new Object[]{oldInstance, index, oldValue}, out);143DefaultPersistenceDelegate.invokeStatement(oldInstance, "set", new Object[]{index, oldValue}, out);144}145}146catch (Exception e) {147// System.err.println("Warning:: failed to write: " + oldGetExp);148out.getExceptionListener().exceptionThrown(e);149}150}151}152}153154static final class ProxyPersistenceDelegate extends PersistenceDelegate {155protected Expression instantiate(Object oldInstance, Encoder out) {156Class<?> type = oldInstance.getClass();157java.lang.reflect.Proxy p = (java.lang.reflect.Proxy)oldInstance;158// This unappealing hack is not required but makes the159// representation of EventHandlers much more concise.160java.lang.reflect.InvocationHandler ih = java.lang.reflect.Proxy.getInvocationHandler(p);161if (ih instanceof EventHandler) {162EventHandler eh = (EventHandler)ih;163Vector<Object> args = new Vector<>();164args.add(type.getInterfaces()[0]);165args.add(eh.getTarget());166args.add(eh.getAction());167if (eh.getEventPropertyName() != null) {168args.add(eh.getEventPropertyName());169}170if (eh.getListenerMethodName() != null) {171args.setSize(4);172args.add(eh.getListenerMethodName());173}174return new Expression(oldInstance,175EventHandler.class,176"create",177args.toArray());178}179return new Expression(oldInstance,180java.lang.reflect.Proxy.class,181"newProxyInstance",182new Object[]{type.getClassLoader(),183type.getInterfaces(),184ih});185}186}187188// Strings189static final class java_lang_String_PersistenceDelegate extends PersistenceDelegate {190protected Expression instantiate(Object oldInstance, Encoder out) { return null; }191192public void writeObject(Object oldInstance, Encoder out) {193// System.out.println("NullPersistenceDelegate:writeObject " + oldInstance);194}195}196197// Classes198static final class java_lang_Class_PersistenceDelegate extends PersistenceDelegate {199protected boolean mutatesTo(Object oldInstance, Object newInstance) {200return oldInstance.equals(newInstance);201}202203protected Expression instantiate(Object oldInstance, Encoder out) {204Class<?> c = (Class)oldInstance;205// As of 1.3 it is not possible to call Class.forName("int"),206// so we have to generate different code for primitive types.207// This is needed for arrays whose subtype may be primitive.208if (c.isPrimitive()) {209Field field = null;210try {211field = PrimitiveWrapperMap.getType(c.getName()).getDeclaredField("TYPE");212} catch (NoSuchFieldException ex) {213System.err.println("Unknown primitive type: " + c);214}215return new Expression(oldInstance, field, "get", new Object[]{null});216}217else if (oldInstance == String.class) {218return new Expression(oldInstance, "", "getClass", new Object[]{});219}220else if (oldInstance == Class.class) {221return new Expression(oldInstance, String.class, "getClass", new Object[]{});222}223else {224Expression newInstance = new Expression(oldInstance, Class.class, "forName", new Object[] { c.getName() });225newInstance.loader = c.getClassLoader();226return newInstance;227}228}229}230231// Fields232static final class java_lang_reflect_Field_PersistenceDelegate extends PersistenceDelegate {233protected boolean mutatesTo(Object oldInstance, Object newInstance) {234return oldInstance.equals(newInstance);235}236237protected Expression instantiate(Object oldInstance, Encoder out) {238Field f = (Field)oldInstance;239return new Expression(oldInstance,240f.getDeclaringClass(),241"getField",242new Object[]{f.getName()});243}244}245246// Methods247static final class java_lang_reflect_Method_PersistenceDelegate extends PersistenceDelegate {248protected boolean mutatesTo(Object oldInstance, Object newInstance) {249return oldInstance.equals(newInstance);250}251252protected Expression instantiate(Object oldInstance, Encoder out) {253Method m = (Method)oldInstance;254return new Expression(oldInstance,255m.getDeclaringClass(),256"getMethod",257new Object[]{m.getName(), m.getParameterTypes()});258}259}260261// Dates262263/**264* The persistence delegate for <CODE>java.util.Date</CODE> classes.265* Do not extend DefaultPersistenceDelegate to improve performance and266* to avoid problems with <CODE>java.sql.Date</CODE>,267* <CODE>java.sql.Time</CODE> and <CODE>java.sql.Timestamp</CODE>.268*269* @author Sergey A. Malenkov270*/271static class java_util_Date_PersistenceDelegate extends PersistenceDelegate {272protected boolean mutatesTo(Object oldInstance, Object newInstance) {273if (!super.mutatesTo(oldInstance, newInstance)) {274return false;275}276Date oldDate = (Date)oldInstance;277Date newDate = (Date)newInstance;278279return oldDate.getTime() == newDate.getTime();280}281282protected Expression instantiate(Object oldInstance, Encoder out) {283Date date = (Date)oldInstance;284return new Expression(date, date.getClass(), "new", new Object[] {date.getTime()});285}286}287288/**289* The persistence delegate for <CODE>java.sql.Timestamp</CODE> classes.290* It supports nanoseconds.291*292* @author Sergey A. Malenkov293*/294static final class java_sql_Timestamp_PersistenceDelegate extends java_util_Date_PersistenceDelegate {295private static final Method getNanosMethod = getNanosMethod();296297private static Method getNanosMethod() {298try {299Class<?> c = Class.forName("java.sql.Timestamp", true, null);300return c.getMethod("getNanos");301} catch (ClassNotFoundException e) {302return null;303} catch (NoSuchMethodException e) {304throw new AssertionError(e);305}306}307308/**309* Invoke Timstamp getNanos.310*/311private static int getNanos(Object obj) {312if (getNanosMethod == null)313throw new AssertionError("Should not get here");314try {315return (Integer)getNanosMethod.invoke(obj);316} catch (InvocationTargetException e) {317Throwable cause = e.getCause();318if (cause instanceof RuntimeException)319throw (RuntimeException)cause;320if (cause instanceof Error)321throw (Error)cause;322throw new AssertionError(e);323} catch (IllegalAccessException iae) {324throw new AssertionError(iae);325}326}327328protected void initialize(Class<?> type, Object oldInstance, Object newInstance, Encoder out) {329// assumes oldInstance and newInstance are Timestamps330int nanos = getNanos(oldInstance);331if (nanos != getNanos(newInstance)) {332out.writeStatement(new Statement(oldInstance, "setNanos", new Object[] {nanos}));333}334}335}336337// Collections338339/*340The Hashtable and AbstractMap classes have no common ancestor yet may341be handled with a single persistence delegate: one which uses the methods342of the Map insterface exclusively. Attatching the persistence delegates343to the interfaces themselves is fraught however since, in the case of344the Map, both the AbstractMap and HashMap classes are declared to345implement the Map interface, leaving the obvious implementation prone346to repeating their initialization. These issues and questions around347the ordering of delegates attached to interfaces have lead us to348ignore any delegates attached to interfaces and force all persistence349delegates to be registered with concrete classes.350*/351352/**353* The base class for persistence delegates for inner classes354* that can be created using {@link Collections}.355*356* @author Sergey A. Malenkov357*/358private static abstract class java_util_Collections extends PersistenceDelegate {359protected boolean mutatesTo(Object oldInstance, Object newInstance) {360if (!super.mutatesTo(oldInstance, newInstance)) {361return false;362}363if ((oldInstance instanceof List) || (oldInstance instanceof Set) || (oldInstance instanceof Map)) {364return oldInstance.equals(newInstance);365}366Collection<?> oldC = (Collection<?>) oldInstance;367Collection<?> newC = (Collection<?>) newInstance;368return (oldC.size() == newC.size()) && oldC.containsAll(newC);369}370371protected void initialize(Class<?> type, Object oldInstance, Object newInstance, Encoder out) {372// do not initialize these custom collections in default way373}374375static final class EmptyList_PersistenceDelegate extends java_util_Collections {376protected Expression instantiate(Object oldInstance, Encoder out) {377return new Expression(oldInstance, Collections.class, "emptyList", null);378}379}380381static final class EmptySet_PersistenceDelegate extends java_util_Collections {382protected Expression instantiate(Object oldInstance, Encoder out) {383return new Expression(oldInstance, Collections.class, "emptySet", null);384}385}386387static final class EmptyMap_PersistenceDelegate extends java_util_Collections {388protected Expression instantiate(Object oldInstance, Encoder out) {389return new Expression(oldInstance, Collections.class, "emptyMap", null);390}391}392393static final class SingletonList_PersistenceDelegate extends java_util_Collections {394protected Expression instantiate(Object oldInstance, Encoder out) {395List<?> list = (List<?>) oldInstance;396return new Expression(oldInstance, Collections.class, "singletonList", new Object[]{list.get(0)});397}398}399400static final class SingletonSet_PersistenceDelegate extends java_util_Collections {401protected Expression instantiate(Object oldInstance, Encoder out) {402Set<?> set = (Set<?>) oldInstance;403return new Expression(oldInstance, Collections.class, "singleton", new Object[]{set.iterator().next()});404}405}406407static final class SingletonMap_PersistenceDelegate extends java_util_Collections {408protected Expression instantiate(Object oldInstance, Encoder out) {409Map<?,?> map = (Map<?,?>) oldInstance;410Object key = map.keySet().iterator().next();411return new Expression(oldInstance, Collections.class, "singletonMap", new Object[]{key, map.get(key)});412}413}414415static final class UnmodifiableCollection_PersistenceDelegate extends java_util_Collections {416protected Expression instantiate(Object oldInstance, Encoder out) {417List<?> list = new ArrayList<>((Collection<?>) oldInstance);418return new Expression(oldInstance, Collections.class, "unmodifiableCollection", new Object[]{list});419}420}421422static final class UnmodifiableList_PersistenceDelegate extends java_util_Collections {423protected Expression instantiate(Object oldInstance, Encoder out) {424List<?> list = new LinkedList<>((Collection<?>) oldInstance);425return new Expression(oldInstance, Collections.class, "unmodifiableList", new Object[]{list});426}427}428429static final class UnmodifiableRandomAccessList_PersistenceDelegate extends java_util_Collections {430protected Expression instantiate(Object oldInstance, Encoder out) {431List<?> list = new ArrayList<>((Collection<?>) oldInstance);432return new Expression(oldInstance, Collections.class, "unmodifiableList", new Object[]{list});433}434}435436static final class UnmodifiableSet_PersistenceDelegate extends java_util_Collections {437protected Expression instantiate(Object oldInstance, Encoder out) {438Set<?> set = new HashSet<>((Set<?>) oldInstance);439return new Expression(oldInstance, Collections.class, "unmodifiableSet", new Object[]{set});440}441}442443static final class UnmodifiableSortedSet_PersistenceDelegate extends java_util_Collections {444protected Expression instantiate(Object oldInstance, Encoder out) {445SortedSet<?> set = new TreeSet<>((SortedSet<?>) oldInstance);446return new Expression(oldInstance, Collections.class, "unmodifiableSortedSet", new Object[]{set});447}448}449450static final class UnmodifiableMap_PersistenceDelegate extends java_util_Collections {451protected Expression instantiate(Object oldInstance, Encoder out) {452Map<?,?> map = new HashMap<>((Map<?,?>) oldInstance);453return new Expression(oldInstance, Collections.class, "unmodifiableMap", new Object[]{map});454}455}456457static final class UnmodifiableSortedMap_PersistenceDelegate extends java_util_Collections {458protected Expression instantiate(Object oldInstance, Encoder out) {459SortedMap<?,?> map = new TreeMap<>((SortedMap<?,?>) oldInstance);460return new Expression(oldInstance, Collections.class, "unmodifiableSortedMap", new Object[]{map});461}462}463464static final class SynchronizedCollection_PersistenceDelegate extends java_util_Collections {465protected Expression instantiate(Object oldInstance, Encoder out) {466List<?> list = new ArrayList<>((Collection<?>) oldInstance);467return new Expression(oldInstance, Collections.class, "synchronizedCollection", new Object[]{list});468}469}470471static final class SynchronizedList_PersistenceDelegate extends java_util_Collections {472protected Expression instantiate(Object oldInstance, Encoder out) {473List<?> list = new LinkedList<>((Collection<?>) oldInstance);474return new Expression(oldInstance, Collections.class, "synchronizedList", new Object[]{list});475}476}477478static final class SynchronizedRandomAccessList_PersistenceDelegate extends java_util_Collections {479protected Expression instantiate(Object oldInstance, Encoder out) {480List<?> list = new ArrayList<>((Collection<?>) oldInstance);481return new Expression(oldInstance, Collections.class, "synchronizedList", new Object[]{list});482}483}484485static final class SynchronizedSet_PersistenceDelegate extends java_util_Collections {486protected Expression instantiate(Object oldInstance, Encoder out) {487Set<?> set = new HashSet<>((Set<?>) oldInstance);488return new Expression(oldInstance, Collections.class, "synchronizedSet", new Object[]{set});489}490}491492static final class SynchronizedSortedSet_PersistenceDelegate extends java_util_Collections {493protected Expression instantiate(Object oldInstance, Encoder out) {494SortedSet<?> set = new TreeSet<>((SortedSet<?>) oldInstance);495return new Expression(oldInstance, Collections.class, "synchronizedSortedSet", new Object[]{set});496}497}498499static final class SynchronizedMap_PersistenceDelegate extends java_util_Collections {500protected Expression instantiate(Object oldInstance, Encoder out) {501Map<?,?> map = new HashMap<>((Map<?,?>) oldInstance);502return new Expression(oldInstance, Collections.class, "synchronizedMap", new Object[]{map});503}504}505506static final class SynchronizedSortedMap_PersistenceDelegate extends java_util_Collections {507protected Expression instantiate(Object oldInstance, Encoder out) {508SortedMap<?,?> map = new TreeMap<>((SortedMap<?,?>) oldInstance);509return new Expression(oldInstance, Collections.class, "synchronizedSortedMap", new Object[]{map});510}511}512513static final class CheckedCollection_PersistenceDelegate extends java_util_Collections {514protected Expression instantiate(Object oldInstance, Encoder out) {515Object type = MetaData.getPrivateFieldValue(oldInstance, "java.util.Collections$CheckedCollection.type");516List<?> list = new ArrayList<>((Collection<?>) oldInstance);517return new Expression(oldInstance, Collections.class, "checkedCollection", new Object[]{list, type});518}519}520521static final class CheckedList_PersistenceDelegate extends java_util_Collections {522protected Expression instantiate(Object oldInstance, Encoder out) {523Object type = MetaData.getPrivateFieldValue(oldInstance, "java.util.Collections$CheckedCollection.type");524List<?> list = new LinkedList<>((Collection<?>) oldInstance);525return new Expression(oldInstance, Collections.class, "checkedList", new Object[]{list, type});526}527}528529static final class CheckedRandomAccessList_PersistenceDelegate extends java_util_Collections {530protected Expression instantiate(Object oldInstance, Encoder out) {531Object type = MetaData.getPrivateFieldValue(oldInstance, "java.util.Collections$CheckedCollection.type");532List<?> list = new ArrayList<>((Collection<?>) oldInstance);533return new Expression(oldInstance, Collections.class, "checkedList", new Object[]{list, type});534}535}536537static final class CheckedSet_PersistenceDelegate extends java_util_Collections {538protected Expression instantiate(Object oldInstance, Encoder out) {539Object type = MetaData.getPrivateFieldValue(oldInstance, "java.util.Collections$CheckedCollection.type");540Set<?> set = new HashSet<>((Set<?>) oldInstance);541return new Expression(oldInstance, Collections.class, "checkedSet", new Object[]{set, type});542}543}544545static final class CheckedSortedSet_PersistenceDelegate extends java_util_Collections {546protected Expression instantiate(Object oldInstance, Encoder out) {547Object type = MetaData.getPrivateFieldValue(oldInstance, "java.util.Collections$CheckedCollection.type");548SortedSet<?> set = new TreeSet<>((SortedSet<?>) oldInstance);549return new Expression(oldInstance, Collections.class, "checkedSortedSet", new Object[]{set, type});550}551}552553static final class CheckedMap_PersistenceDelegate extends java_util_Collections {554protected Expression instantiate(Object oldInstance, Encoder out) {555Object keyType = MetaData.getPrivateFieldValue(oldInstance, "java.util.Collections$CheckedMap.keyType");556Object valueType = MetaData.getPrivateFieldValue(oldInstance, "java.util.Collections$CheckedMap.valueType");557Map<?,?> map = new HashMap<>((Map<?,?>) oldInstance);558return new Expression(oldInstance, Collections.class, "checkedMap", new Object[]{map, keyType, valueType});559}560}561562static final class CheckedSortedMap_PersistenceDelegate extends java_util_Collections {563protected Expression instantiate(Object oldInstance, Encoder out) {564Object keyType = MetaData.getPrivateFieldValue(oldInstance, "java.util.Collections$CheckedMap.keyType");565Object valueType = MetaData.getPrivateFieldValue(oldInstance, "java.util.Collections$CheckedMap.valueType");566SortedMap<?,?> map = new TreeMap<>((SortedMap<?,?>) oldInstance);567return new Expression(oldInstance, Collections.class, "checkedSortedMap", new Object[]{map, keyType, valueType});568}569}570}571572/**573* The persistence delegate for <CODE>java.util.EnumMap</CODE> classes.574*575* @author Sergey A. Malenkov576*/577static final class java_util_EnumMap_PersistenceDelegate extends PersistenceDelegate {578protected boolean mutatesTo(Object oldInstance, Object newInstance) {579return super.mutatesTo(oldInstance, newInstance) && (getType(oldInstance) == getType(newInstance));580}581582protected Expression instantiate(Object oldInstance, Encoder out) {583return new Expression(oldInstance, EnumMap.class, "new", new Object[] {getType(oldInstance)});584}585586private static Object getType(Object instance) {587return MetaData.getPrivateFieldValue(instance, "java.util.EnumMap.keyType");588}589}590591/**592* The persistence delegate for <CODE>java.util.EnumSet</CODE> classes.593*594* @author Sergey A. Malenkov595*/596static final class java_util_EnumSet_PersistenceDelegate extends PersistenceDelegate {597protected boolean mutatesTo(Object oldInstance, Object newInstance) {598return super.mutatesTo(oldInstance, newInstance) && (getType(oldInstance) == getType(newInstance));599}600601protected Expression instantiate(Object oldInstance, Encoder out) {602return new Expression(oldInstance, EnumSet.class, "noneOf", new Object[] {getType(oldInstance)});603}604605private static Object getType(Object instance) {606return MetaData.getPrivateFieldValue(instance, "java.util.EnumSet.elementType");607}608}609610// Collection611static class java_util_Collection_PersistenceDelegate extends DefaultPersistenceDelegate {612protected void initialize(Class<?> type, Object oldInstance, Object newInstance, Encoder out) {613java.util.Collection<?> oldO = (java.util.Collection)oldInstance;614java.util.Collection<?> newO = (java.util.Collection)newInstance;615616if (newO.size() != 0) {617invokeStatement(oldInstance, "clear", new Object[]{}, out);618}619for (Iterator<?> i = oldO.iterator(); i.hasNext();) {620invokeStatement(oldInstance, "add", new Object[]{i.next()}, out);621}622}623}624625// List626static class java_util_List_PersistenceDelegate extends DefaultPersistenceDelegate {627protected void initialize(Class<?> type, Object oldInstance, Object newInstance, Encoder out) {628java.util.List<?> oldO = (java.util.List<?>)oldInstance;629java.util.List<?> newO = (java.util.List<?>)newInstance;630int oldSize = oldO.size();631int newSize = (newO == null) ? 0 : newO.size();632if (oldSize < newSize) {633invokeStatement(oldInstance, "clear", new Object[]{}, out);634newSize = 0;635}636for (int i = 0; i < newSize; i++) {637Object index = new Integer(i);638639Expression oldGetExp = new Expression(oldInstance, "get", new Object[]{index});640Expression newGetExp = new Expression(newInstance, "get", new Object[]{index});641try {642Object oldValue = oldGetExp.getValue();643Object newValue = newGetExp.getValue();644out.writeExpression(oldGetExp);645if (!Objects.equals(newValue, out.get(oldValue))) {646invokeStatement(oldInstance, "set", new Object[]{index, oldValue}, out);647}648}649catch (Exception e) {650out.getExceptionListener().exceptionThrown(e);651}652}653for (int i = newSize; i < oldSize; i++) {654invokeStatement(oldInstance, "add", new Object[]{oldO.get(i)}, out);655}656}657}658659660// Map661static class java_util_Map_PersistenceDelegate extends DefaultPersistenceDelegate {662protected void initialize(Class<?> type, Object oldInstance, Object newInstance, Encoder out) {663// System.out.println("Initializing: " + newInstance);664java.util.Map<?,?> oldMap = (java.util.Map)oldInstance;665java.util.Map<?,?> newMap = (java.util.Map)newInstance;666// Remove the new elements.667// Do this first otherwise we undo the adding work.668if (newMap != null) {669for (Object newKey : newMap.keySet().toArray()) {670// PENDING: This "key" is not in the right environment.671if (!oldMap.containsKey(newKey)) {672invokeStatement(oldInstance, "remove", new Object[]{newKey}, out);673}674}675}676// Add the new elements.677for ( Object oldKey : oldMap.keySet() ) {678Expression oldGetExp = new Expression(oldInstance, "get", new Object[]{oldKey});679// Pending: should use newKey.680Expression newGetExp = new Expression(newInstance, "get", new Object[]{oldKey});681try {682Object oldValue = oldGetExp.getValue();683Object newValue = newGetExp.getValue();684out.writeExpression(oldGetExp);685if (!Objects.equals(newValue, out.get(oldValue))) {686invokeStatement(oldInstance, "put", new Object[]{oldKey, oldValue}, out);687} else if ((newValue == null) && !newMap.containsKey(oldKey)) {688// put oldValue(=null?) if oldKey is absent in newMap689invokeStatement(oldInstance, "put", new Object[]{oldKey, oldValue}, out);690}691}692catch (Exception e) {693out.getExceptionListener().exceptionThrown(e);694}695}696}697}698699static final class java_util_AbstractCollection_PersistenceDelegate extends java_util_Collection_PersistenceDelegate {}700static final class java_util_AbstractList_PersistenceDelegate extends java_util_List_PersistenceDelegate {}701static final class java_util_AbstractMap_PersistenceDelegate extends java_util_Map_PersistenceDelegate {}702static final class java_util_Hashtable_PersistenceDelegate extends java_util_Map_PersistenceDelegate {}703704705// Beans706static final class java_beans_beancontext_BeanContextSupport_PersistenceDelegate extends java_util_Collection_PersistenceDelegate {}707708// AWT709710/**711* The persistence delegate for {@link Insets}.712* It is impossible to use {@link DefaultPersistenceDelegate}713* because this class does not have any properties.714*715* @author Sergey A. Malenkov716*/717static final class java_awt_Insets_PersistenceDelegate extends PersistenceDelegate {718protected boolean mutatesTo(Object oldInstance, Object newInstance) {719return oldInstance.equals(newInstance);720}721722protected Expression instantiate(Object oldInstance, Encoder out) {723Insets insets = (Insets) oldInstance;724Object[] args = new Object[] {725insets.top,726insets.left,727insets.bottom,728insets.right,729};730return new Expression(insets, insets.getClass(), "new", args);731}732}733734/**735* The persistence delegate for {@link Font}.736* It is impossible to use {@link DefaultPersistenceDelegate}737* because size of the font can be float value.738*739* @author Sergey A. Malenkov740*/741static final class java_awt_Font_PersistenceDelegate extends PersistenceDelegate {742protected boolean mutatesTo(Object oldInstance, Object newInstance) {743return oldInstance.equals(newInstance);744}745746protected Expression instantiate(Object oldInstance, Encoder out) {747Font font = (Font) oldInstance;748749int count = 0;750String family = null;751int style = Font.PLAIN;752int size = 12;753754Map<TextAttribute, ?> basic = font.getAttributes();755Map<TextAttribute, Object> clone = new HashMap<>(basic.size());756for (TextAttribute key : basic.keySet()) {757Object value = basic.get(key);758if (value != null) {759clone.put(key, value);760}761if (key == TextAttribute.FAMILY) {762if (value instanceof String) {763count++;764family = (String) value;765}766}767else if (key == TextAttribute.WEIGHT) {768if (TextAttribute.WEIGHT_REGULAR.equals(value)) {769count++;770} else if (TextAttribute.WEIGHT_BOLD.equals(value)) {771count++;772style |= Font.BOLD;773}774}775else if (key == TextAttribute.POSTURE) {776if (TextAttribute.POSTURE_REGULAR.equals(value)) {777count++;778} else if (TextAttribute.POSTURE_OBLIQUE.equals(value)) {779count++;780style |= Font.ITALIC;781}782} else if (key == TextAttribute.SIZE) {783if (value instanceof Number) {784Number number = (Number) value;785size = number.intValue();786if (size == number.floatValue()) {787count++;788}789}790}791}792Class<?> type = font.getClass();793if (count == clone.size()) {794return new Expression(font, type, "new", new Object[]{family, style, size});795}796if (type == Font.class) {797return new Expression(font, type, "getFont", new Object[]{clone});798}799return new Expression(font, type, "new", new Object[]{Font.getFont(clone)});800}801}802803/**804* The persistence delegate for {@link AWTKeyStroke}.805* It is impossible to use {@link DefaultPersistenceDelegate}806* because this class have no public constructor.807*808* @author Sergey A. Malenkov809*/810static final class java_awt_AWTKeyStroke_PersistenceDelegate extends PersistenceDelegate {811protected boolean mutatesTo(Object oldInstance, Object newInstance) {812return oldInstance.equals(newInstance);813}814815protected Expression instantiate(Object oldInstance, Encoder out) {816AWTKeyStroke key = (AWTKeyStroke) oldInstance;817818char ch = key.getKeyChar();819int code = key.getKeyCode();820int mask = key.getModifiers();821boolean onKeyRelease = key.isOnKeyRelease();822823Object[] args = null;824if (ch == KeyEvent.CHAR_UNDEFINED) {825args = !onKeyRelease826? new Object[]{code, mask}827: new Object[]{code, mask, onKeyRelease};828} else if (code == KeyEvent.VK_UNDEFINED) {829if (!onKeyRelease) {830args = (mask == 0)831? new Object[]{ch}832: new Object[]{ch, mask};833} else if (mask == 0) {834args = new Object[]{ch, onKeyRelease};835}836}837if (args == null) {838throw new IllegalStateException("Unsupported KeyStroke: " + key);839}840Class<?> type = key.getClass();841String name = type.getName();842// get short name of the class843int index = name.lastIndexOf('.') + 1;844if (index > 0) {845name = name.substring(index);846}847return new Expression( key, type, "get" + name, args );848}849}850851static class StaticFieldsPersistenceDelegate extends PersistenceDelegate {852protected void installFields(Encoder out, Class<?> cls) {853if (Modifier.isPublic(cls.getModifiers()) && isPackageAccessible(cls)) {854Field fields[] = cls.getFields();855for(int i = 0; i < fields.length; i++) {856Field field = fields[i];857// Don't install primitives, their identity will not be preserved858// by wrapping.859if (Object.class.isAssignableFrom(field.getType())) {860out.writeExpression(new Expression(field, "get", new Object[]{null}));861}862}863}864}865866protected Expression instantiate(Object oldInstance, Encoder out) {867throw new RuntimeException("Unrecognized instance: " + oldInstance);868}869870public void writeObject(Object oldInstance, Encoder out) {871if (out.getAttribute(this) == null) {872out.setAttribute(this, Boolean.TRUE);873installFields(out, oldInstance.getClass());874}875super.writeObject(oldInstance, out);876}877}878879// SystemColor880static final class java_awt_SystemColor_PersistenceDelegate extends StaticFieldsPersistenceDelegate {}881882// TextAttribute883static final class java_awt_font_TextAttribute_PersistenceDelegate extends StaticFieldsPersistenceDelegate {}884885// MenuShortcut886static final class java_awt_MenuShortcut_PersistenceDelegate extends PersistenceDelegate {887protected boolean mutatesTo(Object oldInstance, Object newInstance) {888return oldInstance.equals(newInstance);889}890891protected Expression instantiate(Object oldInstance, Encoder out) {892java.awt.MenuShortcut m = (java.awt.MenuShortcut)oldInstance;893return new Expression(oldInstance, m.getClass(), "new",894new Object[]{new Integer(m.getKey()), Boolean.valueOf(m.usesShiftModifier())});895}896}897898// Component899static final class java_awt_Component_PersistenceDelegate extends DefaultPersistenceDelegate {900protected void initialize(Class<?> type, Object oldInstance, Object newInstance, Encoder out) {901super.initialize(type, oldInstance, newInstance, out);902java.awt.Component c = (java.awt.Component)oldInstance;903java.awt.Component c2 = (java.awt.Component)newInstance;904// The "background", "foreground" and "font" properties.905// The foreground and font properties of Windows change from906// null to defined values after the Windows are made visible -907// special case them for now.908if (!(oldInstance instanceof java.awt.Window)) {909Object oldBackground = c.isBackgroundSet() ? c.getBackground() : null;910Object newBackground = c2.isBackgroundSet() ? c2.getBackground() : null;911if (!Objects.equals(oldBackground, newBackground)) {912invokeStatement(oldInstance, "setBackground", new Object[] { oldBackground }, out);913}914Object oldForeground = c.isForegroundSet() ? c.getForeground() : null;915Object newForeground = c2.isForegroundSet() ? c2.getForeground() : null;916if (!Objects.equals(oldForeground, newForeground)) {917invokeStatement(oldInstance, "setForeground", new Object[] { oldForeground }, out);918}919Object oldFont = c.isFontSet() ? c.getFont() : null;920Object newFont = c2.isFontSet() ? c2.getFont() : null;921if (!Objects.equals(oldFont, newFont)) {922invokeStatement(oldInstance, "setFont", new Object[] { oldFont }, out);923}924}925926// Bounds927java.awt.Container p = c.getParent();928if (p == null || p.getLayout() == null) {929// Use the most concise construct.930boolean locationCorrect = c.getLocation().equals(c2.getLocation());931boolean sizeCorrect = c.getSize().equals(c2.getSize());932if (!locationCorrect && !sizeCorrect) {933invokeStatement(oldInstance, "setBounds", new Object[]{c.getBounds()}, out);934}935else if (!locationCorrect) {936invokeStatement(oldInstance, "setLocation", new Object[]{c.getLocation()}, out);937}938else if (!sizeCorrect) {939invokeStatement(oldInstance, "setSize", new Object[]{c.getSize()}, out);940}941}942}943}944945// Container946static final class java_awt_Container_PersistenceDelegate extends DefaultPersistenceDelegate {947protected void initialize(Class<?> type, Object oldInstance, Object newInstance, Encoder out) {948super.initialize(type, oldInstance, newInstance, out);949// Ignore the children of a JScrollPane.950// Pending(milne) find a better way to do this.951if (oldInstance instanceof javax.swing.JScrollPane) {952return;953}954java.awt.Container oldC = (java.awt.Container)oldInstance;955java.awt.Component[] oldChildren = oldC.getComponents();956java.awt.Container newC = (java.awt.Container)newInstance;957java.awt.Component[] newChildren = (newC == null) ? new java.awt.Component[0] : newC.getComponents();958959BorderLayout layout = ( oldC.getLayout() instanceof BorderLayout )960? ( BorderLayout )oldC.getLayout()961: null;962963JLayeredPane oldLayeredPane = (oldInstance instanceof JLayeredPane)964? (JLayeredPane) oldInstance965: null;966967// Pending. Assume all the new children are unaltered.968for(int i = newChildren.length; i < oldChildren.length; i++) {969Object[] args = ( layout != null )970? new Object[] {oldChildren[i], layout.getConstraints( oldChildren[i] )}971: (oldLayeredPane != null)972? new Object[] {oldChildren[i], oldLayeredPane.getLayer(oldChildren[i]), Integer.valueOf(-1)}973: new Object[] {oldChildren[i]};974975invokeStatement(oldInstance, "add", args, out);976}977}978}979980// Choice981static final class java_awt_Choice_PersistenceDelegate extends DefaultPersistenceDelegate {982protected void initialize(Class<?> type, Object oldInstance, Object newInstance, Encoder out) {983super.initialize(type, oldInstance, newInstance, out);984java.awt.Choice m = (java.awt.Choice)oldInstance;985java.awt.Choice n = (java.awt.Choice)newInstance;986for (int i = n.getItemCount(); i < m.getItemCount(); i++) {987invokeStatement(oldInstance, "add", new Object[]{m.getItem(i)}, out);988}989}990}991992// Menu993static final class java_awt_Menu_PersistenceDelegate extends DefaultPersistenceDelegate {994protected void initialize(Class<?> type, Object oldInstance, Object newInstance, Encoder out) {995super.initialize(type, oldInstance, newInstance, out);996java.awt.Menu m = (java.awt.Menu)oldInstance;997java.awt.Menu n = (java.awt.Menu)newInstance;998for (int i = n.getItemCount(); i < m.getItemCount(); i++) {999invokeStatement(oldInstance, "add", new Object[]{m.getItem(i)}, out);1000}1001}1002}10031004// MenuBar1005static final class java_awt_MenuBar_PersistenceDelegate extends DefaultPersistenceDelegate {1006protected void initialize(Class<?> type, Object oldInstance, Object newInstance, Encoder out) {1007super.initialize(type, oldInstance, newInstance, out);1008java.awt.MenuBar m = (java.awt.MenuBar)oldInstance;1009java.awt.MenuBar n = (java.awt.MenuBar)newInstance;1010for (int i = n.getMenuCount(); i < m.getMenuCount(); i++) {1011invokeStatement(oldInstance, "add", new Object[]{m.getMenu(i)}, out);1012}1013}1014}10151016// List1017static final class java_awt_List_PersistenceDelegate extends DefaultPersistenceDelegate {1018protected void initialize(Class<?> type, Object oldInstance, Object newInstance, Encoder out) {1019super.initialize(type, oldInstance, newInstance, out);1020java.awt.List m = (java.awt.List)oldInstance;1021java.awt.List n = (java.awt.List)newInstance;1022for (int i = n.getItemCount(); i < m.getItemCount(); i++) {1023invokeStatement(oldInstance, "add", new Object[]{m.getItem(i)}, out);1024}1025}1026}102710281029// LayoutManagers10301031// BorderLayout1032static final class java_awt_BorderLayout_PersistenceDelegate extends DefaultPersistenceDelegate {1033private static final String[] CONSTRAINTS = {1034BorderLayout.NORTH,1035BorderLayout.SOUTH,1036BorderLayout.EAST,1037BorderLayout.WEST,1038BorderLayout.CENTER,1039BorderLayout.PAGE_START,1040BorderLayout.PAGE_END,1041BorderLayout.LINE_START,1042BorderLayout.LINE_END,1043};1044@Override1045protected void initialize(Class<?> type, Object oldInstance,1046Object newInstance, Encoder out) {1047super.initialize(type, oldInstance, newInstance, out);1048BorderLayout oldLayout = (BorderLayout) oldInstance;1049BorderLayout newLayout = (BorderLayout) newInstance;1050for (String constraints : CONSTRAINTS) {1051Object oldC = oldLayout.getLayoutComponent(constraints);1052Object newC = newLayout.getLayoutComponent(constraints);1053// Pending, assume any existing elements are OK.1054if (oldC != null && newC == null) {1055invokeStatement(oldInstance, "addLayoutComponent",1056new Object[] { oldC, constraints }, out);1057}1058}1059}1060}10611062// CardLayout1063static final class java_awt_CardLayout_PersistenceDelegate extends DefaultPersistenceDelegate {1064protected void initialize(Class<?> type, Object oldInstance,1065Object newInstance, Encoder out) {1066super.initialize(type, oldInstance, newInstance, out);1067if (getVector(newInstance).isEmpty()) {1068for (Object card : getVector(oldInstance)) {1069Object[] args = {MetaData.getPrivateFieldValue(card, "java.awt.CardLayout$Card.name"),1070MetaData.getPrivateFieldValue(card, "java.awt.CardLayout$Card.comp")};1071invokeStatement(oldInstance, "addLayoutComponent", args, out);1072}1073}1074}1075protected boolean mutatesTo(Object oldInstance, Object newInstance) {1076return super.mutatesTo(oldInstance, newInstance) && getVector(newInstance).isEmpty();1077}1078private static Vector<?> getVector(Object instance) {1079return (Vector<?>) MetaData.getPrivateFieldValue(instance, "java.awt.CardLayout.vector");1080}1081}10821083// GridBagLayout1084static final class java_awt_GridBagLayout_PersistenceDelegate extends DefaultPersistenceDelegate {1085protected void initialize(Class<?> type, Object oldInstance,1086Object newInstance, Encoder out) {1087super.initialize(type, oldInstance, newInstance, out);1088if (getHashtable(newInstance).isEmpty()) {1089for (Map.Entry<?,?> entry : getHashtable(oldInstance).entrySet()) {1090Object[] args = {entry.getKey(), entry.getValue()};1091invokeStatement(oldInstance, "addLayoutComponent", args, out);1092}1093}1094}1095protected boolean mutatesTo(Object oldInstance, Object newInstance) {1096return super.mutatesTo(oldInstance, newInstance) && getHashtable(newInstance).isEmpty();1097}1098private static Hashtable<?,?> getHashtable(Object instance) {1099return (Hashtable<?,?>) MetaData.getPrivateFieldValue(instance, "java.awt.GridBagLayout.comptable");1100}1101}11021103// Swing11041105// JFrame (If we do this for Window instead of JFrame, the setVisible call1106// will be issued before we have added all the children to the JFrame and1107// will appear blank).1108static final class javax_swing_JFrame_PersistenceDelegate extends DefaultPersistenceDelegate {1109protected void initialize(Class<?> type, Object oldInstance, Object newInstance, Encoder out) {1110super.initialize(type, oldInstance, newInstance, out);1111java.awt.Window oldC = (java.awt.Window)oldInstance;1112java.awt.Window newC = (java.awt.Window)newInstance;1113boolean oldV = oldC.isVisible();1114boolean newV = newC.isVisible();1115if (newV != oldV) {1116// false means: don't execute this statement at write time.1117boolean executeStatements = out.executeStatements;1118out.executeStatements = false;1119invokeStatement(oldInstance, "setVisible", new Object[]{Boolean.valueOf(oldV)}, out);1120out.executeStatements = executeStatements;1121}1122}1123}11241125// Models11261127// DefaultListModel1128static final class javax_swing_DefaultListModel_PersistenceDelegate extends DefaultPersistenceDelegate {1129protected void initialize(Class<?> type, Object oldInstance, Object newInstance, Encoder out) {1130// Note, the "size" property will be set here.1131super.initialize(type, oldInstance, newInstance, out);1132javax.swing.DefaultListModel<?> m = (javax.swing.DefaultListModel<?>)oldInstance;1133javax.swing.DefaultListModel<?> n = (javax.swing.DefaultListModel<?>)newInstance;1134for (int i = n.getSize(); i < m.getSize(); i++) {1135invokeStatement(oldInstance, "add", // Can also use "addElement".1136new Object[]{m.getElementAt(i)}, out);1137}1138}1139}11401141// DefaultComboBoxModel1142static final class javax_swing_DefaultComboBoxModel_PersistenceDelegate extends DefaultPersistenceDelegate {1143protected void initialize(Class<?> type, Object oldInstance, Object newInstance, Encoder out) {1144super.initialize(type, oldInstance, newInstance, out);1145javax.swing.DefaultComboBoxModel<?> m = (javax.swing.DefaultComboBoxModel<?>)oldInstance;1146for (int i = 0; i < m.getSize(); i++) {1147invokeStatement(oldInstance, "addElement", new Object[]{m.getElementAt(i)}, out);1148}1149}1150}115111521153// DefaultMutableTreeNode1154static final class javax_swing_tree_DefaultMutableTreeNode_PersistenceDelegate extends DefaultPersistenceDelegate {1155protected void initialize(Class<?> type, Object oldInstance, Object1156newInstance, Encoder out) {1157super.initialize(type, oldInstance, newInstance, out);1158javax.swing.tree.DefaultMutableTreeNode m =1159(javax.swing.tree.DefaultMutableTreeNode)oldInstance;1160javax.swing.tree.DefaultMutableTreeNode n =1161(javax.swing.tree.DefaultMutableTreeNode)newInstance;1162for (int i = n.getChildCount(); i < m.getChildCount(); i++) {1163invokeStatement(oldInstance, "add", new1164Object[]{m.getChildAt(i)}, out);1165}1166}1167}11681169// ToolTipManager1170static final class javax_swing_ToolTipManager_PersistenceDelegate extends PersistenceDelegate {1171protected Expression instantiate(Object oldInstance, Encoder out) {1172return new Expression(oldInstance, javax.swing.ToolTipManager.class,1173"sharedInstance", new Object[]{});1174}1175}11761177// JTabbedPane1178static final class javax_swing_JTabbedPane_PersistenceDelegate extends DefaultPersistenceDelegate {1179protected void initialize(Class<?> type, Object oldInstance, Object newInstance, Encoder out) {1180super.initialize(type, oldInstance, newInstance, out);1181javax.swing.JTabbedPane p = (javax.swing.JTabbedPane)oldInstance;1182for (int i = 0; i < p.getTabCount(); i++) {1183invokeStatement(oldInstance, "addTab",1184new Object[]{1185p.getTitleAt(i),1186p.getIconAt(i),1187p.getComponentAt(i)}, out);1188}1189}1190}11911192// Box1193static final class javax_swing_Box_PersistenceDelegate extends DefaultPersistenceDelegate {1194protected boolean mutatesTo(Object oldInstance, Object newInstance) {1195return super.mutatesTo(oldInstance, newInstance) && getAxis(oldInstance).equals(getAxis(newInstance));1196}11971198protected Expression instantiate(Object oldInstance, Encoder out) {1199return new Expression(oldInstance, oldInstance.getClass(), "new", new Object[] {getAxis(oldInstance)});1200}12011202private Integer getAxis(Object object) {1203Box box = (Box) object;1204return (Integer) MetaData.getPrivateFieldValue(box.getLayout(), "javax.swing.BoxLayout.axis");1205}1206}12071208// JMenu1209// Note that we do not need to state the initialiser for1210// JMenuItems since the getComponents() method defined in1211// Container will return all of the sub menu items that1212// need to be added to the menu item.1213// Not so for JMenu apparently.1214static final class javax_swing_JMenu_PersistenceDelegate extends DefaultPersistenceDelegate {1215protected void initialize(Class<?> type, Object oldInstance, Object newInstance, Encoder out) {1216super.initialize(type, oldInstance, newInstance, out);1217javax.swing.JMenu m = (javax.swing.JMenu)oldInstance;1218java.awt.Component[] c = m.getMenuComponents();1219for (int i = 0; i < c.length; i++) {1220invokeStatement(oldInstance, "add", new Object[]{c[i]}, out);1221}1222}1223}12241225/**1226* The persistence delegate for {@link MatteBorder}.1227* It is impossible to use {@link DefaultPersistenceDelegate}1228* because this class does not have writable properties.1229*1230* @author Sergey A. Malenkov1231*/1232static final class javax_swing_border_MatteBorder_PersistenceDelegate extends PersistenceDelegate {1233protected Expression instantiate(Object oldInstance, Encoder out) {1234MatteBorder border = (MatteBorder) oldInstance;1235Insets insets = border.getBorderInsets();1236Object object = border.getTileIcon();1237if (object == null) {1238object = border.getMatteColor();1239}1240Object[] args = new Object[] {1241insets.top,1242insets.left,1243insets.bottom,1244insets.right,1245object,1246};1247return new Expression(border, border.getClass(), "new", args);1248}1249}12501251/* XXX - doens't seem to work. Debug later.1252static final class javax_swing_JMenu_PersistenceDelegate extends DefaultPersistenceDelegate {1253protected void initialize(Class<?> type, Object oldInstance, Object newInstance, Encoder out) {1254super.initialize(type, oldInstance, newInstance, out);1255javax.swing.JMenu m = (javax.swing.JMenu)oldInstance;1256javax.swing.JMenu n = (javax.swing.JMenu)newInstance;1257for (int i = n.getItemCount(); i < m.getItemCount(); i++) {1258invokeStatement(oldInstance, "add", new Object[]{m.getItem(i)}, out);1259}1260}1261}1262*/12631264/**1265* The persistence delegate for {@link PrintColorUIResource}.1266* It is impossible to use {@link DefaultPersistenceDelegate}1267* because this class has special rule for serialization:1268* it should be converted to {@link ColorUIResource}.1269*1270* @see PrintColorUIResource#writeReplace1271*1272* @author Sergey A. Malenkov1273*/1274static final class sun_swing_PrintColorUIResource_PersistenceDelegate extends PersistenceDelegate {1275protected boolean mutatesTo(Object oldInstance, Object newInstance) {1276return oldInstance.equals(newInstance);1277}12781279protected Expression instantiate(Object oldInstance, Encoder out) {1280Color color = (Color) oldInstance;1281Object[] args = new Object[] {color.getRGB()};1282return new Expression(color, ColorUIResource.class, "new", args);1283}1284}12851286private static final Map<String,Field> fields = Collections.synchronizedMap(new WeakHashMap<String, Field>());1287private static Hashtable<String, PersistenceDelegate> internalPersistenceDelegates = new Hashtable<>();12881289private static PersistenceDelegate nullPersistenceDelegate = new NullPersistenceDelegate();1290private static PersistenceDelegate enumPersistenceDelegate = new EnumPersistenceDelegate();1291private static PersistenceDelegate primitivePersistenceDelegate = new PrimitivePersistenceDelegate();1292private static PersistenceDelegate defaultPersistenceDelegate = new DefaultPersistenceDelegate();1293private static PersistenceDelegate arrayPersistenceDelegate;1294private static PersistenceDelegate proxyPersistenceDelegate;12951296static {12971298internalPersistenceDelegates.put("java.net.URI",1299new PrimitivePersistenceDelegate());13001301// it is possible because MatteBorder is assignable from MatteBorderUIResource1302internalPersistenceDelegates.put("javax.swing.plaf.BorderUIResource$MatteBorderUIResource",1303new javax_swing_border_MatteBorder_PersistenceDelegate());13041305// it is possible because FontUIResource is supported by java_awt_Font_PersistenceDelegate1306internalPersistenceDelegates.put("javax.swing.plaf.FontUIResource",1307new java_awt_Font_PersistenceDelegate());13081309// it is possible because KeyStroke is supported by java_awt_AWTKeyStroke_PersistenceDelegate1310internalPersistenceDelegates.put("javax.swing.KeyStroke",1311new java_awt_AWTKeyStroke_PersistenceDelegate());13121313internalPersistenceDelegates.put("java.sql.Date", new java_util_Date_PersistenceDelegate());1314internalPersistenceDelegates.put("java.sql.Time", new java_util_Date_PersistenceDelegate());13151316internalPersistenceDelegates.put("java.util.JumboEnumSet", new java_util_EnumSet_PersistenceDelegate());1317internalPersistenceDelegates.put("java.util.RegularEnumSet", new java_util_EnumSet_PersistenceDelegate());1318}13191320@SuppressWarnings("rawtypes")1321public synchronized static PersistenceDelegate getPersistenceDelegate(Class type) {1322if (type == null) {1323return nullPersistenceDelegate;1324}1325if (Enum.class.isAssignableFrom(type)) {1326return enumPersistenceDelegate;1327}1328if (null != XMLEncoder.primitiveTypeFor(type)) {1329return primitivePersistenceDelegate;1330}1331// The persistence delegate for arrays is non-trivial; instantiate it lazily.1332if (type.isArray()) {1333if (arrayPersistenceDelegate == null) {1334arrayPersistenceDelegate = new ArrayPersistenceDelegate();1335}1336return arrayPersistenceDelegate;1337}1338// Handle proxies lazily for backward compatibility with 1.2.1339try {1340if (java.lang.reflect.Proxy.isProxyClass(type)) {1341if (proxyPersistenceDelegate == null) {1342proxyPersistenceDelegate = new ProxyPersistenceDelegate();1343}1344return proxyPersistenceDelegate;1345}1346}1347catch(Exception e) {}1348// else if (type.getDeclaringClass() != null) {1349// return new DefaultPersistenceDelegate(new String[]{"this$0"});1350// }13511352String typeName = type.getName();1353PersistenceDelegate pd = (PersistenceDelegate)getBeanAttribute(type, "persistenceDelegate");1354if (pd == null) {1355pd = internalPersistenceDelegates.get(typeName);1356if (pd != null) {1357return pd;1358}1359internalPersistenceDelegates.put(typeName, defaultPersistenceDelegate);1360try {1361String name = type.getName();1362Class c = Class.forName("java.beans.MetaData$" + name.replace('.', '_')1363+ "_PersistenceDelegate");1364pd = (PersistenceDelegate)c.newInstance();1365internalPersistenceDelegates.put(typeName, pd);1366}1367catch (ClassNotFoundException e) {1368String[] properties = getConstructorProperties(type);1369if (properties != null) {1370pd = new DefaultPersistenceDelegate(properties);1371internalPersistenceDelegates.put(typeName, pd);1372}1373}1374catch (Exception e) {1375System.err.println("Internal error: " + e);1376}1377}13781379return (pd != null) ? pd : defaultPersistenceDelegate;1380}13811382private static String[] getConstructorProperties(Class<?> type) {1383String[] names = null;1384int length = 0;1385for (Constructor<?> constructor : type.getConstructors()) {1386String[] value = getAnnotationValue(constructor);1387if ((value != null) && (length < value.length) && isValid(constructor, value)) {1388names = value;1389length = value.length;1390}1391}1392return names;1393}13941395private static String[] getAnnotationValue(Constructor<?> constructor) {1396ConstructorProperties annotation = constructor.getAnnotation(ConstructorProperties.class);1397return (annotation != null)1398? annotation.value()1399: null;1400}14011402private static boolean isValid(Constructor<?> constructor, String[] names) {1403Class[] parameters = constructor.getParameterTypes();1404if (names.length != parameters.length) {1405return false;1406}1407for (String name : names) {1408if (name == null) {1409return false;1410}1411}1412return true;1413}14141415private static Object getBeanAttribute(Class<?> type, String attribute) {1416try {1417return Introspector.getBeanInfo(type).getBeanDescriptor().getValue(attribute);1418} catch (IntrospectionException exception) {1419return null;1420}1421}14221423static Object getPrivateFieldValue(Object instance, String name) {1424Field field = fields.get(name);1425if (field == null) {1426int index = name.lastIndexOf('.');1427final String className = name.substring(0, index);1428final String fieldName = name.substring(1 + index);1429field = AccessController.doPrivileged(new PrivilegedAction<Field>() {1430public Field run() {1431try {1432Field field = Class.forName(className).getDeclaredField(fieldName);1433field.setAccessible(true);1434return field;1435}1436catch (ClassNotFoundException exception) {1437throw new IllegalStateException("Could not find class", exception);1438}1439catch (NoSuchFieldException exception) {1440throw new IllegalStateException("Could not find field", exception);1441}1442}1443});1444fields.put(name, field);1445}1446try {1447return field.get(instance);1448}1449catch (IllegalAccessException exception) {1450throw new IllegalStateException("Could not get value of the field", exception);1451}1452}1453}145414551456