You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@geode.apache.org by kl...@apache.org on 2016/05/17 00:04:36 UTC
[1/3] incubator-geode git commit: Minor fixes
Repository: incubator-geode
Updated Branches:
refs/heads/feature/GEODE-1392 f3f8a81a9 -> 95e2e8317
Minor fixes
Project: http://git-wip-us.apache.org/repos/asf/incubator-geode/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-geode/commit/e19a278e
Tree: http://git-wip-us.apache.org/repos/asf/incubator-geode/tree/e19a278e
Diff: http://git-wip-us.apache.org/repos/asf/incubator-geode/diff/e19a278e
Branch: refs/heads/feature/GEODE-1392
Commit: e19a278ebcc6df8dbf99815482f625fdfebf74ba
Parents: f3f8a81
Author: Kirk Lund <kl...@pivotal.io>
Authored: Mon May 16 13:39:46 2016 -0700
Committer: Kirk Lund <kl...@pivotal.io>
Committed: Mon May 16 13:39:46 2016 -0700
----------------------------------------------------------------------
.../gemfire/internal/util/BlobHelper.java | 72 ++++++--------------
1 file changed, 21 insertions(+), 51 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/e19a278e/geode-core/src/main/java/com/gemstone/gemfire/internal/util/BlobHelper.java
----------------------------------------------------------------------
diff --git a/geode-core/src/main/java/com/gemstone/gemfire/internal/util/BlobHelper.java b/geode-core/src/main/java/com/gemstone/gemfire/internal/util/BlobHelper.java
index 28252c3..a2ba434 100644
--- a/geode-core/src/main/java/com/gemstone/gemfire/internal/util/BlobHelper.java
+++ b/geode-core/src/main/java/com/gemstone/gemfire/internal/util/BlobHelper.java
@@ -14,7 +14,6 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-
package com.gemstone.gemfire.internal.util;
import java.io.IOException;
@@ -26,19 +25,17 @@ import com.gemstone.gemfire.internal.ByteArrayDataInput;
import com.gemstone.gemfire.internal.DSCODE;
import com.gemstone.gemfire.internal.HeapDataOutputStream;
import com.gemstone.gemfire.internal.Version;
-import com.gemstone.gemfire.internal.cache.GemFireCacheImpl;
import com.gemstone.gemfire.internal.offheap.StoredObject;
import com.gemstone.gemfire.internal.offheap.annotations.Unretained;
import com.gemstone.gemfire.pdx.internal.PdxInputStream;
/**
* A "blob" is a serialized representation of an object into a byte[].
- * BlobHelper provides utility methods for
- * serializing and deserializing the object.
- *
- *
+ * BlobHelper provides utility methods for serializing and deserializing the
+ * object.
+ *
+ * TODO: compare performance with org.apache.commons.lang.SerializationUtils
*/
-
public class BlobHelper {
/**
@@ -50,12 +47,10 @@ public class BlobHelper {
}
/**
- * A blob is a serialized Object. This method serializes the
- * object into a blob and returns the byte array that contains the blob.
+ * A blob is a serialized Object. This method serializes the object into a
+ * blob and returns the byte array that contains the blob.
*/
- public static byte[] serializeToBlob(Object obj, Version version)
- throws IOException
- {
+ public static byte[] serializeToBlob(Object obj, Version version) throws IOException {
final long start = startSerialization();
HeapDataOutputStream hdos = new HeapDataOutputStream(version);
DataSerializer.writeObject(obj, hdos);
@@ -65,45 +60,32 @@ public class BlobHelper {
}
/**
- * A blob is a serialized Object. This method serializes the
- * object into the given HeapDataOutputStream.
+ * A blob is a serialized Object. This method serializes the object into
+ * the given HeapDataOutputStream.
*/
- public static void serializeTo(Object obj, HeapDataOutputStream hdos)
- throws IOException
- {
+ public static void serializeTo(Object obj, HeapDataOutputStream hdos) throws IOException {
final int startBytes = hdos.size();
final long start = startSerialization();
DataSerializer.writeObject(obj, hdos);
endSerialization(start, hdos.size()-startBytes);
}
-
-
/**
- * A blob is a serialized Object. This method
- * returns the deserialized object.
+ * A blob is a serialized Object. This method returns the deserialized
+ * object.
*/
- public static Object deserializeBlob(byte[] blob) throws IOException,
- ClassNotFoundException {
+ public static Object deserializeBlob(byte[] blob) throws IOException, ClassNotFoundException {
return deserializeBlob(blob, null, null);
}
/**
- * A blob is a serialized Object. This method
- * returns the deserialized object.
+ * A blob is a serialized Object. This method returns the deserialized
+ * object.
*/
- public static Object deserializeBlob(byte[] blob, Version version,
- ByteArrayDataInput in) throws IOException, ClassNotFoundException {
+ public static Object deserializeBlob(byte[] blob, Version version, ByteArrayDataInput in) throws IOException, ClassNotFoundException {
Object result;
final long start = startDeserialization();
- /*
- final StaticSystemCallbacks sysCb;
- if (version != null && (sysCb = GemFireCacheImpl.FactoryStatics
- .systemCallbacks) != null) {
- // may need to change serialized shape for SQLFire
- result = sysCb.fromVersion(blob, true, version, in);
- }
- else*/ if (blob.length > 0 && blob[0] == DSCODE.PDX) {
+ if (blob.length > 0 && blob[0] == DSCODE.PDX) {
// If the first byte of blob indicates a pdx then wrap
// blob in a PdxInputStream instead.
// This will prevent us from making a copy of the byte[]
@@ -121,24 +103,13 @@ public class BlobHelper {
result = DataSerializer.readObject(in);
}
endDeserialization(start, blob.length);
- // this causes a small performance drop in d-no-ack performance tests
-// if (dis.available() != 0) {
-// LogWriterI18n lw = InternalDistributedSystem.getLoggerI18n();
-// if (lw != null && lw.warningEnabled()) {
-// lw.warning(
-// LocalizedStrings.BlobHelper_DESERIALIZATION_OF_A_0_DID_NOT_READ_1_BYTES_THIS_INDICATES_A_LOGIC_ERROR_IN_THE_SERIALIZATION_CODE_FOR_THIS_CLASS,
-// new Object[] {((result!=null) ? result.getClass().getName() : "NULL"), Integer.valueOf(dis.available())});
-//
-// }
-// }
return result;
}
/**
- * A blob is a serialized Object. This method
- * returns the deserialized object.
- * If a PdxInstance is returned then it will refer to Chunk's off-heap memory
- * with an unretained reference.
+ * A blob is a serialized Object. This method returns the deserialized
+ * object. If a PdxInstance is returned then it will refer to Chunk's
+ * off-heap memory with an unretained reference.
*/
public static @Unretained Object deserializeOffHeapBlob(StoredObject blob) throws IOException, ClassNotFoundException {
Object result;
@@ -152,8 +123,7 @@ public class BlobHelper {
return result;
}
- public static Object deserializeBuffer(ByteArrayDataInput in, int numBytes)
- throws IOException, ClassNotFoundException {
+ public static Object deserializeBuffer(ByteArrayDataInput in, int numBytes) throws IOException, ClassNotFoundException {
final long start = startDeserialization();
Object result = DataSerializer.readObject(in);
endDeserialization(start, numBytes);
[3/3] incubator-geode git commit: Implement unit test
Posted by kl...@apache.org.
Implement unit test
Project: http://git-wip-us.apache.org/repos/asf/incubator-geode/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-geode/commit/95e2e831
Tree: http://git-wip-us.apache.org/repos/asf/incubator-geode/tree/95e2e831
Diff: http://git-wip-us.apache.org/repos/asf/incubator-geode/diff/95e2e831
Branch: refs/heads/feature/GEODE-1392
Commit: 95e2e831793442f9bba0990c4e97eba44017f7cd
Parents: 837512e
Author: Kirk Lund <kl...@pivotal.io>
Authored: Mon May 16 17:04:36 2016 -0700
Committer: Kirk Lund <kl...@pivotal.io>
Committed: Mon May 16 17:04:36 2016 -0700
----------------------------------------------------------------------
.../gemfire/internal/util/BlobHelper.java | 3 +
.../gemfire/internal/util/BlobHelperTest.java | 154 +++++++++++++++++++
2 files changed, 157 insertions(+)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/95e2e831/geode-core/src/main/java/com/gemstone/gemfire/internal/util/BlobHelper.java
----------------------------------------------------------------------
diff --git a/geode-core/src/main/java/com/gemstone/gemfire/internal/util/BlobHelper.java b/geode-core/src/main/java/com/gemstone/gemfire/internal/util/BlobHelper.java
index a2ba434..45f9774 100644
--- a/geode-core/src/main/java/com/gemstone/gemfire/internal/util/BlobHelper.java
+++ b/geode-core/src/main/java/com/gemstone/gemfire/internal/util/BlobHelper.java
@@ -123,6 +123,9 @@ public class BlobHelper {
return result;
}
+ /**
+ * Unused
+ */
public static Object deserializeBuffer(ByteArrayDataInput in, int numBytes) throws IOException, ClassNotFoundException {
final long start = startDeserialization();
Object result = DataSerializer.readObject(in);
http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/95e2e831/geode-core/src/test/java/com/gemstone/gemfire/internal/util/BlobHelperTest.java
----------------------------------------------------------------------
diff --git a/geode-core/src/test/java/com/gemstone/gemfire/internal/util/BlobHelperTest.java b/geode-core/src/test/java/com/gemstone/gemfire/internal/util/BlobHelperTest.java
new file mode 100644
index 0000000..85e04f6
--- /dev/null
+++ b/geode-core/src/test/java/com/gemstone/gemfire/internal/util/BlobHelperTest.java
@@ -0,0 +1,154 @@
+package com.gemstone.gemfire.internal.util;
+
+import static com.gemstone.gemfire.internal.util.BlobHelper.*;
+import static org.assertj.core.api.Assertions.*;
+
+import java.io.EOFException;
+import java.io.NotSerializableException;
+import java.io.ObjectInputStream;
+import java.io.Serializable;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.experimental.categories.Category;
+
+import com.gemstone.gemfire.DataSerializer;
+import com.gemstone.gemfire.internal.HeapDataOutputStream;
+import com.gemstone.gemfire.test.junit.categories.UnitTest;
+
+/**
+ * Unit Tests for {@link BlobHelper}.
+ */
+@Category(UnitTest.class)
+public class BlobHelperTest {
+
+ private static final int HDOS_ALLOC_SIZE = 32;
+
+ private static final String CLASS_NOT_FOUND_MESSAGE = "ClassNotFoundSerialization.readObject fake exception";
+
+ private Map<Object, Object> mapWithTwoEntries;
+
+ private byte[] bytesOfClassNotFoundSerialization;
+ private byte[] bytesOfMap;
+ private byte[] bytesOfNull;
+ private byte[] zeroBytes;
+
+ @Before
+ public void setUp() throws Exception {
+ this.mapWithTwoEntries = new HashMap<>();
+ this.mapWithTwoEntries.put("FOO", "foo");
+ this.mapWithTwoEntries.put("BAR", 7);
+
+ HeapDataOutputStream hdos = createHeapDataOutputStream();
+ DataSerializer.writeObject(new ClassNotFoundSerialization(), hdos);
+ this.bytesOfClassNotFoundSerialization = hdos.toByteArray();
+
+ hdos = createHeapDataOutputStream();
+ DataSerializer.writeObject(this.mapWithTwoEntries, hdos);
+ this.bytesOfMap = hdos.toByteArray();
+
+ this.bytesOfNull = serializeToBlob(null);
+
+ this.zeroBytes = new byte[0];
+ }
+
+ @Test
+ public void deserializeBlobOfClassNotFoundSerializationThrowsEOFException() throws Exception {
+ assertThatThrownBy(() -> deserializeBlob(this.bytesOfClassNotFoundSerialization)).isExactlyInstanceOf(ClassNotFoundException.class);
+ }
+
+ @Test
+ public void deserializeBlobOfMapReturnsCopyOfMap() throws Exception {
+ final Object object = deserializeBlob(this.bytesOfMap);
+
+ assertThat(object).isNotNull();
+ assertThat(object).isExactlyInstanceOf(HashMap.class);
+ assertThat(object).isNotSameAs(this.mapWithTwoEntries);
+ assertThat(object).isEqualTo(this.mapWithTwoEntries);
+ }
+
+ @Test
+ public void deserializeBlobOfNullReturnsNull() throws Exception {
+ assertThat(deserializeBlob(this.bytesOfNull)).isNull();
+ }
+
+ @Test
+ public void deserializeBlobOfZeroBytesThrowsEOFException() throws Exception {
+ assertThatThrownBy(() -> deserializeBlob(this.zeroBytes)).isExactlyInstanceOf(EOFException.class);
+ }
+
+ @Test
+ public void deserializeBlobWithNullThrowsNullPointerException() throws Exception {
+ assertThatThrownBy(() -> deserializeBlob(null)).isExactlyInstanceOf(NullPointerException.class);
+ }
+
+ @Test
+ public void serializeMapToStreamWritesMapAsBytes() throws Exception {
+ HeapDataOutputStream hdos = createHeapDataOutputStream();
+
+ serializeTo(this.mapWithTwoEntries, hdos);
+
+ assertThat(hdos.toByteArray()).isNotNull().isEqualTo(bytesOfMap);
+ }
+
+ @Test
+ public void serializeNullToStreamWritesNullAsBytes() throws Exception {
+ HeapDataOutputStream hdos = createHeapDataOutputStream();
+
+ serializeTo(null, hdos);
+
+ assertThat(hdos.toByteArray()).isNotNull().isEqualTo(this.bytesOfNull);
+ }
+
+ @Test
+ public void serializeToBlobMapReturnsBytesOfMap() throws Exception {
+ byte[] bytes = serializeToBlob(this.mapWithTwoEntries);
+
+ assertThat(bytes).isNotNull().isEqualTo(this.bytesOfMap);
+ }
+
+ @Test
+ public void serializeToBlobUnserializableThrowsNotSerializableException() throws Exception {
+ assertThatThrownBy(() -> serializeToBlob(new Object()))
+ .isExactlyInstanceOf(NotSerializableException.class)
+ .hasMessage(Object.class.getName());
+ }
+
+ @Test
+ public void serializeToBlobWithNullReturnsBytesOfNull() throws Exception {
+ byte[] bytes = serializeToBlob(null);
+
+ assertThat(bytes).isNotNull().isEqualTo(this.bytesOfNull);
+ }
+
+ @Test
+ public void serializeToNullNullThrowsNullPointerException() throws Exception {
+ assertThatThrownBy(() -> serializeTo(null, null)).isExactlyInstanceOf(NullPointerException.class);
+ }
+
+ @Test
+ public void serializeToNullStreamThrowsNullPointerException() throws Exception {
+ assertThatThrownBy(() -> serializeTo(this.mapWithTwoEntries, null)).isExactlyInstanceOf(NullPointerException.class);
+ }
+
+ @Test
+ public void serializeUnserializableToStreamThrowsNotSerializableException() throws Exception {
+ HeapDataOutputStream hdos = createHeapDataOutputStream();
+
+ assertThatThrownBy(() -> serializeTo(new Object(), hdos))
+ .isExactlyInstanceOf(NotSerializableException.class)
+ .hasMessage(Object.class.getName());
+ }
+
+ private HeapDataOutputStream createHeapDataOutputStream() {
+ return new HeapDataOutputStream(HDOS_ALLOC_SIZE, null, true);
+ }
+
+ private static class ClassNotFoundSerialization implements Serializable {
+ private void readObject(final ObjectInputStream in) throws ClassNotFoundException {
+ throw new ClassNotFoundException(CLASS_NOT_FOUND_MESSAGE);
+ }
+ }
+}
[2/3] incubator-geode git commit: Rename to
BlobHelperWithThreadContextClassLoaderTest
Posted by kl...@apache.org.
Rename to BlobHelperWithThreadContextClassLoaderTest
Project: http://git-wip-us.apache.org/repos/asf/incubator-geode/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-geode/commit/837512e4
Tree: http://git-wip-us.apache.org/repos/asf/incubator-geode/tree/837512e4
Diff: http://git-wip-us.apache.org/repos/asf/incubator-geode/diff/837512e4
Branch: refs/heads/feature/GEODE-1392
Commit: 837512e4782579d086f2dcb02d944b534c6f106b
Parents: e19a278
Author: Kirk Lund <kl...@pivotal.io>
Authored: Mon May 16 13:44:31 2016 -0700
Committer: Kirk Lund <kl...@pivotal.io>
Committed: Mon May 16 13:44:31 2016 -0700
----------------------------------------------------------------------
.../gemfire/internal/util/BlobHelperTest.java | 299 -------------------
...bHelperWithThreadContextClassLoaderTest.java | 299 +++++++++++++++++++
2 files changed, 299 insertions(+), 299 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/837512e4/geode-core/src/test/java/com/gemstone/gemfire/internal/util/BlobHelperTest.java
----------------------------------------------------------------------
diff --git a/geode-core/src/test/java/com/gemstone/gemfire/internal/util/BlobHelperTest.java b/geode-core/src/test/java/com/gemstone/gemfire/internal/util/BlobHelperTest.java
deleted file mode 100644
index d7a876e..0000000
--- a/geode-core/src/test/java/com/gemstone/gemfire/internal/util/BlobHelperTest.java
+++ /dev/null
@@ -1,299 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.gemstone.gemfire.internal.util;
-
-import static org.assertj.core.api.Assertions.assertThat;
-import static org.junit.Assert.*;
-
-import java.io.IOException;
-import java.io.Serializable;
-import java.lang.reflect.Constructor;
-import java.lang.reflect.Method;
-import java.net.MalformedURLException;
-import java.net.URL;
-import java.util.Enumeration;
-import java.util.HashMap;
-import java.util.Map;
-
-import org.apache.bcel.Constants;
-import org.apache.bcel.classfile.Field;
-import org.apache.bcel.classfile.JavaClass;
-import org.apache.bcel.generic.ClassGen;
-import org.apache.bcel.generic.ConstantPoolGen;
-import org.apache.bcel.generic.FieldGen;
-import org.apache.bcel.generic.InstructionFactory;
-import org.apache.bcel.generic.InstructionHandle;
-import org.apache.bcel.generic.InstructionList;
-import org.apache.bcel.generic.MethodGen;
-import org.apache.bcel.generic.Type;
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.experimental.categories.Category;
-
-import com.gemstone.gemfire.test.junit.categories.UnitTest;
-
-/**
- * Unit tests for {@link BlobHelper}.
- *
- * @since 2.0.2
- */
-@Category(UnitTest.class)
-public class BlobHelperTest {
-
- private static final String CLASS_NAME_SERIALIZABLE_IMPL = "com.gemstone.gemfire.internal.util.SerializableImpl";
- private static final String CLASS_NAME_SERIALIZABLE_IMPL_WITH_VALUE = "com.gemstone.gemfire.internal.util.SerializableImplWithValue";
- private static final String VALUE = "value";
- private static final String SET_VALUE = "setValue";
- private static final String GET_VALUE = "getValue";
-
- private ClassLoader oldCCL;
-
- @Before
- public void setUp() throws MalformedURLException {
- this.oldCCL = Thread.currentThread().getContextClassLoader();
- Thread.currentThread().setContextClassLoader(new GeneratingClassLoader(this.oldCCL));
- }
-
- @After
- public void tearDown() {
- Thread.currentThread().setContextClassLoader(this.oldCCL);
- }
-
- @Test
- public void thisTestGeneratesSerializableImpl() throws Exception {
- Class loadedClass = Class.forName(CLASS_NAME_SERIALIZABLE_IMPL, true, Thread.currentThread().getContextClassLoader());
- assertThat(loadedClass).isNotNull();
- assertThat(loadedClass.getName()).isEqualTo(CLASS_NAME_SERIALIZABLE_IMPL);
-
- Object instance = loadedClass.newInstance();
- assertThat(instance).isNotNull();
- assertThat(Serializable.class.isInstance(loadedClass));
- assertThat(loadedClass.getInterfaces()).contains(Serializable.class);
- }
-
- @Test
- public void thisTestGeneratesSerializableImplWithValue() throws Exception {
- Class loadedClass = Class.forName(CLASS_NAME_SERIALIZABLE_IMPL_WITH_VALUE, true, Thread.currentThread().getContextClassLoader());
- assertThat(loadedClass).isNotNull();
- assertThat(loadedClass.getName()).isEqualTo(CLASS_NAME_SERIALIZABLE_IMPL_WITH_VALUE);
-
- Object instance = loadedClass.newInstance();
- assertThat(instance).isNotNull();
-
- assertThat(loadedClass.getSuperclass().getName()).isEqualTo(CLASS_NAME_SERIALIZABLE_IMPL);
- assertThat(Serializable.class.isInstance(loadedClass));
-
- assertThat(Valuable.class.isInstance(loadedClass));
- assertThat(loadedClass.getInterfaces()).contains(Valuable.class);
-
- Method setter = loadedClass.getMethod("setValue", Object.class);
- assertThat(setter).isNotNull();
- }
-
- /**
- * Tests serializing an object loaded with the current context class
- * loader (whose parent is the loader that loads GemFire and test
- * classes).
- */
- @Test
- public void serializesAndDeserializesClassFromOtherClassLoader() throws Exception {
- Class loadedClass = Class.forName(CLASS_NAME_SERIALIZABLE_IMPL, true, Thread.currentThread().getContextClassLoader());
-
- Object instance = loadedClass.newInstance();
- byte[] bytes = BlobHelper.serializeToBlob(instance);
-
- Object object = BlobHelper.deserializeBlob(bytes);
-
- assertThat(object).isNotNull();
- assertThat(object.getClass().getName()).isEqualTo(CLASS_NAME_SERIALIZABLE_IMPL);
- assertThat(Serializable.class.isInstance(object));
-
- Class deserializedClass = object.getClass();
- assertThat(deserializedClass.getInterfaces()).contains(Serializable.class);
- }
-
- /**
- * Tests that the deserialized object has the correct state
- */
- @Test
- public void serializesAndDeserializesObjectWithState() throws Exception {
- Class loadedClass = Class.forName(CLASS_NAME_SERIALIZABLE_IMPL_WITH_VALUE, true, Thread.currentThread().getContextClassLoader());
-
- Constructor ctor = loadedClass.getConstructor(new Class[] {Object.class});
- Valuable instance = (Valuable) ctor.newInstance(new Object[] {123});
- assertThat(instance.getValue()).isEqualTo(123);
-
- byte[] bytes = BlobHelper.serializeToBlob(instance);
-
- Valuable object = (Valuable) BlobHelper.deserializeBlob(bytes);
- assertEquals(instance.getValue(), object.getValue());
- assertThat(object.getValue()).isEqualTo(instance.getValue());
- }
-
- /**
- * Custom class loader which uses BCEL to dynamically generate SerializableImpl or SerializableImplWithValue.
- */
- private static class GeneratingClassLoader extends ClassLoader {
-
- private static final String GENERATED = "<generated>";
-
- private final Map<String, Class<?>> classDefinitions;
-
- public GeneratingClassLoader(ClassLoader parent) {
- super(parent);
- this.classDefinitions = new HashMap<>();
- }
-
- public GeneratingClassLoader() {
- this(null); // no parent
- }
-
- @Override
- protected Class<?> findClass(String name) throws ClassNotFoundException {
- Class<?> definedClass = null;
- synchronized (this.classDefinitions) {
- definedClass = getClass(name);
- if (definedClass == null) {
- definedClass = generate(name);
- this.classDefinitions.put(name, definedClass);
- }
- }
- return definedClass;
- }
-
- @Override
- protected URL findResource(String name) {
- return null;
- }
-
- @Override
- protected Enumeration<URL> findResources(String name) throws IOException {
- return null;
- }
-
- private Class<?> generate(String name) throws ClassNotFoundException {
- if (CLASS_NAME_SERIALIZABLE_IMPL.equals(name)) {
- return generateSerializableImpl();
- } else if (CLASS_NAME_SERIALIZABLE_IMPL_WITH_VALUE.equals(name)) {
- return generateSerializableImplWithValue();
- } else {
- return null;
- //throw new Error("Unable to generate " + name);
- }
- }
-
- /**
- * <pre>
- * public class SerializableImpl implements Serializable {
- *
- * public SerializableImpl() {
- * }
- *
- * }
- * </pre>
- */
- private Class<?> generateSerializableImpl() throws ClassNotFoundException {
- ClassGen cg = new ClassGen(CLASS_NAME_SERIALIZABLE_IMPL, Object.class.getName(), GENERATED, Constants.ACC_PUBLIC | Constants.ACC_SUPER, new String[] {Serializable.class.getName()});
- cg.addEmptyConstructor(Constants.ACC_PUBLIC);
- JavaClass jClazz = cg.getJavaClass();
- byte[] bytes = jClazz.getBytes();
- return defineClass(jClazz.getClassName(), bytes, 0, bytes.length);
- }
-
- /**
- * <pre>
- * public class SerializableImplWithValue extends SerializableImpl implements Valuable {
- *
- * private Object value;
- *
- * public SerializableImplWithValue() {
- * }
- *
- * public SerializableImplWithValue(Object value) {
- * this.value = value;
- * }
- *
- * public Object getValue() {
- * return this.value;
- * }
- *
- * public void setValue(Object value) {
- * this.value = value;
- * }
- * }
- * </pre>
- *
- * @see Valuable
- */
- private Class<?> generateSerializableImplWithValue() throws ClassNotFoundException {
- ClassGen cg = new ClassGen(CLASS_NAME_SERIALIZABLE_IMPL_WITH_VALUE, CLASS_NAME_SERIALIZABLE_IMPL, GENERATED, Constants.ACC_PUBLIC | Constants.ACC_SUPER, new String[] {Valuable.class.getName()});
- ConstantPoolGen cp = cg.getConstantPool();
- InstructionFactory fac = new InstructionFactory(cg, cp);
-
- // constructor
- cg.addEmptyConstructor(Constants.ACC_PUBLIC);
-
- // field
- FieldGen fg = new FieldGen(Constants.ACC_PRIVATE, Type.OBJECT, VALUE, cp);
- Field field = fg.getField();
- cg.addField(field);
-
- // setter
- // 0: aload_0
- // 1: aload_1
- // 2: putfield #2; //Field value:Ljava/lang/Object;
- // 5: return
- InstructionList setter = new InstructionList();
- MethodGen setterMethod = new MethodGen(Constants.ACC_PUBLIC, Type.VOID, new Type[] {Type.OBJECT}, new String[] {field.getName()}, SET_VALUE, CLASS_NAME_SERIALIZABLE_IMPL_WITH_VALUE, setter, cp);
- setterMethod.setMaxStack(2);
-
- InstructionHandle setter_ih_0 = setter.append(fac.createLoad(Type.OBJECT, 0)); // 0: aload_0 this
- InstructionHandle setter_ih_1 = setter.append(fac.createLoad(Type.OBJECT, 1)); // 1: aload_1 value
- InstructionHandle setter_ih_2 = setter.append(fac.createPutField(cg.getClassName(), field.getName(), Type.getType(field.getSignature()))); // 2: putfield #2 stack to field
- InstructionHandle setter_ih_0_ih_5 = setter.append(fac.createReturn(Type.VOID)); // 5: return void
-
- cg.addMethod(setterMethod.getMethod());
- setter.dispose();
-
- // getter
- // 0: aload_0
- // 1: getfield #2; //Field value:Ljava/lang/Object;
- // 4: areturn
- InstructionList getter = new InstructionList();
- MethodGen getterMethod = new MethodGen(Constants.ACC_PUBLIC, Type.OBJECT, null, null, GET_VALUE, CLASS_NAME_SERIALIZABLE_IMPL_WITH_VALUE, getter, cp);
- getterMethod.setMaxStack(1);
-
- InstructionHandle getter_ih_0 = getter.append(fac.createLoad(Type.OBJECT, 0)); // 0: aload_0 this
- InstructionHandle getter_ih_1 = getter.append(fac.createGetField(cg.getClassName(), field.getName(), Type.getType(field.getSignature()))); // 1: getfield #2 field to stack
- InstructionHandle getter_ih_4 = getter.append(fac.createReturn(Type.OBJECT)); // 4: areturn Object
-
- cg.addMethod(getterMethod.getMethod());
- getter.dispose();
-
- JavaClass jClazz = cg.getJavaClass();
- byte[] bytes = jClazz.getBytes();
- return defineClass(jClazz.getClassName(), bytes, 0, bytes.length);
- }
-
- private Class<?> getClass(String name) {
- synchronized (this.classDefinitions) {
- return this.classDefinitions.get(name);
- }
- }
- }
-}
http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/837512e4/geode-core/src/test/java/com/gemstone/gemfire/internal/util/BlobHelperWithThreadContextClassLoaderTest.java
----------------------------------------------------------------------
diff --git a/geode-core/src/test/java/com/gemstone/gemfire/internal/util/BlobHelperWithThreadContextClassLoaderTest.java b/geode-core/src/test/java/com/gemstone/gemfire/internal/util/BlobHelperWithThreadContextClassLoaderTest.java
new file mode 100644
index 0000000..f7a90d3
--- /dev/null
+++ b/geode-core/src/test/java/com/gemstone/gemfire/internal/util/BlobHelperWithThreadContextClassLoaderTest.java
@@ -0,0 +1,299 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.gemstone.gemfire.internal.util;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.junit.Assert.*;
+
+import java.io.IOException;
+import java.io.Serializable;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Method;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.apache.bcel.Constants;
+import org.apache.bcel.classfile.Field;
+import org.apache.bcel.classfile.JavaClass;
+import org.apache.bcel.generic.ClassGen;
+import org.apache.bcel.generic.ConstantPoolGen;
+import org.apache.bcel.generic.FieldGen;
+import org.apache.bcel.generic.InstructionFactory;
+import org.apache.bcel.generic.InstructionHandle;
+import org.apache.bcel.generic.InstructionList;
+import org.apache.bcel.generic.MethodGen;
+import org.apache.bcel.generic.Type;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.experimental.categories.Category;
+
+import com.gemstone.gemfire.test.junit.categories.UnitTest;
+
+/**
+ * Unit tests for {@link BlobHelper} with Thread Context ClassLoader.
+ *
+ * @since 2.0.2
+ */
+@Category(UnitTest.class)
+public class BlobHelperWithThreadContextClassLoaderTest {
+
+ private static final String CLASS_NAME_SERIALIZABLE_IMPL = "com.gemstone.gemfire.internal.util.SerializableImpl";
+ private static final String CLASS_NAME_SERIALIZABLE_IMPL_WITH_VALUE = "com.gemstone.gemfire.internal.util.SerializableImplWithValue";
+ private static final String VALUE = "value";
+ private static final String SET_VALUE = "setValue";
+ private static final String GET_VALUE = "getValue";
+
+ private ClassLoader oldCCL;
+
+ @Before
+ public void setUp() throws MalformedURLException {
+ this.oldCCL = Thread.currentThread().getContextClassLoader();
+ Thread.currentThread().setContextClassLoader(new GeneratingClassLoader(this.oldCCL));
+ }
+
+ @After
+ public void tearDown() {
+ Thread.currentThread().setContextClassLoader(this.oldCCL);
+ }
+
+ @Test
+ public void tcclLoadsSerializableImpl() throws Exception {
+ Class loadedClass = Class.forName(CLASS_NAME_SERIALIZABLE_IMPL, true, Thread.currentThread().getContextClassLoader());
+ assertThat(loadedClass).isNotNull();
+ assertThat(loadedClass.getName()).isEqualTo(CLASS_NAME_SERIALIZABLE_IMPL);
+
+ Object instance = loadedClass.newInstance();
+ assertThat(instance).isNotNull();
+ assertThat(Serializable.class.isInstance(loadedClass));
+ assertThat(loadedClass.getInterfaces()).contains(Serializable.class);
+ }
+
+ @Test
+ public void tcclLoadsSerializableImplWithValue() throws Exception {
+ Class loadedClass = Class.forName(CLASS_NAME_SERIALIZABLE_IMPL_WITH_VALUE, true, Thread.currentThread().getContextClassLoader());
+ assertThat(loadedClass).isNotNull();
+ assertThat(loadedClass.getName()).isEqualTo(CLASS_NAME_SERIALIZABLE_IMPL_WITH_VALUE);
+
+ Object instance = loadedClass.newInstance();
+ assertThat(instance).isNotNull();
+
+ assertThat(loadedClass.getSuperclass().getName()).isEqualTo(CLASS_NAME_SERIALIZABLE_IMPL);
+ assertThat(Serializable.class.isInstance(loadedClass));
+
+ assertThat(Valuable.class.isInstance(loadedClass));
+ assertThat(loadedClass.getInterfaces()).contains(Valuable.class);
+
+ Method setter = loadedClass.getMethod("setValue", Object.class);
+ assertThat(setter).isNotNull();
+ }
+
+ /**
+ * Tests serializing an object loaded with the current context class
+ * loader (whose parent is the loader that loads GemFire and test
+ * classes).
+ */
+ @Test
+ public void serializesAndDeserializesClassFromOtherClassLoader() throws Exception {
+ Class loadedClass = Class.forName(CLASS_NAME_SERIALIZABLE_IMPL, true, Thread.currentThread().getContextClassLoader());
+
+ Object instance = loadedClass.newInstance();
+ byte[] bytes = BlobHelper.serializeToBlob(instance);
+
+ Object object = BlobHelper.deserializeBlob(bytes);
+
+ assertThat(object).isNotNull();
+ assertThat(object.getClass().getName()).isEqualTo(CLASS_NAME_SERIALIZABLE_IMPL);
+ assertThat(Serializable.class.isInstance(object));
+
+ Class deserializedClass = object.getClass();
+ assertThat(deserializedClass.getInterfaces()).contains(Serializable.class);
+ }
+
+ /**
+ * Tests that the deserialized object has the correct state
+ */
+ @Test
+ public void serializesAndDeserializesObjectWithState() throws Exception {
+ Class loadedClass = Class.forName(CLASS_NAME_SERIALIZABLE_IMPL_WITH_VALUE, true, Thread.currentThread().getContextClassLoader());
+
+ Constructor ctor = loadedClass.getConstructor(new Class[] {Object.class});
+ Valuable instance = (Valuable) ctor.newInstance(new Object[] {123});
+ assertThat(instance.getValue()).isEqualTo(123);
+
+ byte[] bytes = BlobHelper.serializeToBlob(instance);
+
+ Valuable object = (Valuable) BlobHelper.deserializeBlob(bytes);
+ assertEquals(instance.getValue(), object.getValue());
+ assertThat(object.getValue()).isEqualTo(instance.getValue());
+ }
+
+ /**
+ * Custom class loader which uses BCEL to dynamically generate SerializableImpl or SerializableImplWithValue.
+ */
+ private static class GeneratingClassLoader extends ClassLoader {
+
+ private static final String GENERATED = "<generated>";
+
+ private final Map<String, Class<?>> classDefinitions;
+
+ public GeneratingClassLoader(ClassLoader parent) {
+ super(parent);
+ this.classDefinitions = new HashMap<>();
+ }
+
+ public GeneratingClassLoader() {
+ this(null); // no parent
+ }
+
+ @Override
+ protected Class<?> findClass(String name) throws ClassNotFoundException {
+ Class<?> definedClass = null;
+ synchronized (this.classDefinitions) {
+ definedClass = getClass(name);
+ if (definedClass == null) {
+ definedClass = generate(name);
+ this.classDefinitions.put(name, definedClass);
+ }
+ }
+ return definedClass;
+ }
+
+ @Override
+ protected URL findResource(String name) {
+ return null;
+ }
+
+ @Override
+ protected Enumeration<URL> findResources(String name) throws IOException {
+ return null;
+ }
+
+ private Class<?> generate(String name) throws ClassNotFoundException {
+ if (CLASS_NAME_SERIALIZABLE_IMPL.equals(name)) {
+ return generateSerializableImpl();
+ } else if (CLASS_NAME_SERIALIZABLE_IMPL_WITH_VALUE.equals(name)) {
+ return generateSerializableImplWithValue();
+ } else {
+ return null;
+ //throw new Error("Unable to generate " + name);
+ }
+ }
+
+ /**
+ * <pre>
+ * public class SerializableImpl implements Serializable {
+ *
+ * public SerializableImpl() {
+ * }
+ *
+ * }
+ * </pre>
+ */
+ private Class<?> generateSerializableImpl() throws ClassNotFoundException {
+ ClassGen cg = new ClassGen(CLASS_NAME_SERIALIZABLE_IMPL, Object.class.getName(), GENERATED, Constants.ACC_PUBLIC | Constants.ACC_SUPER, new String[] {Serializable.class.getName()});
+ cg.addEmptyConstructor(Constants.ACC_PUBLIC);
+ JavaClass jClazz = cg.getJavaClass();
+ byte[] bytes = jClazz.getBytes();
+ return defineClass(jClazz.getClassName(), bytes, 0, bytes.length);
+ }
+
+ /**
+ * <pre>
+ * public class SerializableImplWithValue extends SerializableImpl implements Valuable {
+ *
+ * private Object value;
+ *
+ * public SerializableImplWithValue() {
+ * }
+ *
+ * public SerializableImplWithValue(Object value) {
+ * this.value = value;
+ * }
+ *
+ * public Object getValue() {
+ * return this.value;
+ * }
+ *
+ * public void setValue(Object value) {
+ * this.value = value;
+ * }
+ * }
+ * </pre>
+ *
+ * @see Valuable
+ */
+ private Class<?> generateSerializableImplWithValue() throws ClassNotFoundException {
+ ClassGen cg = new ClassGen(CLASS_NAME_SERIALIZABLE_IMPL_WITH_VALUE, CLASS_NAME_SERIALIZABLE_IMPL, GENERATED, Constants.ACC_PUBLIC | Constants.ACC_SUPER, new String[] {Valuable.class.getName()});
+ ConstantPoolGen cp = cg.getConstantPool();
+ InstructionFactory fac = new InstructionFactory(cg, cp);
+
+ // constructor
+ cg.addEmptyConstructor(Constants.ACC_PUBLIC);
+
+ // field
+ FieldGen fg = new FieldGen(Constants.ACC_PRIVATE, Type.OBJECT, VALUE, cp);
+ Field field = fg.getField();
+ cg.addField(field);
+
+ // setter
+ // 0: aload_0
+ // 1: aload_1
+ // 2: putfield #2; //Field value:Ljava/lang/Object;
+ // 5: return
+ InstructionList setter = new InstructionList();
+ MethodGen setterMethod = new MethodGen(Constants.ACC_PUBLIC, Type.VOID, new Type[] {Type.OBJECT}, new String[] {field.getName()}, SET_VALUE, CLASS_NAME_SERIALIZABLE_IMPL_WITH_VALUE, setter, cp);
+ setterMethod.setMaxStack(2);
+
+ InstructionHandle setter_ih_0 = setter.append(fac.createLoad(Type.OBJECT, 0)); // 0: aload_0 this
+ InstructionHandle setter_ih_1 = setter.append(fac.createLoad(Type.OBJECT, 1)); // 1: aload_1 value
+ InstructionHandle setter_ih_2 = setter.append(fac.createPutField(cg.getClassName(), field.getName(), Type.getType(field.getSignature()))); // 2: putfield #2 stack to field
+ InstructionHandle setter_ih_0_ih_5 = setter.append(fac.createReturn(Type.VOID)); // 5: return void
+
+ cg.addMethod(setterMethod.getMethod());
+ setter.dispose();
+
+ // getter
+ // 0: aload_0
+ // 1: getfield #2; //Field value:Ljava/lang/Object;
+ // 4: areturn
+ InstructionList getter = new InstructionList();
+ MethodGen getterMethod = new MethodGen(Constants.ACC_PUBLIC, Type.OBJECT, null, null, GET_VALUE, CLASS_NAME_SERIALIZABLE_IMPL_WITH_VALUE, getter, cp);
+ getterMethod.setMaxStack(1);
+
+ InstructionHandle getter_ih_0 = getter.append(fac.createLoad(Type.OBJECT, 0)); // 0: aload_0 this
+ InstructionHandle getter_ih_1 = getter.append(fac.createGetField(cg.getClassName(), field.getName(), Type.getType(field.getSignature()))); // 1: getfield #2 field to stack
+ InstructionHandle getter_ih_4 = getter.append(fac.createReturn(Type.OBJECT)); // 4: areturn Object
+
+ cg.addMethod(getterMethod.getMethod());
+ getter.dispose();
+
+ JavaClass jClazz = cg.getJavaClass();
+ byte[] bytes = jClazz.getBytes();
+ return defineClass(jClazz.getClassName(), bytes, 0, bytes.length);
+ }
+
+ private Class<?> getClass(String name) {
+ synchronized (this.classDefinitions) {
+ return this.classDefinitions.get(name);
+ }
+ }
+ }
+}