classpath-patches
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[cp-patches] RFC: preview of XMLEncoder


From: Robert Schuster
Subject: [cp-patches] RFC: preview of XMLEncoder
Date: Tue, 22 Nov 2005 15:56:42 +0100
User-agent: Mozilla/5.0 (X11; U; Linux i686; de-AT; rv:1.7.12) Gecko/20051005

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

Hi,
as requested on IRC I put the patch that implements parts of the XMLEncoder on
the list. This code compiles, handles the easier XML serialization situations
but breaks on the more complicated ones (arrays, GUI components).

Furthermore I am not really content with some parts of the encoder's 
architecture.

Please tell me if you want this in anyway.

The ChangeLog:

2005-11-22  Robert Schuster  <address@hidden>

        * java/beans/Statement.java: Doc fixes.
        (doExecute): Workaround for Class.forName call.
        (toString): Made output look more like on the JDK.
        * java/beans/Expression.java: Doc fixes.
        (toString): Made output look more like on the JDK.
        * java/beans/PersistenceDelegate.java,
        java/beans/DefaultPersistenceDelegate.java,
        java/beans/Encoder.java,
        java/beans/XMLEncoder.java: New file.
        * gnu/java/beans/encoder/Action.java,
        gnu/java/beans/encoder/ActionIssuer.java,
        gnu/java/beans/encoder/ArrayInstantiationScannerState.java,
        gnu/java/beans/encoder/ArraySetScannerState.java,
        gnu/java/beans/encoder/ArrayPersistenceDelegate.java,
        gnu/java/beans/encoder/ClassPersistenceDelegate.java,
        gnu/java/beans/encoder/GenericScannerState.java,
        gnu/java/beans/encoder/IgnoringScannerState.java,
        gnu/java/beans/encoder/PrimitivePersistenceDelegate.java,
        gnu/java/beans/encoder/ReportingScannerState.java,
        gnu/java/beans/encoder/ScanEngine.java,
        gnu/java/beans/encoder/ScannerState.java,
        gnu/java/beans/encoder/StAXActionIssuer.java: New file.

cya
Robert
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.1 (GNU/Linux)
Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org

iD8DBQFDgzGqG9cfwmwwEtoRAlRiAJ9q+QTGm9VBizzpoiUjexra3Ni+8QCfVCl5
CLmn2rZAO4rx+JxksktfvG0=
=KOqf
-----END PGP SIGNATURE-----
Index: java/beans/DefaultPersistenceDelegate.java
===================================================================
RCS file: java/beans/DefaultPersistenceDelegate.java
diff -N java/beans/DefaultPersistenceDelegate.java
--- /dev/null   1 Jan 1970 00:00:00 -0000
+++ java/beans/DefaultPersistenceDelegate.java  22 Nov 2005 14:39:49 -0000
@@ -0,0 +1,136 @@
+/* DefaultPersistenceDelegate.java
+ Copyright (C) 2005 Free Software Foundation, Inc.
+
+ This file is part of GNU Classpath.
+
+ GNU Classpath is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ GNU Classpath is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GNU Classpath; see the file COPYING.  If not, write to the
+ Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ 02110-1301 USA.
+
+ Linking this library statically or dynamically with other modules is
+ making a combined work based on this library.  Thus, the terms and
+ conditions of the GNU General Public License cover the whole
+ combination.
+
+ As a special exception, the copyright holders of this library give you
+ permission to link this library with independent modules to produce an
+ executable, regardless of the license terms of these independent
+ modules, and to copy and distribute the resulting executable under
+ terms of your choice, provided that you also meet, for each linked
+ independent module, the terms and conditions of the license of that
+ module.  An independent module is a module which is not derived from
+ or based on this library.  If you modify this library, you may extend
+ this exception to your version of the library, but you are not
+ obligated to do so.  If you do not wish to do so, delete this
+ exception statement from your version. */
+
+
+package java.beans;
+
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+
+public class DefaultPersistenceDelegate extends PersistenceDelegate
+{
+
+  private String[] constructorPropertyNames;
+
+  public DefaultPersistenceDelegate()
+  {
+  }
+
+  public DefaultPersistenceDelegate(String[] constructorPropertyNames)
+  {
+    this.constructorPropertyNames = constructorPropertyNames;
+  }
+
+  protected boolean mutatesTo(Object oldInstance, Object newInstance)
+  {
+    try
+      {
+
+        return (constructorPropertyNames != null
+                && constructorPropertyNames.length > 0
+                && oldInstance.getClass().getDeclaredMethod(
+                  "equals", new Class[] { Object.class }) != null) ?
+                  oldInstance.equals(newInstance)
+                  : super.mutatesTo(oldInstance, newInstance);
+      }
+    catch (NoSuchMethodException nsme)
+      {
+        return super.mutatesTo(oldInstance, newInstance);
+      }
+  }
+
+  protected Expression instantiate(Object oldInstance, Encoder out)
+  {
+    Object[] args = null;
+
+    try
+      {
+        // If there are property names in the array, then we create
+        // a corresponding argument array and store every
+        // argument in it. To retrieve an argument object we have
+        // dig up the right property in the bean class' BeanInfo
+        // object.
+        // This is so costly in terms of execution time I better
+        // not think twice about it ...
+        if (constructorPropertyNames != null)
+          {
+            args = new Object[constructorPropertyNames.length];
+
+            // Look up the properties of oldInstance's class to find matches 
for
+            // the
+            // names given in the constructor.
+            PropertyDescriptor[] propertyDescs = Introspector.getBeanInfo(
+              oldInstance.getClass()).getPropertyDescriptors();
+
+            for (int i = 0; i < constructorPropertyNames.length; i++)
+              {
+                // Scan the property descriptions for a matching name.
+                for (int j = 0; j < propertyDescs.length; j++)
+                  {
+                    if (propertyDescs[i].getName().equals(
+                          constructorPropertyNames[i]))
+                      {
+                        Method readMethod = propertyDescs[i].getReadMethod();
+
+                        args[i] = readMethod.invoke(oldInstance, null);
+                      }
+                  }
+              }
+          }
+
+      }
+    catch (IllegalAccessException iae)
+      {
+        out.getExceptionListener().exceptionThrown(iae);
+      }
+    catch (IllegalArgumentException iarge)
+      {
+        out.getExceptionListener().exceptionThrown(iarge);
+      }
+    catch (InvocationTargetException ite)
+      {
+        out.getExceptionListener().exceptionThrown(ite);
+      }
+    catch (IntrospectionException ie)
+      {
+        out.getExceptionListener().exceptionThrown(ie);
+      }
+
+    return new Expression(oldInstance, oldInstance.getClass(), "new", args);
+  }
+
+}
Index: java/beans/Encoder.java
===================================================================
RCS file: java/beans/Encoder.java
diff -N java/beans/Encoder.java
--- /dev/null   1 Jan 1970 00:00:00 -0000
+++ java/beans/Encoder.java     22 Nov 2005 14:39:49 -0000
@@ -0,0 +1,378 @@
+/* Encoder.java
+ Copyright (C) 2005 Free Software Foundation, Inc.
+
+ This file is part of GNU Classpath.
+
+ GNU Classpath is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ GNU Classpath is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GNU Classpath; see the file COPYING.  If not, write to the
+ Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ 02110-1301 USA.
+
+ Linking this library statically or dynamically with other modules is
+ making a combined work based on this library.  Thus, the terms and
+ conditions of the GNU General Public License cover the whole
+ combination.
+
+ As a special exception, the copyright holders of this library give you
+ permission to link this library with independent modules to produce an
+ executable, regardless of the license terms of these independent
+ modules, and to copy and distribute the resulting executable under
+ terms of your choice, provided that you also meet, for each linked
+ independent module, the terms and conditions of the license of that
+ module.  An independent module is a module which is not derived from
+ or based on this library.  If you modify this library, you may extend
+ this exception to your version of the library, but you are not
+ obligated to do so.  If you do not wish to do so, delete this
+ exception statement from your version. */
+
+
+package java.beans;
+
+import gnu.java.beans.encoder.ArrayPersistenceDelegate;
+import gnu.java.beans.encoder.ClassPersistenceDelegate;
+import gnu.java.beans.encoder.PrimitivePersistenceDelegate;
+
+import java.util.HashMap;
+
+public class Encoder
+{
+
+  /**
+   * An internal DefaultPersistenceDelegate instance that is used for every
+   * class that does not a have a special special PersistenceDelegate.
+   */
+  private static PersistenceDelegate defaultPersistenceDelegate;
+
+  private static PersistenceDelegate fakePersistenceDelegate;
+
+  /**
+   * Stores the relation Class->PersistenceDelegate.
+   */
+  private static HashMap delegates = new HashMap();
+
+  /**
+   * Stores the relation oldInstance->newInstance
+   */
+  private HashMap candidates = new HashMap();
+
+  private ExceptionListener exceptionListener;
+
+  /**
+   * A simple number that is used to restrict the access to writeExpression and
+   * writeStatement. The rule is that both methods should only be used when an
+   * object is written to the stream (= writeObject). Therefore accessCounter 
is
+   * incremented just before the call to writeObject and decremented 
afterwards.
+   * Then writeStatement and writeExpression allow execution only if
+   * accessCounter is bigger than zero.
+   */
+  private int accessCounter = 0;
+
+  public Encoder()
+  {
+    setupDefaultPersistenceDelegates();
+
+    setExceptionListener(null);
+  }
+
+  /**
+   * Sets up a bunch of address@hidden PersistenceDelegate} instances which 
are needed
+   * for the basic working of a address@hidden Encoder}s.
+   */
+  private static void setupDefaultPersistenceDelegates()
+  {
+    synchronized (delegates)
+      {
+        if (defaultPersistenceDelegate != null)
+          return;
+
+        delegates.put(Class.class, new ClassPersistenceDelegate());
+
+        PersistenceDelegate pd = new PrimitivePersistenceDelegate();
+        delegates.put(Boolean.class, pd);
+        delegates.put(Byte.class, pd);
+        delegates.put(Short.class, pd);
+        delegates.put(Integer.class, pd);
+        delegates.put(Long.class, pd);
+        delegates.put(Float.class, pd);
+        delegates.put(Double.class, pd);
+
+        delegates.put(Object[].class, new ArrayPersistenceDelegate());
+
+        defaultPersistenceDelegate = new DefaultPersistenceDelegate();
+        delegates.put(Object.class, defaultPersistenceDelegate);
+
+        // Creates a PersistenceDelegate implementation which is
+        // returned for 'null'. In practice this instance is
+        // not used in any way and is just here to be compatible
+        // with the reference implementation which returns a
+        // similar instance when calling getPersistenceDelegate(null) .
+        fakePersistenceDelegate = new PersistenceDelegate()
+        {
+          protected Expression instantiate(Object o, Encoder e)
+          {
+            return null;
+          }
+        };
+
+      }
+  }
+
+  protected void writeObject(Object o)
+  {
+    // 'null' has no PersistenceDelegate and will not
+    // create an Expression which has to be cloned.
+    // However subclasses should be aware that writeObject
+    // may be called with a 'null' argument and should
+    // write the proper representation of it.
+    if (o == null)
+      return;
+
+    PersistenceDelegate pd = getPersistenceDelegate(o.getClass());
+
+    accessCounter++;
+    pd.writeObject(o, this);
+    accessCounter--;
+  }
+
+  /**
+   * Sets the address@hidden ExceptionListener} instance to be used for 
reporting
+   * recorable exceptions in the instantiation and initialization sequence. If
+   * the argument is <code>null</code> a default instance will be used that
+   * prints the thrown exception to <code>System.err</code>.
+   */
+  public void setExceptionListener(ExceptionListener listener)
+  {
+    exceptionListener = (listener != null) ? listener : new ExceptionListener()
+    {
+      public void exceptionThrown(Exception e)
+      {
+        System.err.println("exception thrown: " + e);
+        e.printStackTrace();
+      }
+    };
+  }
+
+  /**
+   * Returns the currently active address@hidden ExceptionListener} instance.
+   */
+  public ExceptionListener getExceptionListener()
+  {
+    return exceptionListener;
+  }
+
+  public PersistenceDelegate getPersistenceDelegate(Class type)
+  {
+    // This is not specified but the JDK behaves like this.
+    if (type == null)
+      return fakePersistenceDelegate;
+
+    // Treats all array classes in the same way and assigns
+    // them a shared PersistenceDelegate implementation tailored
+    // for array instantation and initialization.
+    if (type.isArray())
+      return (PersistenceDelegate) delegates.get(Object[].class);
+
+    PersistenceDelegate pd = (PersistenceDelegate) delegates.get(type);
+
+    return (pd != null) ? pd : (PersistenceDelegate) 
defaultPersistenceDelegate;
+  }
+
+  /**
+   * Sets the address@hidden PersistenceDelegate} instance for the given class.
+   * <p>
+   * Note: Throws a <code>NullPointerException</code> if the argument is
+   * <code>null</code>.
+   * </p>
+   * <p>
+   * Note: Silently ignores PersistenceDelegates for Array types and primitive
+   * wrapper classes.
+   * </p>
+   * <p>
+   * Note: Although this method is not declared <code>static</code> changes to
+   * the address@hidden PersistenceDelegate}s affect <strong>all</strong>
+   * address@hidden Encoder} instances. <strong>In this 
implementation</strong> the
+   * access is thread safe.
+   * </p>
+   */
+  public void setPersistenceDelegate(Class type, PersistenceDelegate delegate)
+  {
+    // If the argument is null this will cause a NullPointerException
+    // which is expected behavior.
+
+    // This makes custom PDs for array and primitive types impossible but
+    // this is how the JDK behaves.
+    if (type.isArray() || type.isPrimitive())
+      return;
+
+    synchronized (delegates)
+      {
+        delegates.put(type, delegate);
+      }
+
+  }
+
+  public Object remove(Object oldInstance)
+  {
+    return candidates.remove(oldInstance);
+  }
+
+  /**
+   * Returns the replacement object which has been created by the encoder 
during
+   * the instantiation sequence or <code>null</code> if the object has not
+   * been processed yet.
+   * <p>
+   * Note: The <code>String</code> class acts as an endpoint for the
+   * inherently recursive algorithm of the address@hidden Encoder}. Therefore 
instances
+   * of <code>String</code> will always be returned by this method. In other
+   * words the assertion: <code>
+   * assert ( anyEncoder.get(anyString) == anyString )
+   * </code<
+   * will always hold.</p>
+   *
+   * <p>Note: If <code>null</code> is requested, the result will
+   * always be <code>null</code>.</p>
+   */
+  public Object get(Object oldInstance)
+  {
+    // String instances are handled in a special way.
+    // No one knows why this is not officially specified
+    // because this is a rather important design decision.
+    return (oldInstance == null) ? null : 
+             (oldInstance.getClass() == String.class) ?
+               oldInstance : candidates.get(oldInstance);
+  }
+
+  /**
+   * <p>
+   * Note: If you call this method not from within an object instantiation and
+   * initialization sequence it will be silently ignored.
+   * </p>
+   */
+  public void writeStatement(Statement stmt)
+  {
+    // Silently ignore out of bound calls.
+    if (accessCounter <= 0)
+      return;
+
+    Object target = stmt.getTarget();
+
+    Object newTarget = get(target);
+    if (newTarget == null)
+      {
+        writeObject(target);
+        newTarget = get(target);
+      }
+
+    Object[] args = stmt.getArguments();
+    Object[] newArgs = new Object[args.length];
+
+    for (int i = 0; i < args.length; i++)
+      {
+        if ((newArgs[i] = get(args[i])) == null)
+          {
+            writeObject(args[i]);
+            newArgs[i] = get(args[i]);
+          }
+      }
+
+    Statement newStmt = new Statement(newTarget, stmt.getMethodName(), 
newArgs);
+
+    try
+      {
+        newStmt.execute();
+      }
+    catch (Exception e)
+      {
+        exceptionListener.exceptionThrown(e);
+      }
+
+  }
+
+  /**
+   * <p>
+   * Note: If you call this method not from within an object instantiation and
+   * initialization sequence it will be silently ignored.
+   * </p>
+   */
+  public void writeExpression(Expression expr)
+  {
+    // Silently ignore out of bound calls.
+    if (accessCounter <= 0)
+      return;
+
+    Object target = expr.getTarget();
+    Object value = null;
+
+    try
+      {
+        value = expr.getValue();
+      }
+    catch (Exception e)
+      {
+        exceptionListener.exceptionThrown(e);
+        return;
+      }
+
+    if (get(value) == null)
+      {
+        Object newTarget = get(target);
+        if (newTarget == null)
+          {
+            writeObject(target);
+            newTarget = get(target);
+
+            // May happen if exception was thrown.
+            if (newTarget == null)
+              {
+                return;
+              }
+          }
+
+        Object[] args = expr.getArguments();
+        Object[] newArgs = new Object[args.length];
+
+        for (int i = 0; i < args.length; i++)
+          {
+            if ((newArgs[i] = get(args[i])) == null)
+              {
+                writeObject(args[i]);
+                newArgs[i] = get(args[i]);
+              }
+          }
+
+        Expression newExpr = new Expression(newTarget, expr.getMethodName(),
+                                            newArgs);
+        
+        // actually instantiates the new object
+        try
+          {
+            Object newValue = newExpr.getValue();
+
+            candidates.put(value, newValue);
+          }
+        catch (Exception e)
+          {
+            exceptionListener.exceptionThrown(e);
+            return;
+          }
+        writeObject(value);
+
+      }
+    else
+      {
+        writeObject(target);
+      }
+
+  }
+
+}
Index: java/beans/Expression.java
===================================================================
RCS file: /cvsroot/classpath/classpath/java/beans/Expression.java,v
retrieving revision 1.3
diff -u -r1.3 Expression.java
--- java/beans/Expression.java  30 Aug 2005 01:30:00 -0000      1.3
+++ java/beans/Expression.java  22 Nov 2005 14:39:49 -0000
@@ -35,16 +35,13 @@
 obligated to do so.  If you do not wish to do so, delete this
 exception statement from your version. */
 
-
 package java.beans;
 
 /**
- * class Expression
- *
- * An Expression captures the execution of an object method that
- * returns a value.  It stores an object, the method to call, and the
+ * class Expression An Expression captures the execution of an object method
+ * that returns a value. It stores an object, the method to call, and the
  * arguments to pass to the method.
- *
+ * 
  * @since 1.4
  */
 public class Expression extends Statement
@@ -53,38 +50,40 @@
   // yet;
   private static final Object UNSET = new Object();
 
-  // The value to return.  This is equal to unset until getValue is called.
+  // The value to return. This is equal to unset until getValue is called.
   private Object value;
-   
 
   /**
-   * Constructor
-   *
-   * Constructs an Expression representing the invocation of
-   * object.methodName(arg[0], arg[1], ...);  However, it will never
-   * be executed.  Instead, value will always be returned.
-   *
-   * @param value The value to return.
-   * @param target The object to invoke the method on.
-   * @param methodName The object method to invoke.
-   * @param arguments An array of arguments to pass to the method.
+   * Constructor Constructs an Expression representing the invocation of
+   * object.methodName(arg[0], arg[1], ...); However, it will never be 
executed.
+   * Instead, value will always be returned.
+   * 
+   * @param value
+   *          The value to return.
+   * @param target
+   *          The object to invoke the method on.
+   * @param methodName
+   *          The object method to invoke.
+   * @param arguments
+   *          An array of arguments to pass to the method.
    */
   public Expression(Object value, Object target, String methodName,
-                   Object[] arguments)
+                    Object[] arguments)
   {
     super(target, methodName, arguments);
     this.value = value;
   }
 
   /**
-   * Constructor
-   *
-   * Constructs an Expression representing the invocation of
+   * Constructor Constructs an Expression representing the invocation of
    * object.methodName(arg[0], arg[1], ...);
-   *
-   * @param target The object to invoke the method on.
-   * @param methodName The object method to invoke.
-   * @param arguments An array of arguments to pass to the method.
+   * 
+   * @param target
+   *          The object to invoke the method on.
+   * @param methodName
+   *          The object method to invoke.
+   * @param arguments
+   *          An array of arguments to pass to the method.
    */
   public Expression(Object target, String methodName, Object[] arguments)
   {
@@ -93,15 +92,14 @@
   }
 
   /**
-   * Return the result of executing the method.
-   *
-   * If the cached value has not yet been set, the method is
-   * executed in the same way as Statement.execute(), except that
-   * the value is cached, and then returned.  If the value has been
+   * Return the result of executing the method. If the cached value has not yet
+   * been set, the method is executed in the same way as Statement.execute(),
+   * except that the value is cached, and then returned. If the value has been
    * set, it is returned without executing the method again.
-   *
+   * 
    * @return the result of executing the method.
-   * @exception Exception if an error occurs
+   * @exception Exception
+   *              if an error occurs
    */
   public Object getValue() throws Exception
   {
@@ -112,14 +110,15 @@
 
   /**
    * Set the cached value to be returned by getValue()
-   *
-   * @param value the value to cache and return.
+   * 
+   * @param value
+   *          the value to cache and return.
    */
   public void setValue(Object value)
   {
     this.value = value;
   }
-    
+
   /**
    * Return a string representation of this expression.
    */
@@ -127,7 +126,7 @@
   {
     String result = super.toString();
     if (value != UNSET)
-      return value.getClass().getName() + " " + result;
+      return value.getClass().getName() + "=" + result;
     return result;
   }
 }
Index: java/beans/PersistenceDelegate.java
===================================================================
RCS file: java/beans/PersistenceDelegate.java
diff -N java/beans/PersistenceDelegate.java
--- /dev/null   1 Jan 1970 00:00:00 -0000
+++ java/beans/PersistenceDelegate.java 22 Nov 2005 14:39:49 -0000
@@ -0,0 +1,79 @@
+/* java.beans.Expression
+   Copyright (C) 2005 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+ 
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING.  If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version. */
+
+package java.beans;
+
+public abstract class PersistenceDelegate
+{
+
+  protected void initialize(Class type, Object oldInstance, Object newInstance,
+                            Encoder out)
+  {
+    if (type != Object.class)
+      {
+        type = type.getSuperclass();
+
+        PersistenceDelegate pd = out.getPersistenceDelegate(
+          oldInstance.getClass().getSuperclass());
+
+        pd.initialize(type, oldInstance, newInstance, out);
+      }
+  }
+
+  public void writeObject(Object oldInstance, Encoder out)
+  {
+    Object streamCandidate = out.get(oldInstance);
+
+    if (mutatesTo(oldInstance, streamCandidate))
+      {
+        initialize(oldInstance.getClass(), oldInstance, streamCandidate, out);
+      }
+    else
+      {
+        out.remove(oldInstance);
+        out.writeExpression(instantiate(oldInstance, out));
+      }
+  }
+
+  protected boolean mutatesTo(Object oldInstance, Object newInstance)
+  {
+    return (newInstance != null)
+           && oldInstance.getClass() == newInstance.getClass();
+  }
+
+  protected abstract Expression instantiate(Object oldInstance, Encoder out);
+}
Index: java/beans/Statement.java
===================================================================
RCS file: /cvsroot/classpath/classpath/java/beans/Statement.java,v
retrieving revision 1.3
diff -u -r1.3 Statement.java
--- java/beans/Statement.java   30 Aug 2005 01:30:00 -0000      1.3
+++ java/beans/Statement.java   22 Nov 2005 14:39:50 -0000
@@ -1,4 +1,4 @@
-/* java.beans.Statement
+/* Statement.java
    Copyright (C) 2004, 2005 Free Software Foundation, Inc.
 
 This file is part of GNU Classpath.
@@ -48,11 +48,13 @@
 /**
  * class Statement
  *
- * A Statement captures the execution of an object method.  It stores
+ * <p>A Statement captures the execution of an object method.  It stores
  * the object, the method to call, and the arguments to the method and
  * provides the ability to execute the method on the object, using the
- * provided arguments.
+ * provided arguments.</p>
  *
+ * @author Jerry Quinn (address@hidden)
+ * @author Robert Schuster (address@hidden)
  * @since 1.4
  */
 public class Statement
@@ -66,8 +68,10 @@
   private String methodName;
   private Object[] arguments;
 
-  // One or the other of these will get a value after execute is
-  // called once, but not both.
+  /**
+   * One or the other of these will get a value after execute is
+   * called once, but not both.
+   */
   private transient Method method;
   private transient Constructor ctor;
 
@@ -91,7 +95,7 @@
   }
 
   /** Creates a name for the target instance or does nothing if the object's
-   * name is already known. This makes sure that there *is* a name for every
+   * name is already known. This makes sure that there exists a name for every
    * target instance.
    */
   private static synchronized void storeTargetName(Object obj)
@@ -126,37 +130,39 @@
   /**
    * Execute the statement.
    *
-   * Finds the specified method in the target object and calls it with
-   * the arguments given in the constructor.
+   * <p>Finds the specified method in the target object and calls it with
+   * the arguments given in the constructor.</p>
    *
-   * The most specific method according to the JLS(15.11) is used when
-   * there are multiple methods with the same name.
+   * <p>The most specific method according to the JLS(15.11) is used when
+   * there are multiple methods with the same name.</p>
    *
-   * Execute performs some special handling for methods and
+   * <p>Execute performs some special handling for methods and
    * parameters:
+   * <ul>
+   * <li>Static methods can be executed by providing the class as a
+   * target.</li>
    *
-   * Static methods can be executed by providing the class as a
-   * target.
-   *
-   * The method name new is reserved to call the constructor 
+   * <li>The method name new is reserved to call the constructor 
    * new() will construct an object and return it.  Not useful unless
-   * an expression :-)
+   * an expression :-)</li>
    *
-   * If the target is an array, get and set as defined in
+   * <li>If the target is an array, get and set as defined in
    * java.util.List are recognized as valid methods and mapped to the
-   * methods of the same name in java.lang.reflect.Array.
+   * methods of the same name in java.lang.reflect.Array.</li>
    *
-   * The native datatype wrappers Boolean, Byte, Character, Double,
+   * <li>The native datatype wrappers Boolean, Byte, Character, Double,
    * Float, Integer, Long, and Short will map to methods that have
    * native datatypes as parameters, in the same way as Method.invoke.
    * However, these wrappers also select methods that actually take
-   * the wrapper type as an argument.
+   * the wrapper type as an argument.</li>
+   * </ul>
+   * </p>
    *
-   * The Sun spec doesn't deal with overloading between int and
+   * <p>The Sun spec doesn't deal with overloading between int and
    * Integer carefully.  If there are two methods, one that takes an
    * Integer and the other taking an int, the method chosen is not
    * specified, and can depend on the order in which the methods are
-   * declared in the source file.
+   * declared in the source file.</p>
    *
    * @throws Exception if an exception occurs while locating or
    *                  invoking the method.
@@ -178,8 +184,10 @@
       Integer.TYPE, Long.TYPE, Short.TYPE
     };
 
-  // Given a wrapper class, return the native class for it.  For
-  // example, if c is Integer, Integer.TYPE is returned.
+  /** Given a wrapper class, return the native class for it.
+   * <p>For example, if <code>c</code> is <code>Integer</code>, 
+   * <code>Integer.TYPE</code> is returned.</p>
+   */
   private Class unwrap(Class c)
   {
     for (int i = 0; i < wrappers.length; i++)
@@ -188,8 +196,11 @@
     return null;
   }
 
-  // Return true if all args can be assigned to params, false
-  // otherwise.  Arrays are guaranteed to be the same length.
+  /** Returns <code>true</code> if all args can be assigned to
+   * <code>params</code>, <code>false</code> otherwise.
+   *
+   * <p>Arrays are guaranteed to be the same length.</p>
+   */
   private boolean compatible(Class[] params, Class[] args)
   {
     for (int i = 0; i < params.length; i++)
@@ -208,14 +219,15 @@
   }
 
   /**
-   * Return true if the method arguments in first are more specific
-   * than the method arguments in second, i.e. all args in first can
-   * be assigned to those in second.
+   * Returns <code>true</code> if the method arguments in first are
+   * more specific than the method arguments in second, i.e. all
+   * arguments in <code>first</code> can be assigned to those in
+   * <code>second</code>.
    *
-   * A method is more specific if all parameters can also be fed to
+   * <p>A method is more specific if all parameters can also be fed to
    * the less specific method, because, e.g. the less specific method
    * accepts a base class of the equivalent argument for the more
-   * specific one.
+   * specific one.</p>
    *
    * @param first a <code>Class[]</code> value
    * @param second a <code>Class[]</code> value
@@ -333,6 +345,19 @@
       }
     if (method == null)
       throw new NoSuchMethodException("No matching method for statement " + 
toString());
+
+    // If we were calling Class.forName(String) we intercept and call the
+    // forName-variant that allows a ClassLoader argument. We take the
+    // system classloader (aka application classloader) here to make sure
+    // that application defined classes can be resolved. If we would not
+    // do that the Class.forName implementation would use the class loader
+    // of java.beans.Statement which is <null> and cannot resolve application
+    // defined classes.
+    if ( method.equals(
+           Class.class.getMethod("forName", new Class[] { String.class })) )
+      return Class.forName(
+               (String) args[0], true, ClassLoader.getSystemClassLoader());
+
     return method.invoke(target, args);
   }
 
@@ -363,11 +388,15 @@
     for (int i = 0; i < arguments.length; i++)
       {
         result.append(sep);
-        result.append(arguments[i].getClass().getName());
+        result.append(
+          ( arguments[i] == null ) ? "null" : 
+            ( arguments[i] instanceof String ) ? "\"" + arguments[i] + "\"" :
+            arguments[i].getClass().getName());
         sep = ", ";
       }
     result.append(")");
 
     return result.toString();
   }
+  
 }
Index: java/beans/XMLEncoder.java
===================================================================
RCS file: java/beans/XMLEncoder.java
diff -N java/beans/XMLEncoder.java
--- /dev/null   1 Jan 1970 00:00:00 -0000
+++ java/beans/XMLEncoder.java  22 Nov 2005 14:39:50 -0000
@@ -0,0 +1,129 @@
+/* XMLEncoder.java
+   Copyright (C) 2004, 2005 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+ 
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING.  If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+
+package java.beans;
+
+import gnu.java.beans.encoder.ActionIssuer;
+import gnu.java.beans.encoder.ScanEngine;
+import gnu.java.beans.encoder.StAXActionIssuer;
+
+import java.io.OutputStream;
+
+import java.lang.reflect.Array;
+
+import javax.xml.stream.XMLOutputFactory;
+import javax.xml.stream.XMLStreamException;
+import javax.xml.stream.XMLStreamWriter;
+
+public class XMLEncoder extends Encoder
+{
+  Object owner;
+
+  Exception exception;
+
+  boolean skip = false;
+
+  ScanEngine scanEngine;
+
+  ActionIssuer ai;
+
+  public XMLEncoder(OutputStream os)
+  {
+    ai = new StAXActionIssuer(os);
+
+    ai.issuePreamble();
+    ai.issue("java", new String[] { "version", "class" },
+             new String[] { System.getProperty("java.version"),
+                           getClass().getName() });
+
+    scanEngine = new ScanEngine(ai);
+  }
+
+  public void close()
+  {
+    if (ai != null)
+      {
+        ai.issueEnd();
+        ai.flush();
+        ai.close();
+        ai = null;
+      }
+  }
+
+  public void flush()
+  {
+    ai.flush();
+  }
+
+  public void writeExpression(Expression expr)
+  {
+    scanEngine.writeExpression(expr);
+
+    super.writeExpression(expr);
+
+    scanEngine.end();
+  }
+
+  public void writeStatement(Statement stmt)
+  {
+    scanEngine.writeStatement(stmt);
+
+    super.writeStatement(stmt);
+
+    scanEngine.end();
+  }
+
+  public void writeObject(Object o)
+  {
+    scanEngine.writeObject(o);
+
+    super.writeObject(o);
+  }
+
+  public void setOwner(Object o)
+  {
+    owner = o;
+  }
+
+  public Object getOwner()
+  {
+    return owner;
+  }
+
+}
Index: gnu/java/beans/encoder/ActionIssuer.java
===================================================================
RCS file: gnu/java/beans/encoder/ActionIssuer.java
diff -N gnu/java/beans/encoder/ActionIssuer.java
--- /dev/null   1 Jan 1970 00:00:00 -0000
+++ gnu/java/beans/encoder/ActionIssuer.java    22 Nov 2005 14:39:50 -0000
@@ -0,0 +1,62 @@
+/* ActionIssuer.java -- FIXME: briefly describe file purpose
+ Copyright (C) 2005 Free Software Foundation, Inc.
+
+ This file is part of GNU Classpath.
+
+ GNU Classpath is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ GNU Classpath is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GNU Classpath; see the file COPYING.  If not, write to the
+ Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ 02110-1301 USA.
+
+ Linking this library statically or dynamically with other modules is
+ making a combined work based on this library.  Thus, the terms and
+ conditions of the GNU General Public License cover the whole
+ combination.
+
+ As a special exception, the copyright holders of this library give you
+ permission to link this library with independent modules to produce an
+ executable, regardless of the license terms of these independent
+ modules, and to copy and distribute the resulting executable under
+ terms of your choice, provided that you also meet, for each linked
+ independent module, the terms and conditions of the license of that
+ module.  An independent module is a module which is not derived from
+ or based on this library.  If you modify this library, you may extend
+ this exception to your version of the library, but you are not
+ obligated to do so.  If you do not wish to do so, delete this
+ exception statement from your version. */
+
+
+package gnu.java.beans.encoder;
+
+public interface ActionIssuer
+{
+
+  void issuePreamble();
+
+  void issueEnd();
+
+  void issue(String tagName);
+
+  void issue(String tagName, String value);
+
+  void issue(String tagName, String attributeName, String attributeValue);
+
+  void issue(String tagName, String value, String[] attributeNames,
+             String[] attributeValues);
+
+  void issue(String tagName, String[] attributeNames, String[] 
attributeValues);
+
+  void flush();
+
+  void close();
+}
Index: gnu/java/beans/encoder/Action.java
===================================================================
RCS file: gnu/java/beans/encoder/Action.java
diff -N gnu/java/beans/encoder/Action.java
--- /dev/null   1 Jan 1970 00:00:00 -0000
+++ gnu/java/beans/encoder/Action.java  22 Nov 2005 14:39:50 -0000
@@ -0,0 +1,44 @@
+/* Action.java
+   Copyright (C) 2005 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING.  If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package gnu.java.beans.encoder;
+
+public interface Action
+{
+
+}
Index: gnu/java/beans/encoder/ArrayInstantiationScannerState.java
===================================================================
RCS file: gnu/java/beans/encoder/ArrayInstantiationScannerState.java
diff -N gnu/java/beans/encoder/ArrayInstantiationScannerState.java
--- /dev/null   1 Jan 1970 00:00:00 -0000
+++ gnu/java/beans/encoder/ArrayInstantiationScannerState.java  22 Nov 2005 
14:39:50 -0000
@@ -0,0 +1,113 @@
+/* ArrayInstantiationScannerState.java
+ Copyright (C) 2005 Free Software Foundation, Inc.
+
+ This file is part of GNU Classpath.
+
+ GNU Classpath is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ GNU Classpath is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GNU Classpath; see the file COPYING.  If not, write to the
+ Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ 02110-1301 USA.
+
+ Linking this library statically or dynamically with other modules is
+ making a combined work based on this library.  Thus, the terms and
+ conditions of the GNU General Public License cover the whole
+ combination.
+
+ As a special exception, the copyright holders of this library give you
+ permission to link this library with independent modules to produce an
+ executable, regardless of the license terms of these independent
+ modules, and to copy and distribute the resulting executable under
+ terms of your choice, provided that you also meet, for each linked
+ independent module, the terms and conditions of the license of that
+ module.  An independent module is a module which is not derived from
+ or based on this library.  If you modify this library, you may extend
+ this exception to your version of the library, but you are not
+ obligated to do so.  If you do not wish to do so, delete this
+ exception statement from your version. */
+
+
+package gnu.java.beans.encoder;
+
+class ArrayInstantiationScannerState extends ScannerState
+{
+
+  void methodInvocation(String methodName)
+  {
+    throw new InternalError("You are not supposed to be here.");
+  }
+
+  void staticMethodInvocation(String className, String methodName)
+  {
+    throw new InternalError("You are not supposed to be here.");
+  }
+
+  void staticFieldAccess(String className, String fieldName)
+  {
+    throw new InternalError("You are not supposed to be here.");
+  }
+
+  void classResolution(String className)
+  {
+    throw new InternalError("You are not supposed to be here.");
+  }
+
+  void objectInstantiation(String className)
+  {
+    throw new InternalError("You are not supposed to be here.");
+  }
+
+  void primitiveInstantiation(String primitiveName, String valueAsString)
+  {
+    throw new InternalError("You are not supposed to be here.");
+  }
+
+  void arrayInstantiation(String arrayClassName, String lengthAsString)
+  {
+    getActionIssuer().issue("array", new String[] { "class", "length"} , new 
String[] { arrayClassName, lengthAsString });
+  }
+
+  void arraySet(String indexAsString)
+  {
+    throw new InternalError("You are not supposed to be here.");
+  }
+
+  void arrayGet(String indexAsString)
+  {
+    throw new InternalError("You are not supposed to be here.");
+  }
+
+  void listGet()
+  {
+    throw new InternalError("You are not supposed to be here.");
+  }
+
+  void listSet()
+  {
+    throw new InternalError("You are not supposed to be here.");
+  }
+
+  void nullObject()
+  {
+    throw new InternalError("You are not supposed to be here.");
+  }
+
+  void stringReference(String string)
+  {
+    throw new InternalError("You are not supposed to be here.");
+  }
+  
+  void childEnded(ScannerState child)
+  {
+  }
+  
+}
Index: gnu/java/beans/encoder/ArrayPersistenceDelegate.java
===================================================================
RCS file: gnu/java/beans/encoder/ArrayPersistenceDelegate.java
diff -N gnu/java/beans/encoder/ArrayPersistenceDelegate.java
--- /dev/null   1 Jan 1970 00:00:00 -0000
+++ gnu/java/beans/encoder/ArrayPersistenceDelegate.java        22 Nov 2005 
14:39:50 -0000
@@ -0,0 +1,104 @@
+/* ArrayPersistenceDelegate.java
+ Copyright (C) 2005 Free Software Foundation, Inc.
+
+ This file is part of GNU Classpath.
+
+ GNU Classpath is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+ 
+ GNU Classpath is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GNU Classpath; see the file COPYING.  If not, write to the
+ Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ 02110-1301 USA.
+
+ Linking this library statically or dynamically with other modules is
+ making a combined work based on this library.  Thus, the terms and
+ conditions of the GNU General Public License cover the whole
+ combination.
+
+ As a special exception, the copyright holders of this library give you
+ permission to link this library with independent modules to produce an
+ executable, regardless of the license terms of these independent
+ modules, and to copy and distribute the resulting executable under
+ terms of your choice, provided that you also meet, for each linked
+ independent module, the terms and conditions of the license of that
+ module.  An independent module is a module which is not derived from
+ or based on this library.  If you modify this library, you may extend
+ this exception to your version of the library, but you are not
+ obligated to do so.  If you do not wish to do so, delete this
+ exception statement from your version. */
+
+
+package gnu.java.beans.encoder;
+
+import java.beans.Encoder;
+import java.beans.Expression;
+import java.beans.PersistenceDelegate;
+import java.beans.Statement;
+
+import java.lang.reflect.Array;
+
+public class ArrayPersistenceDelegate extends PersistenceDelegate
+{
+
+  protected Expression instantiate(Object oldInstance, Encoder out)
+  {
+    Class type = oldInstance.getClass().getComponentType();
+
+    // oldInstance is expected to be an array, then
+    // getClass().getComponentType() should lead
+    // to its component type.
+    assert (type != null);
+
+    if (type == Boolean.TYPE)
+      type = Boolean.class;
+    else if (type == Byte.TYPE)
+      type = Byte.class;
+    else if (type == Short.TYPE)
+      type = Short.class;
+    else if (type == Integer.TYPE)
+      type = Integer.class;
+    else if (type == Long.TYPE)
+      type = Long.class;
+    else if (type == Float.TYPE)
+      type = Float.class;
+    else if (type == Double.TYPE)
+      type = Double.class;
+
+    return new Expression(
+                          oldInstance,
+                          Array.class,
+                          "newInstance",
+                          new Object[] {
+                                        type,
+                                        new Integer(
+                                                    
Array.getLength(oldInstance)) });
+  }
+
+  protected void initialize(Class type, Object oldInstance, Object newInstance,
+                            Encoder out)
+  {
+    int length = Array.getLength(oldInstance);
+
+    for (int i = 0; i < length; i++)
+      {
+        Object oldValue = Array.get(oldInstance, i);
+
+        if (oldValue != null)
+          out.writeStatement(new Statement(Array.class, "set",
+                                           new Object[] { oldInstance,
+                                                         new Integer(i),
+                                                         oldValue }));
+
+      }
+
+  }
+
+}
Index: gnu/java/beans/encoder/ArraySetScannerState.java
===================================================================
RCS file: gnu/java/beans/encoder/ArraySetScannerState.java
diff -N gnu/java/beans/encoder/ArraySetScannerState.java
--- /dev/null   1 Jan 1970 00:00:00 -0000
+++ gnu/java/beans/encoder/ArraySetScannerState.java    22 Nov 2005 14:39:50 
-0000
@@ -0,0 +1,115 @@
+/* ArraySetScannerState.java
+ Copyright (C) 2005 Free Software Foundation, Inc.
+
+ This file is part of GNU Classpath.
+
+ GNU Classpath is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ GNU Classpath is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GNU Classpath; see the file COPYING.  If not, write to the
+ Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ 02110-1301 USA.
+
+ Linking this library statically or dynamically with other modules is
+ making a combined work based on this library.  Thus, the terms and
+ conditions of the GNU General Public License cover the whole
+ combination.
+
+ As a special exception, the copyright holders of this library give you
+ permission to link this library with independent modules to produce an
+ executable, regardless of the license terms of these independent
+ modules, and to copy and distribute the resulting executable under
+ terms of your choice, provided that you also meet, for each linked
+ independent module, the terms and conditions of the license of that
+ module.  An independent module is a module which is not derived from
+ or based on this library.  If you modify this library, you may extend
+ this exception to your version of the library, but you are not
+ obligated to do so.  If you do not wish to do so, delete this
+ exception statement from your version. */
+
+
+package gnu.java.beans.encoder;
+
+class ArraySetScannerState extends ScannerState
+{
+
+  void methodInvocation(String methodName)
+  {
+    throw new InternalError("You are not supposed to be here.");
+  }
+
+  void staticMethodInvocation(String className, String methodName)
+  {
+    throw new InternalError("You are not supposed to be here.");
+  }
+
+  void staticFieldAccess(String className, String fieldName)
+  {
+    throw new InternalError("You are not supposed to be here.");
+  }
+
+  void classResolution(String className)
+  {
+    throw new InternalError("You are not supposed to be here.");
+  }
+
+  void objectInstantiation(String className)
+  {
+    throw new InternalError("You are not supposed to be here.");
+  }
+
+  void primitiveInstantiation(String primitiveName, String valueAsString)
+  {
+    throw new InternalError("You are not supposed to be here.");
+  }
+
+  void arrayInstantiation(String arrayClassName, String lengthAsString)
+  {
+    throw new InternalError("You are not supposed to be here.");
+//    getActionIssuer().issue("array", new String[] { "class", "length"} , new 
String[] { arrayClassName, lengthAsString });
+  }
+
+  void arraySet(String indexAsString)
+  {
+    getActionIssuer().issue("void", "index", indexAsString);
+  }
+
+  void arrayGet(String indexAsString)
+  {
+    throw new InternalError("You are not supposed to be here.");
+  }
+
+  void listGet()
+  {
+    throw new InternalError("You are not supposed to be here.");
+  }
+
+  void listSet()
+  {
+    throw new InternalError("You are not supposed to be here.");
+  }
+
+  void nullObject()
+  {
+    throw new InternalError("You are not supposed to be here.");
+  }
+
+  void stringReference(String string)
+  {
+    throw new InternalError("You are not supposed to be here.");
+  }
+  
+  void childEnded(ScannerState child)
+  {
+    // Do nothing here (Cannot interact with child states).
+  }
+  
+}
Index: gnu/java/beans/encoder/ClassPersistenceDelegate.java
===================================================================
RCS file: gnu/java/beans/encoder/ClassPersistenceDelegate.java
diff -N gnu/java/beans/encoder/ClassPersistenceDelegate.java
--- /dev/null   1 Jan 1970 00:00:00 -0000
+++ gnu/java/beans/encoder/ClassPersistenceDelegate.java        22 Nov 2005 
14:39:50 -0000
@@ -0,0 +1,62 @@
+/* ClassPersistenceDelegate.java
+   Copyright (C) 2005 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+ 
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING.  If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version. */
+
+package gnu.java.beans.encoder;
+
+import java.beans.Encoder;
+import java.beans.Expression;
+import java.beans.PersistenceDelegate;
+
+public class ClassPersistenceDelegate extends PersistenceDelegate
+{
+
+  protected Expression instantiate(Object oldInstance, Encoder out)
+  {
+    Class oldClass = (Class) oldInstance;
+    // Due to this definition resolving the String and the Class
+    // class does not depend on anything else.
+    if (oldClass == String.class)
+      return new Expression(oldClass, "", "getClass", null);
+
+    if (oldClass == Class.class)
+      return new Expression(oldClass, String.class, "getClass", null);
+
+    return new Expression(oldClass, Class.class, "forName",
+                          new Object[] { oldClass.getName() });
+  }
+
+}
Index: gnu/java/beans/encoder/GenericScannerState.java
===================================================================
RCS file: gnu/java/beans/encoder/GenericScannerState.java
diff -N gnu/java/beans/encoder/GenericScannerState.java
--- /dev/null   1 Jan 1970 00:00:00 -0000
+++ gnu/java/beans/encoder/GenericScannerState.java     22 Nov 2005 14:39:50 
-0000
@@ -0,0 +1,116 @@
+/* GenericScannerState.java
+ Copyright (C) 2005 Free Software Foundation, Inc.
+
+ This file is part of GNU Classpath.
+
+ GNU Classpath is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ GNU Classpath is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GNU Classpath; see the file COPYING.  If not, write to the
+ Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ 02110-1301 USA.
+
+ Linking this library statically or dynamically with other modules is
+ making a combined work based on this library.  Thus, the terms and
+ conditions of the GNU General Public License cover the whole
+ combination.
+
+ As a special exception, the copyright holders of this library give you
+ permission to link this library with independent modules to produce an
+ executable, regardless of the license terms of these independent
+ modules, and to copy and distribute the resulting executable under
+ terms of your choice, provided that you also meet, for each linked
+ independent module, the terms and conditions of the license of that
+ module.  An independent module is a module which is not derived from
+ or based on this library.  If you modify this library, you may extend
+ this exception to your version of the library, but you are not
+ obligated to do so.  If you do not wish to do so, delete this
+ exception statement from your version. */
+
+
+package gnu.java.beans.encoder;
+
+class GenericScannerState extends ScannerState
+{
+
+  void methodInvocation(String methodName)
+  {
+    getActionIssuer().issue("void", "method", methodName);
+  }
+
+  void staticMethodInvocation(String className, String methodName)
+  {
+    getActionIssuer().issue("void", new String[] { "class", "method" },
+                            new String[] { className, methodName });
+  }
+
+  void staticFieldAccess(String className, String fieldName)
+  {
+    getActionIssuer().issue("object", new String[] { "class", "field" },
+                            new String[] { className, fieldName });
+  }
+
+  void classResolution(String className)
+  {
+    getActionIssuer().issue("class", className);
+  }
+
+  void objectInstantiation(String className)
+  {
+    getActionIssuer().issue("object", "class", className);
+  }
+
+  void primitiveInstantiation(String primitiveName, String valueAsString)
+  {
+    getActionIssuer().issue(primitiveName, valueAsString);
+  }
+
+  void arrayInstantiation(String arrayClassName, String lengthAsString)
+  {
+    getActionIssuer().issue("array", new String[] { "class", "length"} , new 
String[] { arrayClassName, lengthAsString });
+  }
+
+  void arraySet(String indexAsString)
+  {
+    getActionIssuer().issue("void", "index", indexAsString);
+  }
+
+  void arrayGet(String indexAsString)
+  {
+    getActionIssuer().issue("object", "index", indexAsString);
+  }
+
+  void listGet()
+  {
+    getActionIssuer().issue("object", "get");
+  }
+
+  void listSet()
+  {
+    getActionIssuer().issue("void", "set");
+  }
+
+  void nullObject()
+  {
+    getActionIssuer().issue("null");
+  }
+
+  void stringReference(String string)
+  {
+    getActionIssuer().issue("string", string);
+  }
+  
+  void childEnded(ScannerState child)
+  {
+    // Do nothing here (Cannot interact with child states).
+  }
+  
+}
Index: gnu/java/beans/encoder/IgnoringScannerState.java
===================================================================
RCS file: gnu/java/beans/encoder/IgnoringScannerState.java
diff -N gnu/java/beans/encoder/IgnoringScannerState.java
--- /dev/null   1 Jan 1970 00:00:00 -0000
+++ gnu/java/beans/encoder/IgnoringScannerState.java    22 Nov 2005 14:39:50 
-0000
@@ -0,0 +1,107 @@
+/* IgnoringScannerState.java -- FIXME: briefly describe file purpose
+ Copyright (C) 2005 Free Software Foundation, Inc.
+
+ This file is part of GNU Classpath.
+
+ GNU Classpath is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ GNU Classpath is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GNU Classpath; see the file COPYING.  If not, write to the
+ Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ 02110-1301 USA.
+
+ Linking this library statically or dynamically with other modules is
+ making a combined work based on this library.  Thus, the terms and
+ conditions of the GNU General Public License cover the whole
+ combination.
+
+ As a special exception, the copyright holders of this library give you
+ permission to link this library with independent modules to produce an
+ executable, regardless of the license terms of these independent
+ modules, and to copy and distribute the resulting executable under
+ terms of your choice, provided that you also meet, for each linked
+ independent module, the terms and conditions of the license of that
+ module.  An independent module is a module which is not derived from
+ or based on this library.  If you modify this library, you may extend
+ this exception to your version of the library, but you are not
+ obligated to do so.  If you do not wish to do so, delete this
+ exception statement from your version. */
+
+
+package gnu.java.beans.encoder;
+
+class IgnoringScannerState extends ScannerState
+{
+
+  void methodInvocation(String methodName)
+  {
+  }
+
+  void staticMethodInvocation(String className, String methodName)
+  {
+  }
+
+  void staticFieldAccess(String className, String fieldName)
+  {
+  }
+
+  void classResolution(String className)
+  {
+  }
+
+  void objectInstantiation(String className)
+  {
+  }
+
+  void primitiveInstantiation(String primitiveName, String valueAsString)
+  {
+  }
+
+  void arrayInstantiation(String arrayClassName, String lengthAsString)
+  {
+  }
+
+  void arraySet(String indexAsString)
+  {
+  }
+
+  void arrayGet(String indexAsString)
+  {
+  }
+
+  void listGet()
+  {
+  }
+
+  void listSet()
+  {
+  }
+
+  void nullObject()
+  {
+  }
+
+  void stringReference(String string)
+  {
+  }
+  
+  void end()
+  {
+    // Important: This overrides an otherwise default behavior which would
+    // issue to write a closing XML tag.
+  }
+  
+  void childEnded(ScannerState child)
+  {
+    
+  }
+  
+}
Index: gnu/java/beans/encoder/PrimitivePersistenceDelegate.java
===================================================================
RCS file: gnu/java/beans/encoder/PrimitivePersistenceDelegate.java
diff -N gnu/java/beans/encoder/PrimitivePersistenceDelegate.java
--- /dev/null   1 Jan 1970 00:00:00 -0000
+++ gnu/java/beans/encoder/PrimitivePersistenceDelegate.java    22 Nov 2005 
14:39:50 -0000
@@ -0,0 +1,60 @@
+/* PrimitivePersistenceDelegate.java
+   Copyright (C) 2005 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+ 
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING.  If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version. */
+
+package gnu.java.beans.encoder;
+
+import java.beans.Encoder;
+import java.beans.Expression;
+import java.beans.PersistenceDelegate;
+
+/**
+ * A shared PersistenceDelegate implementation for all primitive types.
+ */
+public class PrimitivePersistenceDelegate extends PersistenceDelegate
+{
+
+  protected Expression instantiate(Object oldInstance, Encoder out)
+  {
+    // The implementation relies on the fact that every primitive
+    // wrapper class has a constructor accepting a String argument.
+    // By using these constructors creating a primitive instance
+    // depends on the String class only.
+    return new Expression(oldInstance, oldInstance.getClass(), "new",
+                          new Object[] { oldInstance.toString() });
+  }
+
+}
Index: gnu/java/beans/encoder/ReportingScannerState.java
===================================================================
RCS file: gnu/java/beans/encoder/ReportingScannerState.java
diff -N gnu/java/beans/encoder/ReportingScannerState.java
--- /dev/null   1 Jan 1970 00:00:00 -0000
+++ gnu/java/beans/encoder/ReportingScannerState.java   22 Nov 2005 14:39:50 
-0000
@@ -0,0 +1,118 @@
+/* ReportingScannerState.java -- A state for debugging purposes.
+ Copyright (C) 2005 Free Software Foundation, Inc.
+
+ This file is part of GNU Classpath.
+
+ GNU Classpath is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ GNU Classpath is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GNU Classpath; see the file COPYING.  If not, write to the
+ Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ 02110-1301 USA.
+
+ Linking this library statically or dynamically with other modules is
+ making a combined work based on this library.  Thus, the terms and
+ conditions of the GNU General Public License cover the whole
+ combination.
+
+ As a special exception, the copyright holders of this library give you
+ permission to link this library with independent modules to produce an
+ executable, regardless of the license terms of these independent
+ modules, and to copy and distribute the resulting executable under
+ terms of your choice, provided that you also meet, for each linked
+ independent module, the terms and conditions of the license of that
+ module.  An independent module is a module which is not derived from
+ or based on this library.  If you modify this library, you may extend
+ this exception to your version of the library, but you are not
+ obligated to do so.  If you do not wish to do so, delete this
+ exception statement from your version. */
+
+
+package gnu.java.beans.encoder;
+
+class ReportingScannerState extends ScannerState
+{
+
+  void methodInvocation(String methodName)
+  {
+       System.out.println("methodInvocation");
+  }
+
+  void staticMethodInvocation(String className, String methodName)
+  {
+       System.out.println("staticMethodInvocation");
+  }
+
+  void staticFieldAccess(String className, String fieldName)
+  {
+  }
+
+  void classResolution(String className)
+  {
+       System.out.println("classResolution");
+  }
+
+  void objectInstantiation(String className)
+  {
+       System.out.println("objectInstantiation");
+  }
+
+  void primitiveInstantiation(String primitiveName, String valueAsString)
+  {
+       System.out.println("primitiveInstantiation");
+  }
+
+  void arrayInstantiation(String arrayClassName, String lengthAsString)
+  {
+       System.out.println("arrayInstantiation");
+  }
+
+  void arraySet(String indexAsString)
+  {
+       System.out.println("arraySet");
+  }
+
+  void arrayGet(String indexAsString)
+  {
+       System.out.println("arrayGet");
+  }
+
+  void listGet()
+  {
+       System.out.println("listGet");
+  }
+
+  void listSet()
+  {
+       System.out.println("listSet");
+  }
+
+  void nullObject()
+  {
+       System.out.println("nullObject");
+  }
+
+  void stringReference(String string)
+  {
+       System.out.println("stringReference");
+  }
+
+ void end()
+ {
+       System.out.println("-close");
+ }
+
+ void childEnded(ScannerState child)
+ {
+   System.out.println("childEnded: " + child);
+ }
+ 
+}
Index: gnu/java/beans/encoder/ScanEngine.java
===================================================================
RCS file: gnu/java/beans/encoder/ScanEngine.java
diff -N gnu/java/beans/encoder/ScanEngine.java
--- /dev/null   1 Jan 1970 00:00:00 -0000
+++ gnu/java/beans/encoder/ScanEngine.java      22 Nov 2005 14:39:50 -0000
@@ -0,0 +1,465 @@
+/* ScanEngine.java 
+ -- Main scan engine of the java.beans.XMLEncoder.
+ Copyright (C) 2005 Free Software Foundation, Inc.
+
+ This file is part of GNU Classpath.
+
+ GNU Classpath is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ GNU Classpath is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GNU Classpath; see the file COPYING.  If not, write to the
+ Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ 02110-1301 USA.
+
+ Linking this library statically or dynamically with other modules is
+ making a combined work based on this library.  Thus, the terms and
+ conditions of the GNU General Public License cover the whole
+ combination.
+
+ As a special exception, the copyright holders of this library give you
+ permission to link this library with independent modules to produce an
+ executable, regardless of the license terms of these independent
+ modules, and to copy and distribute the resulting executable under
+ terms of your choice, provided that you also meet, for each linked
+ independent module, the terms and conditions of the license of that
+ module.  An independent module is a module which is not derived from
+ or based on this library.  If you modify this library, you may extend
+ this exception to your version of the library, but you are not
+ obligated to do so.  If you do not wish to do so, delete this
+ exception statement from your version. */
+
+
+package gnu.java.beans.encoder;
+
+import java.beans.Expression;
+import java.beans.Statement;
+import java.lang.reflect.Array;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Stack;
+
+import javax.xml.stream.XMLStreamException;
+
+public class ScanEngine
+{
+
+  /**
+   * Stores the scanner engine states as values and their names as keys.
+   */
+  HashMap states = new HashMap();
+
+  ScannerState current = new GenericScannerState();
+
+  ActionIssuer issuer;
+
+  Stack parents = new Stack();
+
+  public ScanEngine(ActionIssuer newIssuer)
+  {
+    issuer = newIssuer;
+
+    current.enter(issuer);
+
+    // Scanner configuration:
+    // null - no changes
+    // string - no changes
+    final ScannerState start = current;
+    ScannerState conf;
+
+    // TODO: Develop ReportingScannerState and put it in here
+    register(ScannerState.DEFAULT_STATE_NAME, new ReportingScannerState());
+
+    register("start", start);
+
+    // Special dead-end state where all transitions are ignored
+    register("ignoreAll", new 
IgnoringScannerState()).setDefaultSuccessor("ignoreAll");
+
+    // StringReference, Null Object
+    start.putSuccessor(ScannerState.TRANSITION_STRING_REFERENCE, "simple");
+    start.putSuccessor(ScannerState.TRANSITION_NULL_OBJECT, "simple");
+    register("simple", new GenericScannerState());
+
+    // ClassResolution
+    start.putSuccessor(ScannerState.TRANSITION_CLASS_RESOLUTION, "classRes0");
+    register("classRes0", new 
GenericScannerState()).setDefaultSuccessor("ignoreAll");
+
+    start.putSuccessor(ScannerState.TRANSITION_OBJECT_INSTANTIATION, 
"newObj0");
+    register("newObj0", new 
GenericScannerState()).setDefaultSuccessor("ignoreAll");
+
+    start.putSuccessor(ScannerState.TRANSITION_PRIMITIVE_INSTANTIATION, 
"newPrimitive0");
+    register("newPrimitive0", new 
GenericScannerState()).setDefaultSuccessor("ignoreAll");
+
+    start.putSuccessor(ScannerState.TRANSITION_ARRAY_INSTANTIATION, 
"newArray0");
+    conf = register("newArray0", new GenericScannerState());
+    conf.putSuccessor(ScannerState.TRANSITION_ARRAY_SET, "newArray1");
+    conf.putSuccessor(ScannerState.TRANSITION_CLASS_RESOLUTION, "ignoreAll");
+    conf.putSuccessor(ScannerState.TRANSITION_PRIMITIVE_INSTANTIATION, 
"ignoreAll");
+
+    register("newArray1", new 
GenericScannerState()).setDefaultSuccessor("start");
+  }
+
+  private ScannerState register(String name, ScannerState state)
+  {
+    states.put(name, state);
+
+    return state;
+  }
+
+  public void writeExpression(Expression expr)
+  {
+    String methodName = expr.getMethodName();
+    Object[] args = expr.getArguments();
+    Object target = expr.getTarget();
+    Object value = null;
+
+    try
+      {
+        value = expr.getValue();
+      }
+    catch (Exception e)
+      {
+        throw (InternalError) new InternalError(
+                                                "The Expression's value should 
be available at this point.").initCause(e);
+      }
+
+    if (target == Array.class)
+      {
+        if (methodName.equals("newInstance"))
+          {
+            arrayInstantiation(((Class) args[0]).getName(), 
args[1].toString());
+            return;
+          }
+        else if (methodName.equals("get"))
+          {
+            arrayGet(args[1].toString());
+            return;
+          }
+        else if (methodName.equals("set"))
+          {
+            arraySet(args[1].toString());
+            return;
+          }
+      }
+
+    if (target instanceof Class)
+      {
+        if (methodName.equals("new"))
+          {
+            Class targetClass = (Class) target;
+
+            Class valueClass = value.getClass();
+
+            // All primitive types have short-hand forms for their
+            // constructors.
+            if (valueClass == Boolean.class)
+              primitiveInstantiation("boolean", args[0].toString());
+            else if (valueClass == Short.class)
+              primitiveInstantiation("short", args[0].toString());
+            else if (valueClass == Integer.class)
+              primitiveInstantiation("int", args[0].toString());
+            else if (valueClass == Long.class)
+              primitiveInstantiation("long", args[0].toString());
+            else if (valueClass == Float.class)
+              primitiveInstantiation("float", args[0].toString());
+            else if (valueClass == Double.class)
+              primitiveInstantiation("double", args[0].toString());
+            else
+              objectInstantiation(targetClass.getName());
+            
+            return;
+          }
+        else if (value instanceof Class)
+          {
+            String className = ((Class) value).getName();
+
+            // At this point some static method will be called.
+
+            // However "Class.forName" represents class resolution and has a
+            // different syntax.
+            if (methodName.equals("forName"))
+              {
+                classResolution(className);
+                return;
+              }
+            else
+            // The same goes for "Class.getField".
+            // Note: The name of the wanted field is given in
+            // the argument array.
+            if (methodName.equals("getField"))
+              {
+                staticFieldAccess(className, args[0].toString());
+                return;
+              }
+            else
+              {
+                staticMethodInvocation(className, methodName);
+                return;
+              }
+          }
+      }
+    else if (target instanceof List)
+      {
+        if (methodName.equals("get"))
+          {
+            listGet();
+            return;
+          }
+        else if (methodName.equals("set"))
+          {
+            listSet();
+            return;
+          }
+      }
+
+    // If nothing else could be used then this is a normal
+    // method invocation.
+    methodInvocation(methodName);
+  }
+
+  public void end()
+  {
+    current.end();
+
+    ScannerState oldCurrent = current;
+    current = (ScannerState) parents.pop();
+
+    // Gives the parent the possibility to interact with the child state.
+    current.childEnded(current);
+
+    System.out.println("leave");
+  }
+
+  public void writeStatement(Statement stmt)
+  {
+    // Thats is probably wrong. Everything here should
+    // be void things.
+    
+    String methodName = stmt.getMethodName();
+    Object target = stmt.getTarget();
+    Object[] args = stmt.getArguments();
+    Object value = null;
+
+    if (target == Array.class)
+      {
+        if (methodName.equals("newInstance"))
+          {
+            arrayInstantiation(((Class) args[0]).getName(), 
args[1].toString());
+            return;
+          }
+        else if (methodName.equals("get"))
+          {
+            arrayGet(args[1].toString());
+            return;
+          }
+        else if (methodName.equals("set"))
+          {
+            arraySet(args[1].toString());
+            return;
+          }
+      }
+
+    if (target instanceof Class)
+      {
+        if (methodName.equals("new"))
+          {
+            Class targetClass = (Class) target;
+
+            Class valueClass = value.getClass();
+
+            // All primitive types have short-hand forms for their
+            // constructors.
+            if (valueClass == Boolean.class)
+              primitiveInstantiation("boolean", args[0].toString());
+            else if (valueClass == Short.class)
+              primitiveInstantiation("short", args[0].toString());
+            else if (valueClass == Integer.class)
+              primitiveInstantiation("int", args[0].toString());
+            else if (valueClass == Long.class)
+              primitiveInstantiation("long", args[0].toString());
+            else if (valueClass == Float.class)
+              primitiveInstantiation("float", args[0].toString());
+            else if (valueClass == Double.class)
+              primitiveInstantiation("double", args[0].toString());
+            else
+              objectInstantiation(targetClass.getName());
+            
+            return;
+          }
+        else if (value instanceof Class)
+          {
+            String className = ((Class) value).getName();
+
+            // At this point some static method will be called.
+
+            // However "Class.forName" represents class resolution and has a
+            // different syntax.
+            if (methodName.equals("forName"))
+              {
+                classResolution(className);
+                return;
+              }
+            else
+            // The same goes for "Class.getField".
+            // Note: The name of the wanted field is given in
+            // the argument array.
+            if (methodName.equals("getField"))
+              {
+                staticFieldAccess(className, args[0].toString());
+                return;
+              }
+            else
+              {
+                staticMethodInvocation(className, methodName);
+                return;
+              }
+          }
+      }
+    else if (target instanceof List)
+      {
+        if (methodName.equals("get"))
+          {
+            listGet();
+            return;
+          }
+        else if (methodName.equals("set"))
+          {
+            listSet();
+            return;
+          }
+      }
+
+    // If nothing else could be used then this is a normal
+    // method invocation.
+    methodInvocation(methodName);
+  }
+
+  public void writeObject(Object o)
+  {
+    if (o == null)
+      {
+        nullObject();
+        end();
+      }
+    else if (o instanceof String)
+      {
+        stringReference((String) o);
+        end();
+      }
+
+  }
+
+  private void transition(int transition)
+  {
+    parents.push(current);
+
+    String stateName = current.getSuccessor(transition);
+    System.out.println("enter: " + transition + " to " + stateName);
+
+    ScannerState newState = (ScannerState) states.get(stateName);
+
+    assert (newState != null) : "State '" + stateName + "' was not defined.";
+
+    newState.enter(issuer);
+    current = newState;
+  }
+
+  void methodInvocation(String methodName)
+  {
+    transition(ScannerState.TRANSITION_METHOD_INVOCATION);
+
+    current.methodInvocation(methodName);
+  }
+
+  void staticMethodInvocation(String className, String methodName)
+  {
+    transition(ScannerState.TRANSITION_STATIC_METHOD_INVOCATION);
+
+    current.staticMethodInvocation(className, methodName);
+  }
+
+  void staticFieldAccess(String className, String fieldName)
+  {
+    transition(ScannerState.TRANSITION_STATIC_FIELD_ACCESS);
+
+    current.staticFieldAccess(className, fieldName);
+  }
+
+  void classResolution(String className)
+  {
+    transition(ScannerState.TRANSITION_CLASS_RESOLUTION);
+
+    current.classResolution(className);
+  }
+
+  void objectInstantiation(String className)
+  {
+    transition(ScannerState.TRANSITION_OBJECT_INSTANTIATION);
+
+    current.objectInstantiation(className);
+  }
+
+  void primitiveInstantiation(String primitiveName, String valueAsString)
+  {
+    transition(ScannerState.TRANSITION_PRIMITIVE_INSTANTIATION);
+
+    current.primitiveInstantiation(primitiveName, valueAsString);
+  }
+
+  void arrayInstantiation(String arrayClassName, String lengthAsString)
+  {
+    transition(ScannerState.TRANSITION_ARRAY_INSTANTIATION);
+
+    current.arrayInstantiation(arrayClassName, lengthAsString);
+  }
+
+  void arraySet(String indexAsString)
+  {
+    transition(ScannerState.TRANSITION_ARRAY_SET);
+
+    current.arraySet(indexAsString);
+  }
+
+  void arrayGet(String indexAsString)
+  {
+    transition(ScannerState.TRANSITION_ARRAY_GET);
+
+    current.arrayGet(indexAsString);
+  }
+
+  void listSet()
+  {
+    transition(ScannerState.TRANSITION_LIST_SET);
+
+    current.listSet();
+  }
+
+  void listGet()
+  {
+    transition(ScannerState.TRANSITION_LIST_GET);
+
+    current.listGet();
+  }
+
+  void nullObject()
+  {
+    transition(ScannerState.TRANSITION_NULL_OBJECT);
+
+    current.nullObject();
+  }
+
+  void stringReference(String string)
+  {
+    transition(ScannerState.TRANSITION_STRING_REFERENCE);
+
+    current.stringReference(string);
+  }
+
+}
Index: gnu/java/beans/encoder/ScannerState.java
===================================================================
RCS file: gnu/java/beans/encoder/ScannerState.java
diff -N gnu/java/beans/encoder/ScannerState.java
--- /dev/null   1 Jan 1970 00:00:00 -0000
+++ gnu/java/beans/encoder/ScannerState.java    22 Nov 2005 14:39:50 -0000
@@ -0,0 +1,137 @@
+/* ScannerState.java
+   Copyright (C) 2005 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING.  If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package gnu.java.beans.encoder;
+
+import java.util.HashMap;
+
+public abstract class ScannerState
+{
+  
+  static final int TRANSITION_METHOD_INVOCATION = 0;
+  static final int TRANSITION_STATIC_METHOD_INVOCATION = 1;
+  static final int TRANSITION_STATIC_FIELD_ACCESS = 2;
+  static final int TRANSITION_CLASS_RESOLUTION = 3;
+  static final int TRANSITION_OBJECT_INSTANTIATION = 4;
+  static final int TRANSITION_PRIMITIVE_INSTANTIATION = 5;
+  static final int TRANSITION_ARRAY_INSTANTIATION = 6;
+  static final int TRANSITION_ARRAY_SET = 7;
+  static final int TRANSITION_ARRAY_GET = 8;
+  static final int TRANSITION_LIST_SET = 9;
+  static final int TRANSITION_LIST_GET = 10;
+  static final int TRANSITION_NULL_OBJECT = 11;
+  static final int TRANSITION_STRING_REFERENCE = 12;
+  
+  static final int TRANSITION_FIRST = 0;
+  static final int TRANSITION_LAST = 12;
+
+  static final String DEFAULT_STATE_NAME = "default";
+  
+  String defaultSuccessor = DEFAULT_STATE_NAME;
+  
+  HashMap transitions = new HashMap();
+  
+  private ActionIssuer actionIssuer;
+  
+  void enter(ActionIssuer issuer)
+  {
+    if ( actionIssuer == null )
+       actionIssuer = issuer;
+  }
+  
+  void end()
+  {
+    actionIssuer.issueEnd();
+  }
+  
+  protected ActionIssuer getActionIssuer()
+  {
+    return actionIssuer;
+  }
+  
+  void putSuccessor(int transition, String stateName)
+  {
+    if (transition < TRANSITION_FIRST &&
+      transition > TRANSITION_LAST )
+      {
+        throw new IllegalStateException("Transition identifier '" + transition 
+ "' is unknown.");
+      }
+    
+    transitions.put(new Integer(transition), stateName);
+  }
+  
+  String getSuccessor(int transition)
+  {
+    String state = (String) transitions.get(new Integer(transition));
+    
+    return (state == null) ? defaultSuccessor : state;
+  }
+  
+  void setDefaultSuccessor(String newDefaultSuccessor)
+  {
+    defaultSuccessor = newDefaultSuccessor;
+  }
+
+  abstract void methodInvocation(String methodName);
+  
+  abstract void staticMethodInvocation(String className, String methodName);
+  
+  abstract void staticFieldAccess(String className, String fieldName);
+  
+  abstract void classResolution(String className);
+  
+  abstract void objectInstantiation(String className);
+  
+  abstract void primitiveInstantiation(String primitiveName, String 
valueAsString);
+  
+  abstract void arrayInstantiation(String arrayClassName, String 
lengthAsString);
+  
+  abstract void arraySet(String indexAsString);
+  
+  abstract void arrayGet(String indexAsString);
+  
+  abstract void listGet();
+  
+  abstract void listSet();
+
+  abstract void nullObject();
+  
+  abstract void stringReference(String string);
+
+  abstract void childEnded(ScannerState child);
+}
Index: gnu/java/beans/encoder/StAXActionIssuer.java
===================================================================
RCS file: gnu/java/beans/encoder/StAXActionIssuer.java
diff -N gnu/java/beans/encoder/StAXActionIssuer.java
--- /dev/null   1 Jan 1970 00:00:00 -0000
+++ gnu/java/beans/encoder/StAXActionIssuer.java        22 Nov 2005 14:39:50 
-0000
@@ -0,0 +1,242 @@
+/* StAXActionIssuer.java
+ Copyright (C) 2005 Free Software Foundation, Inc.
+
+ This file is part of GNU Classpath.
+
+ GNU Classpath is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ GNU Classpath is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GNU Classpath; see the file COPYING.  If not, write to the
+ Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ 02110-1301 USA.
+
+ Linking this library statically or dynamically with other modules is
+ making a combined work based on this library.  Thus, the terms and
+ conditions of the GNU General Public License cover the whole
+ combination.
+
+ As a special exception, the copyright holders of this library give you
+ permission to link this library with independent modules to produce an
+ executable, regardless of the license terms of these independent
+ modules, and to copy and distribute the resulting executable under
+ terms of your choice, provided that you also meet, for each linked
+ independent module, the terms and conditions of the license of that
+ module.  An independent module is a module which is not derived from
+ or based on this library.  If you modify this library, you may extend
+ this exception to your version of the library, but you are not
+ obligated to do so.  If you do not wish to do so, delete this
+ exception statement from your version. */
+
+
+package gnu.java.beans.encoder;
+
+import java.io.OutputStream;
+import java.util.ArrayList;
+import java.util.Iterator;
+
+import javax.xml.stream.XMLOutputFactory;
+import javax.xml.stream.XMLStreamException;
+import javax.xml.stream.XMLStreamWriter;
+
+public class StAXActionIssuer implements ActionIssuer
+{
+  XMLStreamWriter writer;
+
+  ArrayList writeCommands = new ArrayList();
+
+  int indent = 0;
+
+  public StAXActionIssuer(OutputStream os)
+  {
+    try
+      {
+        XMLOutputFactory factory = XMLOutputFactory.newInstance();
+        writer = factory.createXMLStreamWriter(os);
+      }
+    catch (XMLStreamException se)
+      {
+        throw (InternalError) new InternalError(
+          "Could not instantiate a streaming XML writer.").initCause(se);
+      }
+
+  }
+
+  private void add(WriteCommand wc)
+  {
+    writeCommands.add(wc);
+  }
+
+  public void flush()
+  {
+    Iterator ite = writeCommands.iterator();
+
+    try
+      {
+        while (ite.hasNext())
+          ((WriteCommand) ite.next()).write();
+
+        writeCommands.clear();
+      }
+    catch (XMLStreamException xse)
+      {
+        // TODO: find out
+      }
+
+  }
+
+  public void close()
+  {
+    if (writer != null)
+      {
+        try
+          {
+            writer.writeEndDocument();
+            writer.close();
+          }
+        catch (XMLStreamException xse)
+          {
+            // TODO: find out
+          }
+        writer = null;
+      }
+    
+  }
+
+  public void issuePreamble()
+  {
+    add(new PreambleWriteCommand());
+  }
+
+  public void issueEnd()
+  {
+    add(new EndWriteCommand());
+  }
+
+  public void issue(String tagName)
+  {
+    add(new ValueWriteCommand(tagName));
+  }
+
+  public void issue(String tagName, String value)
+  {
+    add(new ValueWriteCommand(tagName, value));
+  }
+
+  public void issue(String tagName, String attributeName, String 
attributeValue)
+  {
+    add(new ValueWriteCommand(tagName, null, new String[] { attributeName },
+                              new String[] { attributeValue }));
+  }
+
+  public void issue(String tagName, String value, String[] attributeNames,
+                    String[] attributeValues)
+  {
+    add(new ValueWriteCommand(tagName, value, attributeNames, 
attributeValues));
+  }
+
+  public void issue(String tagName, String[] attributeNames,
+                    String[] attributeValues)
+  {
+    add(new ValueWriteCommand(tagName, null, attributeNames, attributeValues));
+  }
+
+  interface WriteCommand
+  {
+    void write() throws XMLStreamException;
+  }
+
+  class PreambleWriteCommand implements WriteCommand
+  {
+
+    public void write() throws XMLStreamException
+    {
+      writer.writeStartDocument("UTF-8", "1.0");
+    }
+
+  }
+
+  class ValueWriteCommand implements WriteCommand
+  {
+    String tagName, value;
+
+    String[] attributeNames, attributeValues;
+
+    ValueWriteCommand(String newTagName)
+    {
+      tagName = newTagName;
+    }
+
+    ValueWriteCommand(String newTagName, String newValue)
+    {
+      this(newTagName);
+      value = newValue;
+    }
+
+    ValueWriteCommand(String newTagName, String newValue,
+                      String[] newAttributeNames, String[] newAttributeValues)
+    {
+      this(newTagName, newValue);
+
+      assert (newAttributeNames != null);
+      assert (newAttributeValues != null);
+      assert (newAttributeNames.length == newAttributeValues.length);
+
+      attributeNames = newAttributeNames;
+      attributeValues = newAttributeValues;
+    }
+
+    public void write() throws XMLStreamException
+    {
+
+      for ( int i = 0;i< indent; i++ )
+        writer.writeCharacters(" ");
+
+      writer.writeStartElement(tagName);
+
+      if (attributeNames != null)
+        for (int i = 0; i < attributeNames.length; i++)
+          writer.writeAttribute(attributeNames[i], attributeValues[i]);
+
+      writer.writeCharacters("\n");
+
+      indent += 2;
+
+      if (value != null)
+        {
+          for ( int i = 0;i< indent; i++ )
+            writer.writeCharacters(" ");
+
+          writer.writeCharacters(value);
+
+          writer.writeCharacters("\n");
+        }
+
+    }
+  }
+
+  class EndWriteCommand implements WriteCommand
+  {
+
+    public void write() throws XMLStreamException
+    {
+      indent -= 2;
+
+      for ( int i = 0;i< indent; i++ )
+        writer.writeCharacters(" ");
+
+      writer.writeEndElement();
+
+      writer.writeCharacters("\n");
+    }
+
+  }
+
+}

reply via email to

[Prev in Thread] Current Thread [Next in Thread]