提交 1f1691b6 authored 作者: Thomas Mueller's avatar Thomas Mueller

Issue 180: when deserializing objects, the context class loader is used instead…

Issue 180: when deserializing objects, the context class loader is used instead of the default class loader if the system property "h2.useThreadContextClassLoader" is set. Thanks a lot to Noah Fontes for the patch!
上级 75a8ee0f
......@@ -19,7 +19,12 @@ Change Log
<h1>Change Log</h1>
<h2>Next Version (unreleased)</h2>
<ul><li>The optimization for "group by" was not working correctly if the group by column
<ul><li>Issue 180: when deserializing objects, the context class loader is used
instead of the default class loader if the system property "h2.useThreadContextClassLoader" is set.
Thanks a lot to Noah Fontes for the patch!
</li><li>When using the exclusive mode, LOB operations could cause the thread to freeze.
This also affected the CreateCluster tool (when using BLOB or CLOB data).
</li><li>The optimization for "group by" was not working correctly if the group by column
was aliased in the select list.
</li><li>Issue 326: improved support for case sensitive (mixed case) identifiers
without quotes when using DATABASE_TO_UPPER=FALSE.
......
......@@ -377,6 +377,13 @@ public class SysProperties {
*/
public static final String URL_MAP = Utils.getProperty("h2.urlMap", null);
/**
* System property <code>h2.useThreadContextClassLoader</code> (default: false).<br />
* Instead of using the default class loader when deserializing objects,
* the current thread-context class loader will be used.
*/
public static final boolean USE_THREAD_CONTEXT_CLASS_LOADER = Utils.getProperty("h2.useThreadContextClassLoader", false);
/**
* System property <code>h2.webMaxValueLength</code> (default: 100000).<br />
* The H2 Console will abbreviate (truncate) result values larger than this size.
......
......@@ -12,6 +12,7 @@ import java.io.IOException;
import java.io.InputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.ObjectStreamClass;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
......@@ -250,7 +251,21 @@ public class Utils {
public static Object deserialize(byte[] data) {
try {
ByteArrayInputStream in = new ByteArrayInputStream(data);
ObjectInputStream is = new ObjectInputStream(in);
ObjectInputStream is;
if (SysProperties.USE_THREAD_CONTEXT_CLASS_LOADER) {
final ClassLoader loader = Thread.currentThread().getContextClassLoader();
is = new ObjectInputStream(in) {
protected Class<?> resolveClass(ObjectStreamClass desc) throws IOException, ClassNotFoundException {
try {
return Class.forName(desc.getName(), true, loader);
} catch (ClassNotFoundException e) {
return super.resolveClass(desc);
}
}
};
} else {
is = new ObjectInputStream(in);
}
return is.readObject();
} catch (Throwable e) {
throw DbException.get(ErrorCode.DESERIALIZATION_FAILED_1, e, e.toString());
......
......@@ -137,6 +137,7 @@ import org.h2.test.unit.TestFtp;
import org.h2.test.unit.TestIntArray;
import org.h2.test.unit.TestIntIntHashMap;
import org.h2.test.unit.TestJmx;
import org.h2.test.unit.TestObjectDeserialization;
import org.h2.test.unit.TestTraceSystem;
import org.h2.test.unit.TestMathUtils;
import org.h2.test.unit.TestNetUtils;
......@@ -338,6 +339,7 @@ java org.h2.test.TestAll timer
System.setProperty("h2.check2", "true");
System.setProperty("h2.delayWrongPasswordMin", "0");
System.setProperty("h2.delayWrongPasswordMax", "0");
System.setProperty("h2.useThreadContextClassLoader", "true");
// System.setProperty("h2.storeLocalTime", "true");
......@@ -668,6 +670,7 @@ kill -9 `jps -l | grep "org.h2.test." | cut -d " " -f 1`
new TestMathUtils().runTest(this);
new TestOldVersion().runTest(this);
new TestNetUtils().runTest(this);
new TestObjectDeserialization().runTest(this);
new TestMultiThreadedKernel().runTest(this);
new TestOverflow().runTest(this);
new TestPageStore().runTest(this);
......
/*
* Copyright 2004-2011 H2 Group. Multiple-Licensed under the H2 License,
* Version 1.0, and under the Eclipse Public License, Version 1.0
* (http://h2database.com/html/license.html).
* Initial Developer: Noah Fontes <nfontes@invectorate.com>
*/
package org.h2.test.unit;
import org.h2.message.DbException;
import org.h2.test.TestBase;
import org.h2.util.StringUtils;
import org.h2.util.Utils;
/**
* Tests the ability to deserialize objects that are not part of the system class-
* loading scope.
*/
public class TestObjectDeserialization extends TestBase {
private static final String CLAZZ = "org.h2.test.unit.SampleObject";
private static final String OBJECT = "aced00057372001d6f72672e68322e746573742e756e69742e53616d706c654f626a65637400000000000000010200007870";
protected boolean usesThreadContextClassLoader;
/**
* Run just this test.
*
* @param a ignored
*/
public static void main(String... a) throws Exception {
System.setProperty("h2.useThreadContextClassLoader", "true");
TestBase.createCaller().init().test();
}
public void test() throws Exception {
testThreadContextClassLoader();
}
private void testThreadContextClassLoader() throws Exception {
Thread.currentThread().setContextClassLoader(new TestClassLoader());
try {
Utils.deserialize(StringUtils.convertHexToBytes(OBJECT));
fail();
} catch (DbException e) {
// expected
}
assertTrue(usesThreadContextClassLoader);
}
/**
* A special class loader.
*/
private class TestClassLoader extends ClassLoader {
public TestClassLoader() {
super();
}
protected synchronized Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException {
if (name.equals(CLAZZ)) {
usesThreadContextClassLoader = true;
}
return super.loadClass(name, resolve);
}
}
}
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论