Source for java.beans.DefaultPersistenceDelegate

   1: /* DefaultPersistenceDelegate.java
   2:  Copyright (C) 2005 Free Software Foundation, Inc.
   3: 
   4:  This file is part of GNU Classpath.
   5: 
   6:  GNU Classpath is free software; you can redistribute it and/or modify
   7:  it under the terms of the GNU General Public License as published by
   8:  the Free Software Foundation; either version 2, or (at your option)
   9:  any later version.
  10: 
  11:  GNU Classpath is distributed in the hope that it will be useful, but
  12:  WITHOUT ANY WARRANTY; without even the implied warranty of
  13:  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  14:  General Public License for more details.
  15: 
  16:  You should have received a copy of the GNU General Public License
  17:  along with GNU Classpath; see the file COPYING.  If not, write to the
  18:  Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
  19:  02110-1301 USA.
  20: 
  21:  Linking this library statically or dynamically with other modules is
  22:  making a combined work based on this library.  Thus, the terms and
  23:  conditions of the GNU General Public License cover the whole
  24:  combination.
  25: 
  26:  As a special exception, the copyright holders of this library give you
  27:  permission to link this library with independent modules to produce an
  28:  executable, regardless of the license terms of these independent
  29:  modules, and to copy and distribute the resulting executable under
  30:  terms of your choice, provided that you also meet, for each linked
  31:  independent module, the terms and conditions of the license of that
  32:  module.  An independent module is a module which is not derived from
  33:  or based on this library.  If you modify this library, you may extend
  34:  this exception to your version of the library, but you are not
  35:  obligated to do so.  If you do not wish to do so, delete this
  36:  exception statement from your version. */
  37: 
  38: 
  39: package java.beans;
  40: 
  41: import java.lang.reflect.InvocationTargetException;
  42: import java.lang.reflect.Method;
  43: 
  44: /** <p><code>DefaultPersistenceDelegate</code> is a {@link PersistenceDelegate}
  45:  * implementation that can be used to serialize objects which adhere to the
  46:  * Java Beans naming convention.</p>
  47:  *
  48:  * @author Robert Schuster (robertschuster@fsfe.org)
  49:  * @since 1.4
  50:  */
  51: public class DefaultPersistenceDelegate extends PersistenceDelegate
  52: {
  53: 
  54:   private String[] constructorPropertyNames;
  55: 
  56:   /** Using this constructor the object to be serialized will be instantiated
  57:    * with the default non-argument constructor.
  58:    */
  59:   public DefaultPersistenceDelegate()
  60:   {
  61:   }
  62: 
  63:   /** This constructor allows to specify which Bean properties appear
  64:    * in the constructor.
  65:    *
  66:    * <p>The implementation reads the mentioned properties from the Bean
  67:    * instance and applies it in the given order to a corresponding
  68:    * constructor.</p>
  69:    *
  70:    * @param constructorPropertyNames The properties the Bean's constructor
  71:    * should be given to.
  72:    */
  73:   public DefaultPersistenceDelegate(String[] constructorPropertyNames)
  74:   {
  75:     this.constructorPropertyNames = constructorPropertyNames;
  76:   }
  77: 
  78:   protected boolean mutatesTo(Object oldInstance, Object newInstance)
  79:   {
  80:     try
  81:       {
  82: 
  83:         return (constructorPropertyNames != null
  84:                && constructorPropertyNames.length > 0
  85:                && oldInstance.getClass()
  86:                .getDeclaredMethod("equals",
  87:                                   new Class[] { Object.class }) != null)
  88:                                   ? oldInstance.equals(newInstance)
  89:                                   : super.mutatesTo(oldInstance, newInstance);
  90:       }
  91:     catch (NoSuchMethodException nsme)
  92:       {
  93:         return super.mutatesTo(oldInstance, newInstance);
  94:       }
  95:   }
  96: 
  97:   protected Expression instantiate(Object oldInstance, Encoder out)
  98:   {
  99:     Object[] args = null;
 100: 
 101:     try
 102:       {
 103:         // If there are property names in the array, then we create
 104:         // a corresponding argument array and store every
 105:         // argument in it. To retrieve an argument object we have
 106:         // dig up the right property in the bean class' BeanInfo
 107:         // object.
 108:         // This is so costly in terms of execution time I better
 109:         // not think twice about it ...
 110:         if (constructorPropertyNames != null)
 111:           {
 112:             args = new Object[constructorPropertyNames.length];
 113: 
 114:             // Look up the properties of oldInstance's class to find matches for
 115:             // the
 116:             // names given in the constructor.
 117:             PropertyDescriptor[] propertyDescs = Introspector.getBeanInfo(
 118:                                                                           oldInstance.getClass()).getPropertyDescriptors();
 119: 
 120:             for (int i = 0; i < constructorPropertyNames.length; i++)
 121:               {
 122:                 // Scan the property descriptions for a matching name.
 123:                 for (int j = 0; j < propertyDescs.length; j++)
 124:                   {
 125:                     if (propertyDescs[i].getName().equals(
 126:                                                           constructorPropertyNames[i]))
 127:                       {
 128:                         Method readMethod = propertyDescs[i].getReadMethod();
 129: 
 130:                         args[i] = readMethod.invoke(oldInstance);
 131:                       }
 132:                   }
 133:               }
 134:           }
 135: 
 136:       }
 137:     catch (IllegalAccessException iae)
 138:       {
 139:         out.getExceptionListener().exceptionThrown(iae);
 140:       }
 141:     catch (IllegalArgumentException iarge)
 142:       {
 143:         out.getExceptionListener().exceptionThrown(iarge);
 144:       }
 145:     catch (InvocationTargetException ite)
 146:       {
 147:         out.getExceptionListener().exceptionThrown(ite);
 148:       }
 149:     catch (IntrospectionException ie)
 150:       {
 151:         out.getExceptionListener().exceptionThrown(ie);
 152:       }
 153: 
 154:     return new Expression(oldInstance, oldInstance.getClass(), "new", args);
 155:   }
 156: 
 157:   protected void initialize(Class<?> type, Object oldInstance,
 158:                             Object newInstance, Encoder out)
 159:   {
 160:     // Calling the supertype's implementation of initialize makes it
 161:     // possible that descendants of classes like AbstractHashMap
 162:     // or Hashtable are serialized correctly. This mechanism grounds on
 163:     // two other facts:
 164:     // * Each class which has not registered a special purpose
 165:     //   PersistenceDelegate is handled by a DefaultPersistenceDelegate
 166:     //   instance.
 167:     // * PersistenceDelegate.initialize() is implemented in a way that it
 168:     //   calls the initialize method of the superclass' persistence delegate.
 169:     super.initialize(type, oldInstance, newInstance, out);
 170: 
 171:     // Suppresses the writing of property setting statements when this delegate
 172:     // is not used for the exact instance type. By doing so the following code
 173:     // is called only once per object.
 174:     if (type != oldInstance.getClass())
 175:       return;
 176: 
 177:     try
 178:       {
 179:         PropertyDescriptor[] propertyDescs = Introspector.getBeanInfo(
 180:                                                                       oldInstance.getClass()).getPropertyDescriptors();
 181: 
 182:         for (int i = 0; i < propertyDescs.length; i++)
 183:           {
 184:             Method readMethod = propertyDescs[i].getReadMethod();
 185:             Method writeMethod = propertyDescs[i].getWriteMethod();
 186: 
 187:             if (readMethod != null && writeMethod != null)
 188:               {
 189:                 Object oldValue = readMethod.invoke(oldInstance);
 190: 
 191:                 if (oldValue != null)
 192:                   out.writeStatement(new Statement(oldInstance,
 193:                                                    writeMethod.getName(),
 194:                                                    new Object[] { oldValue }));
 195:               }
 196:           }
 197:       }
 198:     catch (IntrospectionException ie)
 199:       {
 200:         out.getExceptionListener().exceptionThrown(ie);
 201:       }
 202:     catch (IllegalAccessException iae)
 203:       {
 204:         out.getExceptionListener().exceptionThrown(iae);
 205:       }
 206:     catch (InvocationTargetException ite)
 207:       {
 208:         out.getExceptionListener().exceptionThrown(ite);
 209:       }
 210:   }
 211: }