Author: julien(a)jboss.com
Date: 2008-03-04 08:26:22 -0500 (Tue, 04 Mar 2008)
New Revision: 10190
Added:
modules/common/trunk/common/src/test/java/org/jboss/portal/test/common/io/SerializableCloneTestCase.java
Modified:
modules/common/trunk/common/pom.xml
modules/common/trunk/common/src/main/java/org/jboss/portal/common/io/IOTools.java
Log:
improve the IOTools.clone() to work with a specified classloader
Modified: modules/common/trunk/common/pom.xml
===================================================================
--- modules/common/trunk/common/pom.xml 2008-03-04 03:47:25 UTC (rev 10189)
+++ modules/common/trunk/common/pom.xml 2008-03-04 13:26:22 UTC (rev 10190)
@@ -112,8 +112,6 @@
export MAVEN_OPTS="-Xdebug -Xnoagent -Djava.compiler=NONE
-Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000"
-->
<!--
- <forkMode>never</forkMode>
- <argLine>-enableassertions</argLine>
-->
<forkMode>never</forkMode>
<argLine>-enableassertions</argLine>
Modified:
modules/common/trunk/common/src/main/java/org/jboss/portal/common/io/IOTools.java
===================================================================
---
modules/common/trunk/common/src/main/java/org/jboss/portal/common/io/IOTools.java 2008-03-04
03:47:25 UTC (rev 10189)
+++
modules/common/trunk/common/src/main/java/org/jboss/portal/common/io/IOTools.java 2008-03-04
13:26:22 UTC (rev 10190)
@@ -40,8 +40,7 @@
import java.io.ObjectInputStream;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
-import java.io.DataOutputStream;
-import java.util.Map;
+import java.io.ObjectStreamClass;
/**
* IO tools.
@@ -341,20 +340,16 @@
/**
* Clone an object implementing the <code>Serializable</code> interface.
*
- * @param serializable
- * @return
+ * @param serializable the serializable object to clone
+ * @return a clone
* @throws IllegalArgumentException if the serializable object is null
- * @throws IOException
+ * @throws IOException any IOException
*/
public static <S extends Serializable> S clone(S serializable) throws
IllegalArgumentException, IOException
{
- if (serializable == null)
- {
- throw new IllegalArgumentException("Cannot clone null");
- }
try
{
- return (S)unserialize(serialize(serializable));
+ return clone(serializable, null);
}
catch (ClassNotFoundException e)
{
@@ -362,6 +357,33 @@
}
}
+ /**
+ * Clone an object implementing the <code>Serializable</code> interface.
The specified classloader will be used
+ * to perform the unserialization. If no classloader is specified and the object is
not null then the classloader
+ * used is the one returned by
<code>serializable.getClass().getClassLoader()</code>.
+ *
+ * @param serializable the serializable object to clone
+ * @return a clone
+ * @throws IllegalArgumentException if the serializable object is null
+ * @throws IOException any IOException
+ */
+ public static <S extends Serializable> S clone(S serializable, ClassLoader
classLoader) throws IllegalArgumentException, IOException, ClassNotFoundException
+ {
+ if (serializable == null)
+ {
+ throw new IllegalArgumentException("Cannot clone null");
+ }
+
+ //
+ if (classLoader == null && serializable != null)
+ {
+ classLoader = serializable.getClass().getClassLoader();
+ }
+
+ //
+ return (S)unserialize(serialize(serializable), classLoader);
+ }
+
public static byte[] serialize(Serializable serializable) throws
IllegalArgumentException, IOException
{
if (serializable == null)
@@ -375,14 +397,76 @@
return baos.toByteArray();
}
+ /**
+ * Unserialize the bytes into an object. The thread context classloader is used to
perform unserialization.
+ *
+ * @param bytes the bytes to unserialize
+ * @return the unserialized object
+ * @throws IllegalArgumentException if the byte array is null
+ * @throws IOException any IOException
+ * @throws ClassNotFoundException any ClassNotFoundException
+ */
public static Serializable unserialize(byte[] bytes) throws IllegalArgumentException,
IOException, ClassNotFoundException
{
+ return unserialize(bytes, null);
+ }
+
+ /**
+ * Unserialize the bytes into an object. If the provided classloader is not null, this
classloader is used to perform
+ * the unserialization otherwise the thread current context classloader is used.
+ *
+ * @param bytes the bytes to unserialize
+ * @param classLoader the classloader
+ * @return the unserialized object
+ * @throws IllegalArgumentException if the byte array is null
+ * @throws IOException any IOException
+ * @throws ClassNotFoundException any ClassNotFoundException
+ */
+ public static Serializable unserialize(byte[] bytes, final ClassLoader classLoader)
throws IllegalArgumentException, IOException, ClassNotFoundException
+ {
if (bytes == null)
{
throw new IllegalArgumentException("No null serializable accepted");
}
+
+ //
ByteArrayInputStream bais = new ByteArrayInputStream(bytes);
- ObjectInputStream ois = new ObjectInputStream(bais);
+ ObjectInputStream ois = new ObjectInputStream(bais)
+ {
+ protected Class<?> resolveClass(ObjectStreamClass desc) throws
IOException, ClassNotFoundException
+ {
+ if (classLoader == null)
+ {
+ return super.resolveClass(desc);
+ }
+ else
+ {
+ String className = desc.getName();
+
+ // JDK 6, by default, only supports array types (ex. [[B) using
Class.forName()
+ return Class.forName(className, false, classLoader);
+ }
+ }
+
+ protected Class resolveProxyClass(String[] interfaces) throws IOException,
ClassNotFoundException
+ {
+ if (classLoader == null)
+ {
+ return super.resolveProxyClass(interfaces);
+ }
+ else
+ {
+ // Load the interfaces from the specified class loader
+ Class[] ifaceClasses = new Class[interfaces.length];
+ for (int i = 0; i < interfaces.length; i++)
+ {
+ ifaceClasses[i] = classLoader.loadClass(interfaces[i]);
+ }
+
+ return java.lang.reflect.Proxy.getProxyClass(classLoader, ifaceClasses);
+ }
+ }
+ };
return (Serializable)ois.readObject();
}
Added:
modules/common/trunk/common/src/test/java/org/jboss/portal/test/common/io/SerializableCloneTestCase.java
===================================================================
---
modules/common/trunk/common/src/test/java/org/jboss/portal/test/common/io/SerializableCloneTestCase.java
(rev 0)
+++
modules/common/trunk/common/src/test/java/org/jboss/portal/test/common/io/SerializableCloneTestCase.java 2008-03-04
13:26:22 UTC (rev 10190)
@@ -0,0 +1,110 @@
+/******************************************************************************
+ * JBoss, a division of Red Hat *
+ * Copyright 2008, Red Hat Middleware, LLC, and individual *
+ * contributors as indicated by the @authors tag. See the *
+ * copyright.txt in the distribution for a full listing of *
+ * individual contributors. *
+ * *
+ * This is free software; you can redistribute it and/or modify it *
+ * under the terms of the GNU Lesser General Public License as *
+ * published by the Free Software Foundation; either version 2.1 of *
+ * the License, or (at your option) any later version. *
+ * *
+ * This software 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 *
+ * Lesser General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU Lesser General Public *
+ * License along with this software; if not, write to the Free *
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA *
+ * 02110-1301 USA, or see the FSF site:
http://www.fsf.org. *
+ ******************************************************************************/
+package org.jboss.portal.test.common.io;
+
+import junit.framework.TestCase;
+import org.jboss.portal.common.io.IOTools;
+
+import java.io.Serializable;
+import java.io.IOException;
+import java.io.InputStream;
+
+/**
+ * @author <a href="mailto:julien@jboss.org">Julien Viet</a>
+ * @version $Revision: 630 $
+ */
+public class SerializableCloneTestCase extends TestCase
+{
+
+ public static class Foo implements Serializable
+ {
+ }
+
+ public void testA() throws IOException, ClassNotFoundException
+ {
+ Foo foo = new Foo();
+ ClassLoader fooCL = new FooClassLoader();
+ Class fooClass = fooCL.loadClass(Foo.class.getName());
+ assertNotSame(fooClass, Foo.class);
+
+ //
+ Object clone = IOTools.clone(foo, fooCL);
+ assertSame(fooClass, clone.getClass());
+ }
+
+ private static class FooClassLoader extends ClassLoader
+ {
+
+ /** . */
+ private final byte[] bytes;
+
+ /** . */
+ private Class fooClass;
+
+ private FooClassLoader() throws IOException
+ {
+ InputStream in =
Foo.class.getClassLoader().getResourceAsStream(Foo.class.getName().replace('.',
'/') + ".class");
+ bytes = IOTools.getBytes(in);
+ }
+
+ public Class<?> loadClass(String name, boolean resolve) throws
ClassNotFoundException
+ {
+ if (Foo.class.getName().equals(name))
+ {
+ Class<?> fooClass = findClass(name);
+
+ //
+ if (resolve)
+ {
+ resolveClass(fooClass);
+ }
+
+ //
+ return fooClass;
+ }
+ else
+ {
+ return super.loadClass(name, resolve);
+ }
+ }
+
+ protected Class<?> findClass(String name) throws ClassNotFoundException
+ {
+ if (Foo.class.getName().equals(name))
+ {
+ if (fooClass == null)
+ {
+ fooClass = defineClass(name, bytes, 0, bytes.length);
+ }
+
+ //
+ return fooClass;
+ }
+ else
+ {
+ return super.findClass(name);
+ }
+ }
+ }
+
+}