[multiple changes]
2005-02-19 Michael Koch <konqueror@gmx.de> * Makefile.am: Added new files in gnu/java/beans and java/beans/XMLDecoder.java. * Makefile.in: Regenerated. 2005-02-19 Robert Schuster <thebohemian@gmx.net> * gnu/java/beans/decoder/GrowableArrayContext.java: Fixed assignment behavior by using java.lang.reflect.Array.set() directly. 2005-02-19 Dalibor Topic <robilad@kaffe.org> * gnu/java/beans/EmptyBeanInfo.java, gnu/java/beans/info/ComponentBeanInfo.java: Removed unused files. 2005-02-19 Robert Schuster <thebohemian@gmx.net> * gnu/java/beans/DummyAppletStub.java: Add dummy implementation of AppletStub for java.beans.Beans.instantiate. * gnu/java/beans/DummyAppletContext.java: Add dummy implementation of AppletContext. * java/beans/Beans: Added 1.4 functionality, fixed user documentation to be conformant with Javadoc guidelines. (instantiate): Added two more overloaded variants, reworked user documentation, fixed exception behavior, fixed behavior when deserializing null. 2005-02-19 Mark Wielaard <mark@klomp.org> * gnu/java/beans/decoder/DummyHandler.java: Add return statements for failing methods. * gnu/java/beans/decoder/DummyContext.java: Likewise. 2005-02-19 Robert Schuster <theBohemian@gmx.net> * gnu/java/beans/decoder/AbstractContext.java, gnu/java/beans/decoder/AbstractCreatableContext.java, gnu/java/beans/decoder/AbstractElementHandler.java, gnu/java/beans/decoder/AbstractObjectContext.java, gnu/java/beans/decoder/ArrayContext.java, gnu/java/beans/decoder/ArrayHandler.java, gnu/java/beans/decoder/AssemblyException.java, gnu/java/beans/decoder/BooleanHandler.java, gnu/java/beans/decoder/ByteHandler.java, gnu/java/beans/decoder/CharHandler.java, gnu/java/beans/decoder/ClassHandler.java, gnu/java/beans/decoder/ConstructorContext.java, gnu/java/beans/decoder/Context.java, gnu/java/beans/decoder/DecoderContext.java, gnu/java/beans/decoder/DefaultExceptionListener.java, gnu/java/beans/decoder/DoubleHandler.java, gnu/java/beans/decoder/DummyContext.java, gnu/java/beans/decoder/DummyHandler.java, gnu/java/beans/decoder/ElementHandler.java, gnu/java/beans/decoder/FloatHandler.java, gnu/java/beans/decoder/GrowableArrayContext.java, gnu/java/beans/decoder/IndexContext.java, gnu/java/beans/decoder/IntHandler.java, gnu/java/beans/decoder/JavaHandler.java, gnu/java/beans/decoder/LongHandler.java, gnu/java/beans/decoder/MethodContext.java, gnu/java/beans/decoder/MethodFinder.java, gnu/java/beans/decoder/NullHandler.java, gnu/java/beans/decoder/ObjectContext.java, gnu/java/beans/decoder/ObjectHandler.java, gnu/java/beans/decoder/PersistenceParser.java, gnu/java/beans/decoder/PropertyContext.java, gnu/java/beans/decoder/ShortHandler.java, gnu/java/beans/decoder/SimpleHandler.java, gnu/java/beans/decoder/StaticMethodContext.java, gnu/java/beans/decoder/StringHandler.java, gnu/java/beans/decoder/VoidHandler.java: New class implementing java.beans.XMLDecoder decoding functionality. * java/beans/XMLDecoder.java: New class. From-SVN: r95287
This commit is contained in:
+292
-185
@@ -1,5 +1,5 @@
|
||||
/* java.beans.Beans
|
||||
Copyright (C) 1998, 1999 Free Software Foundation, Inc.
|
||||
Copyright (C) 1998, 1999, 2004, 2005 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU Classpath.
|
||||
|
||||
@@ -35,23 +35,26 @@ 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.DummyAppletStub;
|
||||
import gnu.java.io.ClassLoaderObjectInputStream;
|
||||
|
||||
import java.applet.Applet;
|
||||
import java.beans.beancontext.BeanContext;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.ObjectInputStream;
|
||||
import java.net.URL;
|
||||
|
||||
/**
|
||||
* <code>Beans</code> provides some helper methods that allow the basic
|
||||
* operations of Bean-ness.
|
||||
*
|
||||
* @author John Keiser
|
||||
* @author Robert Schuster
|
||||
*
|
||||
* @since 1.1
|
||||
* @version 1.1.0, 29 Jul 1998
|
||||
* @status updated to 1.4
|
||||
*
|
||||
*/
|
||||
public class Beans
|
||||
@@ -66,196 +69,300 @@ public class Beans
|
||||
*/
|
||||
public Beans()
|
||||
{
|
||||
// Do nothing here.
|
||||
// Does intentionally nothing here.
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows you to instantiate a Bean. This method takes
|
||||
* a ClassLoader from which to read the Bean and the
|
||||
* name of the Bean.<P>
|
||||
*
|
||||
* The Bean name should be a dotted name, like a class.
|
||||
* It can represent several things. Beans will search
|
||||
* for the Bean using the name like this:<P>
|
||||
* <OL>
|
||||
* <LI>Searches for a serialized instance of the Bean
|
||||
* using getResource(), mangling the Bean name by
|
||||
* replacing the dots with slashes and appending .ser
|
||||
* (for example, gnu.beans.BlahDeBlah would cause
|
||||
* Beans to search for gnu/beans/BlahDeBlah.ser using
|
||||
* getResource()).</LI>
|
||||
* <LI>Searches for the Bean class using the beanName,
|
||||
* and then instantiates it with the no-arg constructor.
|
||||
* At that point, if it is an Applet, it provides it
|
||||
* with AppletContext and AppletStub, and then calls
|
||||
* init().</LI>
|
||||
* </OL>
|
||||
*
|
||||
* @param cl the ClassLoader to use, or <CODE>null</CODE>
|
||||
* to use the default ClassLoader.
|
||||
* @param beanName the name of the Bean.
|
||||
*
|
||||
* @return the Bean.
|
||||
*
|
||||
* @XXX
|
||||
*/
|
||||
public static Object instantiate (ClassLoader cl, String beanName)
|
||||
throws IOException, ClassNotFoundException
|
||||
{
|
||||
Object bean;
|
||||
InputStream serStream;
|
||||
|
||||
if (cl == null)
|
||||
{
|
||||
serStream = ClassLoader.getSystemResourceAsStream
|
||||
(beanName.replace ('.','/')+".ser");
|
||||
}
|
||||
else
|
||||
{
|
||||
serStream = cl.getResourceAsStream (beanName.replace ('.', '/')
|
||||
+ ".ser");
|
||||
}
|
||||
|
||||
if (serStream != null)
|
||||
{
|
||||
if(cl == null)
|
||||
{
|
||||
ObjectInputStream ois = new ObjectInputStream(serStream);
|
||||
/** Creates a bean.
|
||||
* <p>This is a convenience method that calls <code>instantiate(cl, beanName, null, null)</code>.</p>
|
||||
*
|
||||
* @see instantiate(ClassLoader, String, BeanContext, AppletInitializer)
|
||||
* @param cl ClassLoader to be used or <code>null</code> for the system classloader.
|
||||
* @param beanName Name of a serialized bean or class name.
|
||||
* @return A newly created bean.
|
||||
* @throws IOException If access of an IO resource failed.
|
||||
* @throws ClassNotFoundException If the class name is not known or does not lead to a proper bean class.
|
||||
*/
|
||||
public static Object instantiate(ClassLoader cl, String beanName)
|
||||
throws IOException, ClassNotFoundException
|
||||
{
|
||||
return instantiate(cl, beanName, null, null);
|
||||
}
|
||||
|
||||
/** Creates a bean.
|
||||
*
|
||||
* <p>This is a convenience method that calls <code>instantiate(cl, beanName, beanContext, null)</code>.</p>
|
||||
*
|
||||
* @see instantiate(ClassLoader, String, BeanContext, AppletInitializer)
|
||||
* @param cl ClassLoader to be used or <code>null</code> for the system classloader.
|
||||
* @param beanName Name of a serialized bean or class name.
|
||||
* @param beanContext Context to which the newly created Bean should be added.
|
||||
* @return A newly created bean.
|
||||
* @throws IOException If access of an IO resource failed.
|
||||
* @throws ClassNotFoundException If the class name is not known or does not lead to a proper bean class.
|
||||
*/
|
||||
public static Object instantiate(
|
||||
ClassLoader cl,
|
||||
String beanName,
|
||||
BeanContext beanContext)
|
||||
throws IOException, ClassNotFoundException
|
||||
{
|
||||
return instantiate(cl, beanName, beanContext, null);
|
||||
}
|
||||
|
||||
/** Instantiates a bean according to Beans 1.0.
|
||||
*
|
||||
* <p>In Beans 1.0 the instantiation scheme is as follows:</p>
|
||||
* <p>The name should be dot-separated (e.g "place.for.beans.myBean") and indicate either a
|
||||
* serialized object or a class name. In the first case all dots in the name are replaced with
|
||||
* slashes ('/') and ".ser" is appended ("place.for.beans.myBean" becomes "place/for/beans/myBean.ser").
|
||||
* The bean is then loaded as an application or system resource depending on whether a
|
||||
* <code>ClassLoader</code> was provided.</p>
|
||||
*
|
||||
* <p>If no such resource exists or if it contains no bean the name is interpreted as a class name of
|
||||
* which an instance is then created.</p>
|
||||
*
|
||||
* <p>If a <code>BeanContext</code> instance is available the created bean is added to it.</p>
|
||||
*
|
||||
* <p>If the created Bean is an <code>Applet</code> or subclass and an <code>AppletInitializer</code>
|
||||
* instance is available the applet is initialized and afterwards activated using the initializer. Additionally
|
||||
* every instantiated <code>Applet</code> bean is initialized using the {@link Applet.init} method.
|
||||
* Furthermore every applet gets a default <code>AppletStub</code>. The <code>Applet</code>'s
|
||||
* document base is the location of the ".ser" file if it was deserialized or the location of its class
|
||||
* file if it was instantiated.</p>
|
||||
*
|
||||
* <p>A <code>ClassNotFoundException</code> is not only thrown when a class name was unknown
|
||||
* but even when the class has public no-argument constructor
|
||||
* (<code>IllegalAccessException</code> is wrapped) or an exception is thrown while
|
||||
* invoking such a constructor (causing exception is wrapped).</p>
|
||||
*
|
||||
* @param cl ClassLoader to be used or <code>null</code> for the system classloader.
|
||||
* @param beanName Name of a serialized bean or class name.
|
||||
* @param beanContext Context to which the newly created Bean should be added.
|
||||
* @param initializer The AppletInitializer which is used for initializing <code>Applet</code> beans.
|
||||
* @return A newly created bean.
|
||||
* @throws IOException If access of an IO resource failed.
|
||||
* @throws ClassNotFoundException If the class name is not known or does not lead to a proper bean class.
|
||||
*/
|
||||
public static Object instantiate(
|
||||
ClassLoader cl,
|
||||
String beanName,
|
||||
BeanContext beanContext,
|
||||
AppletInitializer initializer)
|
||||
throws IOException, ClassNotFoundException
|
||||
{
|
||||
Object bean = null;
|
||||
URL beanLocation = null;
|
||||
URL classLocation = null;
|
||||
|
||||
// Converts bean name into a resource name (eg. "a.b.c" -> "a/b/c").
|
||||
String resourceName = beanName.replace('.', '/');
|
||||
|
||||
/* Tries to get an input stream of the Bean, reading it as a system resource
|
||||
* if no ClassLoader is present or as an application resource if a classloader
|
||||
* is given.
|
||||
*/
|
||||
beanLocation =
|
||||
(cl == null)
|
||||
? ClassLoader.getSystemResource(resourceName + ".ser")
|
||||
: cl.getResource(resourceName + ".ser");
|
||||
|
||||
// Reads the serialized Bean from the returned URL.
|
||||
if (beanLocation != null)
|
||||
{
|
||||
// Deserializes the bean instance.
|
||||
ObjectInputStream ois =
|
||||
(cl == null)
|
||||
? new ObjectInputStream(beanLocation.openStream())
|
||||
: new ClassLoaderObjectInputStream(
|
||||
beanLocation.openStream(),
|
||||
cl);
|
||||
|
||||
bean = ois.readObject();
|
||||
}
|
||||
else
|
||||
{
|
||||
ClassLoaderObjectInputStream ois =
|
||||
new ClassLoaderObjectInputStream (serStream, cl);
|
||||
bean = ois.readObject();
|
||||
}
|
||||
}
|
||||
else if(cl == null)
|
||||
{
|
||||
Class beanClass = Class.forName(beanName);
|
||||
try
|
||||
{
|
||||
bean = beanClass.newInstance();
|
||||
}
|
||||
catch(IllegalAccessException E)
|
||||
{
|
||||
bean = null;
|
||||
}
|
||||
catch(InstantiationException E)
|
||||
{
|
||||
bean = null;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Class beanClass = cl.loadClass(beanName);
|
||||
try
|
||||
{
|
||||
bean = beanClass.newInstance();
|
||||
}
|
||||
catch(IllegalAccessException E)
|
||||
{
|
||||
bean = null;
|
||||
}
|
||||
catch(InstantiationException E)
|
||||
{
|
||||
bean = null;
|
||||
}
|
||||
}
|
||||
|
||||
if(bean instanceof Applet)
|
||||
{
|
||||
Applet a = (Applet)bean;
|
||||
//a.setAppletContext(???);
|
||||
//a.setStub(???);
|
||||
if(serStream == null)
|
||||
{
|
||||
a.init();
|
||||
}
|
||||
}
|
||||
/* Implementation note: The result of ObjectInputStream.readObject()
|
||||
* may have been null at this point (its a valid value to deserialize)
|
||||
* and we explicitly want to try instantiation in such a case
|
||||
* (this is important for compatibility).
|
||||
*/
|
||||
}
|
||||
|
||||
return bean;
|
||||
}
|
||||
// Instantiates the Bean using reflective instantiation if it has not been created yet.
|
||||
if (bean == null)
|
||||
{
|
||||
// Makes sure that the deserialization was NOT done.
|
||||
beanLocation = null;
|
||||
|
||||
/**
|
||||
* Get the Bean as a different class type.
|
||||
* This should be used instead of casting to get a new
|
||||
* type view of a Bean, because in the future there may
|
||||
* be new types of Bean, even Beans spanning multiple
|
||||
* Objects.
|
||||
*
|
||||
* @param bean the Bean to cast.
|
||||
* @param newClass the Class to cast it to.
|
||||
*
|
||||
* @return the Bean as a new view, or if the operation
|
||||
* could not be performed, the Bean itself.
|
||||
*/
|
||||
public static Object getInstanceOf(Object bean, Class newClass)
|
||||
{
|
||||
return bean;
|
||||
}
|
||||
Class beanClass;
|
||||
if (cl == null)
|
||||
{
|
||||
beanClass = Class.forName(beanName);
|
||||
classLocation =
|
||||
ClassLoader.getSystemResource(resourceName + ".class");
|
||||
}
|
||||
else
|
||||
{
|
||||
beanClass = cl.loadClass(beanName);
|
||||
classLocation = cl.getResource(resourceName + ".class");
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine whether the Bean can be cast to a different
|
||||
* class type.
|
||||
* This should be used instead of instanceof to determine
|
||||
* a Bean's castability, because in the future there may
|
||||
* be new types of Bean, even Beans spanning multiple
|
||||
* Objects.
|
||||
*
|
||||
* @param bean the Bean to cast.
|
||||
* @param newBeanClass the Class to cast it to.
|
||||
*
|
||||
* @return whether the Bean can be cast to the class type
|
||||
* in question.
|
||||
*/
|
||||
public static boolean isInstanceOf(Object bean, Class newBeanClass)
|
||||
{
|
||||
return newBeanClass.isInstance(bean);
|
||||
}
|
||||
// Instantiates and optionally registers the new bean.
|
||||
try
|
||||
{
|
||||
bean = beanClass.newInstance();
|
||||
}
|
||||
catch(Exception e) {
|
||||
/* Wraps all kinds of Exceptions in a ClassNotFoundException (this behavior
|
||||
* matches with official >= 1.5, this was different for <=1.4)
|
||||
*/
|
||||
throw new ClassNotFoundException(null, e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Find out whether the GUI is available to use.
|
||||
* Defaults to true.
|
||||
*
|
||||
* @return whether the GUI is available to use.
|
||||
*/
|
||||
public static boolean isGuiAvailable()
|
||||
{
|
||||
return guiAvailable;
|
||||
}
|
||||
/* Applet beans are treated in the following way:
|
||||
* - all AppletS get a default AppletStub
|
||||
* - all AppletS are initialized using the AppletInitializer instance (if it is available)
|
||||
* - as every other Bean Applets are added to a BeanContext if one is available
|
||||
* - each instantiated Applet is initialized using Applet.init() (this is not done for deserialized ones)
|
||||
* - finally AppletS get activated using the AppletInitializerS activate-Method
|
||||
*
|
||||
* The order of operations is important for compatibility.
|
||||
*/
|
||||
Applet applet = null;
|
||||
if (bean instanceof Applet)
|
||||
{
|
||||
// Makes a second instanceof call unneccessary (instanceof is expensive).
|
||||
applet = (Applet) bean;
|
||||
|
||||
/**
|
||||
* Find out whether it is design time. Design time means
|
||||
* we are in a RAD tool.
|
||||
* Defaults to false.
|
||||
*
|
||||
* @return whether it is design time.
|
||||
*/
|
||||
public static boolean isDesignTime()
|
||||
{
|
||||
return designTime;
|
||||
}
|
||||
/* The AppletStub's code and document base is set as follows:
|
||||
* The code base is always the URL from where the class data originated
|
||||
* (without the package name).
|
||||
* If the Applet was deserialized the document base is the location of
|
||||
* the serialized instance (usually the ".ser" file) otherwise its the URL
|
||||
* from where the class data originated (usually the absolute directory
|
||||
* location of the ".class" file).
|
||||
*/
|
||||
applet.setStub(
|
||||
new DummyAppletStub(
|
||||
applet
|
||||
.getClass()
|
||||
.getProtectionDomain()
|
||||
.getCodeSource()
|
||||
.getLocation(),
|
||||
(beanLocation == null) ? classLocation : beanLocation));
|
||||
|
||||
/**
|
||||
* Set whether the GUI is available to use.
|
||||
* @param guiAvailable whether the GUI is available to use.
|
||||
*/
|
||||
public static void setGuiAvailable(boolean guiAvailable)
|
||||
throws SecurityException
|
||||
{
|
||||
Beans.guiAvailable = guiAvailable;
|
||||
}
|
||||
// Runs the Applet's initialization using an AppletInitializer.
|
||||
if (initializer != null)
|
||||
{
|
||||
initializer.initialize(applet, beanContext);
|
||||
}
|
||||
}
|
||||
|
||||
// Adds the new bean to its BeanContext.
|
||||
if (beanContext != null)
|
||||
{
|
||||
beanContext.add(bean);
|
||||
}
|
||||
|
||||
if (applet != null)
|
||||
{
|
||||
|
||||
// Initializes an instantiated (not deserialized) Applet using its own method.
|
||||
if (beanLocation == null)
|
||||
{
|
||||
applet.init();
|
||||
}
|
||||
|
||||
// Runs the Applet's activation using an AppletInitializer.
|
||||
if (initializer != null)
|
||||
{
|
||||
initializer.activate(applet);
|
||||
}
|
||||
}
|
||||
|
||||
return bean;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the Bean as a different class type.
|
||||
* This should be used instead of casting to get a new
|
||||
* type view of a Bean, because in the future there may
|
||||
* be new types of Bean, even Beans spanning multiple
|
||||
* Objects.
|
||||
*
|
||||
* @param bean the Bean to cast.
|
||||
* @param newClass the Class to cast it to.
|
||||
*
|
||||
* @return the Bean as a new view, or if the operation
|
||||
* could not be performed, the Bean itself.
|
||||
*/
|
||||
public static Object getInstanceOf(Object bean, Class newClass)
|
||||
{
|
||||
return bean;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines whether the Bean can be cast to a different
|
||||
* class type.
|
||||
* This should be used instead of instanceof to determine
|
||||
* a Bean's castability, because in the future there may
|
||||
* be new types of Bean, even Beans spanning multiple
|
||||
* Objects.
|
||||
*
|
||||
* @param bean the Bean to cast.
|
||||
* @param newClass the Class to cast it to.
|
||||
*
|
||||
* @return whether the Bean can be cast to the class type
|
||||
* in question.
|
||||
*/
|
||||
public static boolean isInstanceOf(Object bean, Class newBeanClass)
|
||||
{
|
||||
return newBeanClass.isInstance(bean);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the GUI is available to use.
|
||||
* <p>Defaults to true.</p>
|
||||
*
|
||||
* @return whether the GUI is available to use.
|
||||
*/
|
||||
public static boolean isGuiAvailable()
|
||||
{
|
||||
return guiAvailable;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether it is design time. Design time means
|
||||
* we are in a RAD tool.
|
||||
* <p>Defaults to false.</p>
|
||||
*
|
||||
* @return whether it is design time.
|
||||
*/
|
||||
public static boolean isDesignTime()
|
||||
{
|
||||
return designTime;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets whether the GUI is available to use.
|
||||
*
|
||||
* @param guiAvailable whether the GUI is available to use.
|
||||
*/
|
||||
public static void setGuiAvailable(boolean guiAvailable)
|
||||
throws SecurityException
|
||||
{
|
||||
Beans.guiAvailable = guiAvailable;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets whether it is design time. Design time means we
|
||||
* are in a RAD tool.
|
||||
*
|
||||
* @param designTime whether it is design time.
|
||||
*/
|
||||
public static void setDesignTime(boolean designTime)
|
||||
throws SecurityException
|
||||
{
|
||||
Beans.designTime = designTime;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set whether it is design time. Design time means we
|
||||
* are in a RAD tool.
|
||||
*
|
||||
* @param designTime whether it is design time.
|
||||
*/
|
||||
public static void setDesignTime(boolean designTime)
|
||||
throws SecurityException
|
||||
{
|
||||
Beans.designTime = designTime;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,307 @@
|
||||
/* java.beans.XMLDecoder --
|
||||
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., 59 Temple Place, Suite 330, Boston, MA
|
||||
02111-1307 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.decoder.DefaultExceptionListener;
|
||||
import gnu.java.beans.decoder.PersistenceParser;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.Iterator;
|
||||
import java.util.NoSuchElementException;
|
||||
|
||||
/**
|
||||
* The XMLDecoder reads XML data that is structured according to
|
||||
* <a href="http://java.sun.com/products/jfc/tsc/articles/persistence3/javabeans.dtd">this</a> DTD
|
||||
* and creates objects according to the content. Usually such data is generated using the
|
||||
* {@link XMLEncoder} class.
|
||||
* <p>
|
||||
* An example XML document might look like this:
|
||||
* <code>
|
||||
* <java>
|
||||
* <string>Hello World</string>
|
||||
* <int>200</int>
|
||||
* </java>
|
||||
* </code>
|
||||
* <p>To read the <code>String</code> and the <code>Integer</code> instance the following can be used (assume
|
||||
* the XML data can be obtained from the InputStream):</p>
|
||||
* <code>
|
||||
* XMLDecoder decoder = new XMLDecoder(inputStreamContainingXMLData);
|
||||
* String message = (String) decoder.readObject();
|
||||
* Integer number = (Integer) decoder.readObject();
|
||||
* </code>
|
||||
* <p>Besides this basic functionality the <code>XMLDecoder</code> has some more features that might come
|
||||
* handy in certain situations:</p>
|
||||
* <p>An owner object can be set using the <code>setOwner</code> method which can then be accessed when
|
||||
* decoding. This feature is only useful if the XML data is aware of the owner object. Such data may
|
||||
* look like this (assume that the owner object is a JFrame instance):</p>
|
||||
* <code>
|
||||
* <java>
|
||||
* <void method="getOwner">
|
||||
* <void method="setVisible">
|
||||
* <boolean>true<boolean>
|
||||
* </void>
|
||||
* </void>
|
||||
* </java>
|
||||
* </code>
|
||||
* This accesses the <code>JFrame</code> and makes it visible using the <code>setVisible</code> method.
|
||||
* <p>Please note that changing the owner <b>after</b> the having read the first object has no effect,
|
||||
* because all object have been decoded then.</p>
|
||||
* <p>If the <code>XMLDecoder</code> is created with no {@link ExceptionListener} instance a default one
|
||||
* is used that prints an error message to <code>System.err</code> whenever a recoverable exception
|
||||
* is thrown. Recovarable exceptions occur when the XML data cannot be interpreted correctly (e.g
|
||||
* unknown classes or methods, invocation on null, ...). In general be very careful when the
|
||||
* <code>XMLDecoder</code> provoked such exceptions because the resulting object(s) may be in an
|
||||
* undesirable state.</p>
|
||||
* <p>Note that changing the ExceptionListener instance after <code>readObject</code> has been called
|
||||
* once has no effect because the decoding is completed then.</p>
|
||||
* <p>At last one can provide a specific <code>ClassLoader</code> which is then used when <code>Class</code>
|
||||
* objects are accessed. See {@link java.lang.Class#forName(String, boolean, ClassLoader)} for details
|
||||
* on this.</p>
|
||||
* <p>Note: If the <code>InputStream</code> instance given to any of the constructors is <code>null</code>
|
||||
* the resulting <code>XMLDecoder</code> will be silently (without any exception) useless. Each call
|
||||
* to <code>readObject</code> will return <code>null</code> and never throws an
|
||||
* <code>ArrayIndexOutOfBoundsException</code>.</p>
|
||||
*
|
||||
* @author Robert Schuster
|
||||
* @since 1.4
|
||||
* @status updated to 1.5
|
||||
*/
|
||||
public class XMLDecoder
|
||||
{
|
||||
private Object owner;
|
||||
|
||||
private ExceptionListener exceptionListener;
|
||||
|
||||
private InputStream inputStream;
|
||||
|
||||
private boolean isStreamClosed;
|
||||
|
||||
private ClassLoader classLoader;
|
||||
|
||||
private Iterator iterator;
|
||||
|
||||
/** Creates a XMLDecoder instance that parses the XML data of the given input stream.
|
||||
* Using this constructor no special ClassLoader, a default ExceptionListener
|
||||
* and no owner object is used.
|
||||
*
|
||||
* @param in InputStream to read XML data from.
|
||||
*/
|
||||
public XMLDecoder(InputStream in)
|
||||
{
|
||||
this(in, null);
|
||||
}
|
||||
|
||||
/** Creates a XMLDecoder instance that parses the XML data of the given input stream.
|
||||
* Using this constructor no special ClassLoader and a default ExceptionListener
|
||||
* is used.
|
||||
*
|
||||
* @param in InputStream to read XML data from.
|
||||
* @param owner Owner object which can be accessed and modified while parsing.
|
||||
*/
|
||||
public XMLDecoder(InputStream in, Object owner)
|
||||
{
|
||||
this(in, owner, null);
|
||||
}
|
||||
|
||||
/** Creates a XMLDecoder instance that parses the XML data of the given input stream.
|
||||
* If the ExceptionListener argument is null a default implementation is used.
|
||||
*
|
||||
* @param in InputStream to read XML data from.
|
||||
* @param owner Owner object which can be accessed and modified while parsing.
|
||||
* @param exceptionListener ExceptionListener instance to which exception notifications are send.
|
||||
*/
|
||||
public XMLDecoder(
|
||||
InputStream in,
|
||||
Object owner,
|
||||
ExceptionListener exceptionListener)
|
||||
{
|
||||
this(
|
||||
in,
|
||||
owner,
|
||||
exceptionListener,
|
||||
Thread.currentThread().getContextClassLoader());
|
||||
}
|
||||
|
||||
/** Creates a XMLDecoder instance that parses the XML data of the given input stream.
|
||||
* If the ExceptionListener argument is null a default implementation is used.
|
||||
*
|
||||
* @param in InputStream to read XML data from.
|
||||
* @param owner Owner object which can be accessed and modified while parsing.
|
||||
* @param exceptionListener ExceptionListener instance to which exception notifications are send.
|
||||
* @param cl ClassLoader instance that is used for calls to <code>Class.forName(String, boolean, ClassLoader)</code>
|
||||
* @since 1.5
|
||||
*/
|
||||
public XMLDecoder(
|
||||
InputStream in,
|
||||
Object owner,
|
||||
ExceptionListener listener,
|
||||
ClassLoader cl)
|
||||
{
|
||||
// initially here was a check for the validity of the InputStream argument but some
|
||||
// great engineers decided that this API should silently discard this and behave rather
|
||||
// odd: readObject will always return null ...
|
||||
inputStream = in;
|
||||
|
||||
setExceptionListener(listener);
|
||||
|
||||
// validity of this object is checked in Class.forName() and therefore may be null
|
||||
classLoader = cl;
|
||||
|
||||
this.owner = owner;
|
||||
}
|
||||
|
||||
/** Closes the stream associated with this decoder. This should be done after having read all
|
||||
* decoded objects.
|
||||
* <p>See the description of the {@link #readObject()} for the effect caused by <code>close</code>.</p>
|
||||
*/
|
||||
public void close()
|
||||
{
|
||||
if (isStreamClosed)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
inputStream.close();
|
||||
isStreamClosed = true;
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
// bad style forced by original API design ...
|
||||
}
|
||||
}
|
||||
|
||||
/** Returns the ExceptionListener instance associated with this decoder.
|
||||
* <p>See the description of {@link XMLDecoder} class for more information on the ExceptionListener.</p>
|
||||
*
|
||||
* @return Current ExceptionListener of the decoder.
|
||||
*/
|
||||
public ExceptionListener getExceptionListener()
|
||||
{
|
||||
return exceptionListener;
|
||||
}
|
||||
|
||||
/** Returns the owner object of the decoder. This method is usually called
|
||||
* from within the parsed XML data.
|
||||
* <p>See the description of {@link XMLDecoder} class for more information on the owner object.</p>
|
||||
*
|
||||
* @return The owner object of this decoder.
|
||||
*/
|
||||
public Object getOwner()
|
||||
{
|
||||
return owner;
|
||||
}
|
||||
|
||||
/** Returns the next available decoded object.
|
||||
* <p>Note that the actual decoding takes place when the method is called for the first time.</p>
|
||||
* <p>If the <code>close</code> method was already called a <code>NoSuchElementException</code>
|
||||
* is thrown.</p>
|
||||
* <p>If the InputStream instance used in the constructors was <code>null</code> this method
|
||||
* will always return <code>null</code> itself.</p>
|
||||
*
|
||||
* @return The next object in a sequence decoded from XML data.
|
||||
* @throws ArrayIndexOutOfBoundsException When no more objects are available.
|
||||
*/
|
||||
public Object readObject() throws ArrayIndexOutOfBoundsException
|
||||
{
|
||||
// note: the RI does it this way ...
|
||||
if(inputStream == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// note: the original API documentation says nothing on what to do
|
||||
// when the stream was closed before readObject is called but it actually
|
||||
// throws a NoSuchElementException - this behaviour is imitated here
|
||||
if (isStreamClosed)
|
||||
{
|
||||
throw new NoSuchElementException("Cannot read any objects - XMLDecoder was already closed.");
|
||||
}
|
||||
|
||||
// creates the PersistenceParser (doing the parsing and decoding) and returns its
|
||||
// Iterator on first invocation
|
||||
if (iterator == null)
|
||||
{
|
||||
iterator =
|
||||
new PersistenceParser(
|
||||
inputStream,
|
||||
exceptionListener,
|
||||
classLoader,
|
||||
this)
|
||||
.iterator();
|
||||
}
|
||||
|
||||
// note: done according to the official documentation
|
||||
if (!iterator.hasNext())
|
||||
{
|
||||
throw new ArrayIndexOutOfBoundsException("No more objects available from this XMLDecoder.");
|
||||
}
|
||||
|
||||
// returns just the next object if there was no problem
|
||||
return iterator.next();
|
||||
}
|
||||
|
||||
/** Sets the ExceptionListener instance to which notifications of exceptions are send
|
||||
* while parsing the XML data.
|
||||
* <p>See the description of {@link XMLDecoder} class for more information on the ExceptionListener.</p>
|
||||
*
|
||||
* @param listener
|
||||
*/
|
||||
public void setExceptionListener(ExceptionListener listener)
|
||||
{
|
||||
// uses a default implementation when null
|
||||
if (listener == null)
|
||||
{
|
||||
listener = new DefaultExceptionListener();
|
||||
}
|
||||
exceptionListener = listener;
|
||||
}
|
||||
|
||||
/** Sets the owner object which can be accessed from the parsed XML data.
|
||||
* <p>See the description of {@link XMLDecoder} class for more information on the owner object.</p>
|
||||
*
|
||||
* @param newOwner
|
||||
*/
|
||||
public void setOwner(Object newOwner)
|
||||
{
|
||||
owner = newOwner;
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user