You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ignite.apache.org by sd...@apache.org on 2022/01/19 12:04:04 UTC
[ignite-3] branch main updated: IGNITE-16258 Support Serializable lambdas marshalling in User Object Serialization
This is an automated email from the ASF dual-hosted git repository.
sdanilov pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/ignite-3.git
The following commit(s) were added to refs/heads/main by this push:
new 4f8f7ae IGNITE-16258 Support Serializable lambdas marshalling in User Object Serialization
4f8f7ae is described below
commit 4f8f7aef8b475381cd23bc2865a3986472679d40
Author: Roman Puchkovskiy <ro...@gmail.com>
AuthorDate: Wed Jan 19 16:03:56 2022 +0400
IGNITE-16258 Support Serializable lambdas marshalling in User Object Serialization
---
.../network/serialization/BuiltInType.java | 3 +-
.../SpecialSerializationMethodsImpl.java | 94 ++++++++---------
.../marshal/BuiltInContainerMarshallers.java | 2 +-
.../serialization/marshal/BuiltInMarshalling.java | 44 ++++----
.../marshal/BuiltInNonContainerMarshallers.java | 1 +
.../network/serialization/marshal/Classes.java} | 30 +++++-
.../marshal/DefaultUserObjectMarshaller.java | 8 +-
.../marshal/MarshallingNotSupportedException.java} | 11 +-
...iptorsTest.java => BuiltInDescriptorsTest.java} | 6 +-
.../network/serialization/marshal/ClassesTest.java | 101 ++++++++++++++++++
...erObjectMarshallerWithArbitraryObjectsTest.java | 116 +++++++++++----------
...efaultUserObjectMarshallerWithBuiltinsTest.java | 10 +-
.../marshal/NoArgConstructorInstantiationTest.java | 2 +-
...=> NonSerializableWithoutNoArgConstructor.java} | 4 +-
.../marshal/UnsafeInstantiationTest.java | 4 +-
15 files changed, 286 insertions(+), 150 deletions(-)
diff --git a/modules/network/src/main/java/org/apache/ignite/internal/network/serialization/BuiltInType.java b/modules/network/src/main/java/org/apache/ignite/internal/network/serialization/BuiltInType.java
index 56f6f2b..e0a5de8 100644
--- a/modules/network/src/main/java/org/apache/ignite/internal/network/serialization/BuiltInType.java
+++ b/modules/network/src/main/java/org/apache/ignite/internal/network/serialization/BuiltInType.java
@@ -79,7 +79,8 @@ public enum BuiltInType {
LINKED_HASH_MAP(41, LinkedHashMap.class),
BIT_SET(42, BitSet.class),
NULL(43, Null.class),
- REFERENCE(44, DummyPlaceholder.class)
+ REFERENCE(44, DummyPlaceholder.class),
+ CLASS(45, Class.class)
;
/**
diff --git a/modules/network/src/main/java/org/apache/ignite/internal/network/serialization/SpecialSerializationMethodsImpl.java b/modules/network/src/main/java/org/apache/ignite/internal/network/serialization/SpecialSerializationMethodsImpl.java
index 84e7caa..aba7b96 100644
--- a/modules/network/src/main/java/org/apache/ignite/internal/network/serialization/SpecialSerializationMethodsImpl.java
+++ b/modules/network/src/main/java/org/apache/ignite/internal/network/serialization/SpecialSerializationMethodsImpl.java
@@ -19,31 +19,29 @@ package org.apache.ignite.internal.network.serialization;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
-import java.lang.invoke.MethodHandle;
-import java.lang.invoke.MethodHandles;
-import java.lang.invoke.MethodType;
+import java.lang.reflect.Method;
import java.util.Objects;
import org.jetbrains.annotations.Nullable;
/**
- * Encapsulates special serialization methods like writeReplace()/readResolve() for convenient invocation.
+ * Encapsulates special serialization methods like writeReplace()/readResolve() and so on for convenient invocation.
*/
class SpecialSerializationMethodsImpl implements SpecialSerializationMethods {
- /** MethodHandle that can be used to invoke writeReplace() on the target class. */
+ /** Method that can be used to invoke writeReplace() on the target class. */
@Nullable
- private final MethodHandle writeReplaceHandle;
+ private final Method writeReplace;
- /** MethodHandle that can be used to invoke readResolve() on the target class. */
+ /** Method that can be used to invoke readResolve() on the target class. */
@Nullable
- private final MethodHandle readResolveHandle;
+ private final Method readResolve;
- /** MethodHandle that can be used to invoke writeObject() on the target class. */
+ /** Method that can be used to invoke writeObject() on the target class. */
@Nullable
- private final MethodHandle writeObjectHandle;
+ private final Method writeObject;
- /** MethodHandle that can be used to invoke readObject() on the target class. */
+ /** Method that can be used to invoke readObject() on the target class. */
@Nullable
- private final MethodHandle readObjectHandle;
+ private final Method readObject;
/**
* Creates a new instance from the provided descriptor.
@@ -51,47 +49,47 @@ class SpecialSerializationMethodsImpl implements SpecialSerializationMethods {
* @param descriptor class descriptor on which class to operate
*/
public SpecialSerializationMethodsImpl(ClassDescriptor descriptor) {
- writeReplaceHandle = descriptor.hasWriteReplace() ? writeReplaceHandle(descriptor) : null;
- readResolveHandle = descriptor.hasReadResolve() ? readResolveHandle(descriptor) : null;
- writeObjectHandle = descriptor.hasWriteObject() ? writeObjectHandle(descriptor) : null;
- readObjectHandle = descriptor.hasReadObject() ? readObjectHandle(descriptor) : null;
+ writeReplace = descriptor.hasWriteReplace() ? writeReplaceInvoker(descriptor) : null;
+ readResolve = descriptor.hasReadResolve() ? readResolveInvoker(descriptor) : null;
+ writeObject = descriptor.hasWriteObject() ? writeObjectInvoker(descriptor) : null;
+ readObject = descriptor.hasReadObject() ? readObjectInvoker(descriptor) : null;
}
- private static MethodHandle writeReplaceHandle(ClassDescriptor descriptor) {
+ private static Method writeReplaceInvoker(ClassDescriptor descriptor) {
try {
- return MethodHandles.privateLookupIn(descriptor.clazz(), MethodHandles.lookup())
- .findVirtual(descriptor.clazz(), "writeReplace", MethodType.methodType(Object.class))
- .asType(MethodType.methodType(Object.class, Object.class));
+ Method method = descriptor.clazz().getDeclaredMethod("writeReplace");
+ method.setAccessible(true);
+ return method;
} catch (ReflectiveOperationException e) {
throw new ReflectionException("Cannot find writeReplace() in " + descriptor.clazz(), e);
}
}
- private static MethodHandle readResolveHandle(ClassDescriptor descriptor) {
+ private static Method readResolveInvoker(ClassDescriptor descriptor) {
try {
- return MethodHandles.privateLookupIn(descriptor.clazz(), MethodHandles.lookup())
- .findVirtual(descriptor.clazz(), "readResolve", MethodType.methodType(Object.class))
- .asType(MethodType.methodType(Object.class, Object.class));
+ Method method = descriptor.clazz().getDeclaredMethod("readResolve");
+ method.setAccessible(true);
+ return method;
} catch (ReflectiveOperationException e) {
throw new ReflectionException("Cannot find readResolve() in " + descriptor.clazz(), e);
}
}
- private static MethodHandle writeObjectHandle(ClassDescriptor descriptor) {
+ private static Method writeObjectInvoker(ClassDescriptor descriptor) {
try {
- return MethodHandles.privateLookupIn(descriptor.clazz(), MethodHandles.lookup())
- .findVirtual(descriptor.clazz(), "writeObject", MethodType.methodType(void.class, ObjectOutputStream.class))
- .asType(MethodType.methodType(void.class, Object.class, ObjectOutputStream.class));
+ Method method = descriptor.clazz().getDeclaredMethod("writeObject", ObjectOutputStream.class);
+ method.setAccessible(true);
+ return method;
} catch (ReflectiveOperationException e) {
throw new ReflectionException("Cannot find writeObject() in " + descriptor.clazz(), e);
}
}
- private static MethodHandle readObjectHandle(ClassDescriptor descriptor) {
+ private static Method readObjectInvoker(ClassDescriptor descriptor) {
try {
- return MethodHandles.privateLookupIn(descriptor.clazz(), MethodHandles.lookup())
- .findVirtual(descriptor.clazz(), "readObject", MethodType.methodType(void.class, ObjectInputStream.class))
- .asType(MethodType.methodType(void.class, Object.class, ObjectInputStream.class));
+ Method method = descriptor.clazz().getDeclaredMethod("readObject", ObjectInputStream.class);
+ method.setAccessible(true);
+ return method;
} catch (ReflectiveOperationException e) {
throw new ReflectionException("Cannot find readObject() in " + descriptor.clazz(), e);
}
@@ -100,13 +98,11 @@ class SpecialSerializationMethodsImpl implements SpecialSerializationMethods {
/** {@inheritDoc} */
@Override
public Object writeReplace(Object object) throws SpecialMethodInvocationException {
- Objects.requireNonNull(writeReplaceHandle);
+ Objects.requireNonNull(writeReplace);
try {
- return writeReplaceHandle.invokeExact(object);
- } catch (Error e) {
- throw e;
- } catch (Throwable e) {
+ return writeReplace.invoke(object, (Object[]) null);
+ } catch (ReflectiveOperationException e) {
throw new SpecialMethodInvocationException("writeReplace() invocation failed on " + object, e);
}
}
@@ -114,13 +110,11 @@ class SpecialSerializationMethodsImpl implements SpecialSerializationMethods {
/** {@inheritDoc} */
@Override
public Object readResolve(Object object) throws SpecialMethodInvocationException {
- Objects.requireNonNull(readResolveHandle);
+ Objects.requireNonNull(readResolve);
try {
- return readResolveHandle.invokeExact(object);
- } catch (Error e) {
- throw e;
- } catch (Throwable e) {
+ return readResolve.invoke(object, (Object[]) null);
+ } catch (ReflectiveOperationException e) {
throw new SpecialMethodInvocationException("readResolve() invocation failed on " + object, e);
}
}
@@ -128,13 +122,11 @@ class SpecialSerializationMethodsImpl implements SpecialSerializationMethods {
/** {@inheritDoc} */
@Override
public void writeObject(Object object, ObjectOutputStream stream) throws SpecialMethodInvocationException {
- Objects.requireNonNull(writeObjectHandle);
+ Objects.requireNonNull(writeObject);
try {
- writeObjectHandle.invokeExact(object, stream);
- } catch (Error e) {
- throw e;
- } catch (Throwable e) {
+ writeObject.invoke(object, stream);
+ } catch (ReflectiveOperationException e) {
throw new SpecialMethodInvocationException("writeObject() invocation failed on " + object, e);
}
}
@@ -142,13 +134,11 @@ class SpecialSerializationMethodsImpl implements SpecialSerializationMethods {
/** {@inheritDoc} */
@Override
public void readObject(Object object, ObjectInputStream stream) throws SpecialMethodInvocationException {
- Objects.requireNonNull(readObjectHandle);
+ Objects.requireNonNull(readObject);
try {
- readObjectHandle.invokeExact(object, stream);
- } catch (Error e) {
- throw e;
- } catch (Throwable e) {
+ readObject.invoke(object, stream);
+ } catch (ReflectiveOperationException e) {
throw new SpecialMethodInvocationException("readObject() invocation failed on " + object, e);
}
}
diff --git a/modules/network/src/main/java/org/apache/ignite/internal/network/serialization/marshal/BuiltInContainerMarshallers.java b/modules/network/src/main/java/org/apache/ignite/internal/network/serialization/marshal/BuiltInContainerMarshallers.java
index 1918984..13a2eb6 100644
--- a/modules/network/src/main/java/org/apache/ignite/internal/network/serialization/marshal/BuiltInContainerMarshallers.java
+++ b/modules/network/src/main/java/org/apache/ignite/internal/network/serialization/marshal/BuiltInContainerMarshallers.java
@@ -83,7 +83,7 @@ class BuiltInContainerMarshallers {
<T> void fillGenericRefArray(DataInputStream input, T[] array, ValueReader<T> elementReader, UnmarshallingContext context)
throws IOException, UnmarshalException {
- BuiltInMarshalling.fillGenericRefArray(input, array, elementReader, context);
+ BuiltInMarshalling.fillGenericRefArrayFrom(input, array, elementReader, context);
}
void writeBuiltInCollection(Collection<?> object, ClassDescriptor descriptor, DataOutputStream output, MarshallingContext context)
diff --git a/modules/network/src/main/java/org/apache/ignite/internal/network/serialization/marshal/BuiltInMarshalling.java b/modules/network/src/main/java/org/apache/ignite/internal/network/serialization/marshal/BuiltInMarshalling.java
index 787c66c..b981142 100644
--- a/modules/network/src/main/java/org/apache/ignite/internal/network/serialization/marshal/BuiltInMarshalling.java
+++ b/modules/network/src/main/java/org/apache/ignite/internal/network/serialization/marshal/BuiltInMarshalling.java
@@ -229,11 +229,11 @@ class BuiltInMarshalling {
}
static void writeBigDecimal(BigDecimal object, DataOutput output) throws IOException {
- output.writeUTF(object.toString());
+ writeString(object.toString(), output);
}
static BigDecimal readBigDecimal(DataInput input) throws IOException {
- return new BigDecimal(input.readUTF());
+ return new BigDecimal(readString(input));
}
static void writeEnum(Enum<?> object, DataOutput output) throws IOException {
@@ -245,32 +245,37 @@ class BuiltInMarshalling {
assert enumClass.getSuperclass() == Enum.class;
- output.writeUTF(enumClass.getName());
- output.writeUTF(object.name());
+ writeClass(enumClass, output);
+ writeString(object.name(), output);
}
+ @SuppressWarnings("unchecked")
static <T extends Enum<T>> Enum<?> readEnum(DataInput input) throws IOException, UnmarshalException {
- String enumClassName = input.readUTF();
- Class<T> enumClass = enumClass(enumClassName);
+ Class<T> enumClass = (Class<T>) readClass(input);
return Enum.valueOf(enumClass, input.readUTF());
}
- private static <T extends Enum<T>> Class<T> enumClass(String className) throws UnmarshalException {
- return classByName(className, "enum");
- }
-
@NotNull
- private static <T> Class<T> classByName(String className, String classKind) throws UnmarshalException {
+ private static <T> Class<T> classByName(String className) throws UnmarshalException {
try {
// TODO: what classloader to use?
@SuppressWarnings("unchecked") Class<T> castedClass = (Class<T>) Class.forName(className);
return castedClass;
} catch (ClassNotFoundException e) {
- throw new UnmarshalException("Can not load " + classKind + " class: " + className, e);
+ throw new UnmarshalException("Can not load a class: " + className, e);
}
}
- static <T> void writeRefArray(T[] array, DataOutputStream output, ValueWriter<T> valueWriter, MarshallingContext context)
+ static void writeClass(Class<?> classToWrite, DataOutput output) throws IOException {
+ writeString(classToWrite.getName(), output);
+ }
+
+ static Class<?> readClass(DataInput input) throws IOException, UnmarshalException {
+ String className = readString(input);
+ return classByName(className);
+ }
+
+ private static <T> void writeRefArray(T[] array, DataOutputStream output, ValueWriter<T> valueWriter, MarshallingContext context)
throws IOException, MarshalException {
writeLength(array.length, output);
for (T object : array) {
@@ -278,7 +283,7 @@ class BuiltInMarshalling {
}
}
- static <T> T[] readRefArray(
+ private static <T> T[] readRefArray(
DataInputStream input,
IntFunction<T[]> arrayFactory,
ValueReader<T> valueReader,
@@ -301,8 +306,7 @@ class BuiltInMarshalling {
@SuppressWarnings("unchecked")
private static <T> IntFunction<T[]> readTypeAndCreateArrayFactory(DataInput input) throws IOException, UnmarshalException {
- String componentClassName = input.readUTF();
- Class<T> componentType = classByName(componentClassName, "component");
+ Class<T> componentType = (Class<T>) readClass(input);
return len -> (T[]) Array.newInstance(componentType, len);
}
@@ -312,7 +316,7 @@ class BuiltInMarshalling {
return arrayFactory.apply(length);
}
- static <T> void fillGenericRefArray(DataInputStream input, T[] array, ValueReader<T> elementReader, UnmarshallingContext context)
+ static <T> void fillGenericRefArrayFrom(DataInputStream input, T[] array, ValueReader<T> elementReader, UnmarshallingContext context)
throws IOException, UnmarshalException {
fillRefArrayFrom(input, array, elementReader, context);
}
@@ -335,13 +339,13 @@ class BuiltInMarshalling {
}
static void writeEnumArray(Enum<?>[] array, DataOutputStream output, MarshallingContext context) throws IOException, MarshalException {
- output.writeUTF(array.getClass().getComponentType().getName());
+ writeClass(array.getClass().getComponentType(), output);
writeRefArray(array, output, enumWriter, context);
}
+ @SuppressWarnings("unchecked")
static Enum<?>[] readEnumArray(DataInputStream input, UnmarshallingContext context) throws IOException, UnmarshalException {
- String enumClassName = input.readUTF();
- Class<? extends Enum<?>> enumClass = enumClass(enumClassName);
+ Class<? extends Enum<?>> enumClass = (Class<? extends Enum<?>>) readClass(input);
return readRefArray(input, len -> (Enum<?>[]) Array.newInstance(enumClass, len), enumReader, context);
}
diff --git a/modules/network/src/main/java/org/apache/ignite/internal/network/serialization/marshal/BuiltInNonContainerMarshallers.java b/modules/network/src/main/java/org/apache/ignite/internal/network/serialization/marshal/BuiltInNonContainerMarshallers.java
index a3b8769..e6a0a15 100644
--- a/modules/network/src/main/java/org/apache/ignite/internal/network/serialization/marshal/BuiltInNonContainerMarshallers.java
+++ b/modules/network/src/main/java/org/apache/ignite/internal/network/serialization/marshal/BuiltInNonContainerMarshallers.java
@@ -69,6 +69,7 @@ class BuiltInNonContainerMarshallers {
addSingle(map, Enum[].class, BuiltInMarshalling::writeEnumArray, BuiltInMarshalling::readEnumArray);
addSingle(map, BitSet.class, BuiltInMarshalling::writeBitSet, BuiltInMarshalling::readBitSet);
addSingle(map, Null.class, (obj, output) -> {}, input -> null);
+ addSingle(map, Class.class, BuiltInMarshalling::writeClass, BuiltInMarshalling::readClass);
return Map.copyOf(map);
}
diff --git a/modules/network/src/test/java/org/apache/ignite/internal/network/serialization/marshal/WithoutNoArgConstructor.java b/modules/network/src/main/java/org/apache/ignite/internal/network/serialization/marshal/Classes.java
similarity index 52%
copy from modules/network/src/test/java/org/apache/ignite/internal/network/serialization/marshal/WithoutNoArgConstructor.java
copy to modules/network/src/main/java/org/apache/ignite/internal/network/serialization/marshal/Classes.java
index 0516176..e5fd895 100644
--- a/modules/network/src/test/java/org/apache/ignite/internal/network/serialization/marshal/WithoutNoArgConstructor.java
+++ b/modules/network/src/main/java/org/apache/ignite/internal/network/serialization/marshal/Classes.java
@@ -17,10 +17,32 @@
package org.apache.ignite.internal.network.serialization.marshal;
-class WithoutNoArgConstructor {
- int value;
+import java.io.Serializable;
- public WithoutNoArgConstructor(int value) {
- this.value = value;
+/**
+ * Utilities to work with classes.
+ */
+class Classes {
+ static boolean isSerializable(Class<?> objectClass) {
+ return Serializable.class.isAssignableFrom(objectClass);
+ }
+
+ static boolean isLambda(Class<?> objectClass) {
+ return !objectClass.isPrimitive() && !objectClass.isArray()
+ && !objectClass.isAnonymousClass() && !objectClass.isLocalClass()
+ && objectClass.isSynthetic()
+ && classCannotBeLoadedByName(objectClass);
+ }
+
+ private static boolean classCannotBeLoadedByName(Class<?> objectClass) {
+ try {
+ Class.forName(objectClass.getName());
+ return false;
+ } catch (ClassNotFoundException e) {
+ return true;
+ }
+ }
+
+ private Classes() {
}
}
diff --git a/modules/network/src/main/java/org/apache/ignite/internal/network/serialization/marshal/DefaultUserObjectMarshaller.java b/modules/network/src/main/java/org/apache/ignite/internal/network/serialization/marshal/DefaultUserObjectMarshaller.java
index b79c1ac..20c7d9a 100644
--- a/modules/network/src/main/java/org/apache/ignite/internal/network/serialization/marshal/DefaultUserObjectMarshaller.java
+++ b/modules/network/src/main/java/org/apache/ignite/internal/network/serialization/marshal/DefaultUserObjectMarshaller.java
@@ -134,10 +134,14 @@ public class DefaultUserObjectMarshaller implements UserObjectMarshaller {
Class<?> objectClass = object.getClass();
if (isInnerClass(objectClass)) {
- throw new IllegalArgumentException("Non-static inner class instances are not supported for marshalling: " + objectClass);
+ throw new MarshallingNotSupportedException("Non-static inner class instances are not supported for marshalling: "
+ + objectClass);
}
if (isCapturingClosure(objectClass)) {
- throw new IllegalArgumentException("Capturing nested class instances are not supported for marshalling: " + object);
+ throw new MarshallingNotSupportedException("Capturing nested class instances are not supported for marshalling: " + object);
+ }
+ if (Classes.isLambda(objectClass) && !Classes.isSerializable(objectClass)) {
+ throw new MarshallingNotSupportedException("Non-serializable lambda instances are not supported for marshalling: " + object);
}
}
diff --git a/modules/network/src/test/java/org/apache/ignite/internal/network/serialization/marshal/WithoutNoArgConstructor.java b/modules/network/src/main/java/org/apache/ignite/internal/network/serialization/marshal/MarshallingNotSupportedException.java
similarity index 74%
copy from modules/network/src/test/java/org/apache/ignite/internal/network/serialization/marshal/WithoutNoArgConstructor.java
copy to modules/network/src/main/java/org/apache/ignite/internal/network/serialization/marshal/MarshallingNotSupportedException.java
index 0516176..94b9f2d 100644
--- a/modules/network/src/test/java/org/apache/ignite/internal/network/serialization/marshal/WithoutNoArgConstructor.java
+++ b/modules/network/src/main/java/org/apache/ignite/internal/network/serialization/marshal/MarshallingNotSupportedException.java
@@ -17,10 +17,13 @@
package org.apache.ignite.internal.network.serialization.marshal;
-class WithoutNoArgConstructor {
- int value;
+import org.apache.ignite.lang.IgniteException;
- public WithoutNoArgConstructor(int value) {
- this.value = value;
+/**
+ * Thrown to indicate that an object cannot be marshalled, or that it will be impossible to unmarshal it then.
+ */
+class MarshallingNotSupportedException extends IgniteException {
+ public MarshallingNotSupportedException(String msg) {
+ super(msg);
}
}
diff --git a/modules/network/src/test/java/org/apache/ignite/internal/network/serialization/DefaultDescriptorsTest.java b/modules/network/src/test/java/org/apache/ignite/internal/network/serialization/BuiltInDescriptorsTest.java
similarity index 97%
rename from modules/network/src/test/java/org/apache/ignite/internal/network/serialization/DefaultDescriptorsTest.java
rename to modules/network/src/test/java/org/apache/ignite/internal/network/serialization/BuiltInDescriptorsTest.java
index 0a29655..671e452 100644
--- a/modules/network/src/test/java/org/apache/ignite/internal/network/serialization/DefaultDescriptorsTest.java
+++ b/modules/network/src/test/java/org/apache/ignite/internal/network/serialization/BuiltInDescriptorsTest.java
@@ -29,6 +29,7 @@ import static org.apache.ignite.internal.network.serialization.BuiltInType.BYTE_
import static org.apache.ignite.internal.network.serialization.BuiltInType.CHAR;
import static org.apache.ignite.internal.network.serialization.BuiltInType.CHAR_ARRAY;
import static org.apache.ignite.internal.network.serialization.BuiltInType.CHAR_BOXED;
+import static org.apache.ignite.internal.network.serialization.BuiltInType.CLASS;
import static org.apache.ignite.internal.network.serialization.BuiltInType.DATE;
import static org.apache.ignite.internal.network.serialization.BuiltInType.DECIMAL;
import static org.apache.ignite.internal.network.serialization.BuiltInType.DECIMAL_ARRAY;
@@ -67,9 +68,9 @@ import static org.junit.jupiter.api.Assertions.assertEquals;
import org.junit.jupiter.api.Test;
/**
- * Tests for default descriptors.
+ * Tests for built-in descriptors.
*/
-public class DefaultDescriptorsTest {
+public class BuiltInDescriptorsTest {
/**
* Tests that default descriptor were not changed by accident.
*/
@@ -120,5 +121,6 @@ public class DefaultDescriptorsTest {
assertEquals(42, BIT_SET.descriptorId());
assertEquals(43, NULL.descriptorId());
assertEquals(44, REFERENCE.descriptorId());
+ assertEquals(45, CLASS.descriptorId());
}
}
diff --git a/modules/network/src/test/java/org/apache/ignite/internal/network/serialization/marshal/ClassesTest.java b/modules/network/src/test/java/org/apache/ignite/internal/network/serialization/marshal/ClassesTest.java
new file mode 100644
index 0000000..09be2fc
--- /dev/null
+++ b/modules/network/src/test/java/org/apache/ignite/internal/network/serialization/marshal/ClassesTest.java
@@ -0,0 +1,101 @@
+/*
+ * 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 org.apache.ignite.internal.network.serialization.marshal;
+
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+import java.io.Serializable;
+import org.junit.jupiter.api.Test;
+
+class ClassesTest {
+ @Test
+ void isSerializableReturnsFalseForNonSerializableClass() {
+ assertFalse(Classes.isSerializable(NonSerializable.class));
+ }
+
+ @Test
+ void isSerializableReturnsTrueForSerializableClass() {
+ assertTrue(Classes.isSerializable(EmptySerializable.class));
+ }
+
+ @Test
+ void isLambdaReturnsFalseForOrdinaryClassInstance() {
+ assertFalse(Classes.isLambda(NonSerializable.class));
+ }
+
+ @SuppressWarnings("Convert2Lambda")
+ @Test
+ void isLambdaReturnsFalseForAnonymousClassInstance() {
+ Runnable object = new Runnable() {
+ @Override
+ public void run() {
+ // no-op
+ }
+ };
+
+ assertFalse(Classes.isLambda(object.getClass()));
+ }
+
+ @Test
+ void isLambdaReturnsTrueForNonSerializableLambda() {
+ Runnable object = () -> {};
+
+ assertTrue(Classes.isLambda(object.getClass()));
+ }
+
+ @Test
+ void isLambdaReturnsTrueForSerializableLambda() {
+ Runnable object = serializableLambda();
+
+ assertTrue(Classes.isLambda(object.getClass()));
+ }
+
+ private Runnable serializableLambda() {
+ return (Runnable & Serializable) () -> {};
+ }
+
+ @Test
+ void isLambdaReturnsFalseForPrimitiveClasses() {
+ assertFalse(Classes.isLambda(int.class));
+ }
+
+ @Test
+ void isLambdaReturnsFalseForPrimitiveArrayClasses() {
+ assertFalse(Classes.isLambda(int[].class));
+ }
+
+ @Test
+ void isLambdaReturnsFalseForObjectArrayClasses() {
+ assertFalse(Classes.isLambda(Object[].class));
+ }
+
+ @Test
+ void isLambdaReturnsFalseForEnumClasses() {
+ assertFalse(Classes.isLambda(EmptyEnum.class));
+ }
+
+ private static class NonSerializable {
+ }
+
+ private static class EmptySerializable implements Serializable {
+ }
+
+ private enum EmptyEnum {
+ }
+}
diff --git a/modules/network/src/test/java/org/apache/ignite/internal/network/serialization/marshal/DefaultUserObjectMarshallerWithArbitraryObjectsTest.java b/modules/network/src/test/java/org/apache/ignite/internal/network/serialization/marshal/DefaultUserObjectMarshallerWithArbitraryObjectsTest.java
index 3239988..6a89e9b 100644
--- a/modules/network/src/test/java/org/apache/ignite/internal/network/serialization/marshal/DefaultUserObjectMarshallerWithArbitraryObjectsTest.java
+++ b/modules/network/src/test/java/org/apache/ignite/internal/network/serialization/marshal/DefaultUserObjectMarshallerWithArbitraryObjectsTest.java
@@ -30,7 +30,6 @@ import static org.hamcrest.Matchers.not;
import static org.hamcrest.Matchers.notNullValue;
import static org.hamcrest.Matchers.nullValue;
import static org.hamcrest.Matchers.sameInstance;
-import static org.hamcrest.Matchers.startsWith;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertThrows;
@@ -49,7 +48,6 @@ import org.apache.ignite.internal.network.serialization.ClassDescriptorFactory;
import org.apache.ignite.internal.network.serialization.ClassDescriptorRegistry;
import org.apache.ignite.internal.network.serialization.IdIndexedDescriptors;
import org.jetbrains.annotations.NotNull;
-import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
/**
@@ -192,6 +190,18 @@ class DefaultUserObjectMarshallerWithArbitraryObjectsTest {
}
@Test
+ void doesNotSupportInnerClassInstances() {
+ assertThrows(MarshallingNotSupportedException.class, () -> marshaller.marshal(new Inner()));
+ }
+
+ @Test
+ void doesNotSupportInnerClassInstancesInsideContainers() {
+ List<Inner> list = singletonList(new Inner());
+
+ assertThrows(MarshallingNotSupportedException.class, () -> marshaller.marshal(list));
+ }
+
+ @Test
void supportsNonCapturingAnonymousClassInstances() throws Exception {
Callable<String> unmarshalled = marshalAndUnmarshalNonNull(nonCapturingAnonymousInstance());
@@ -209,89 +219,84 @@ class DefaultUserObjectMarshallerWithArbitraryObjectsTest {
}
@Test
- void supportsNonCapturingLambdas() throws Exception {
- Callable<String> unmarshalled = marshalAndUnmarshalNonNull(nonCapturingLambda());
+ void doesNotSupportCapturingAnonymousClassInstances() {
+ Runnable capturingClosure = capturingAnonymousInstance();
- assertThat(unmarshalled.call(), is("Hi!"));
+ assertThrows(MarshallingNotSupportedException.class, () -> marshaller.marshal(capturingClosure));
}
- private static Callable<String> nonCapturingLambda() {
- return () -> "Hi!";
+ private Runnable capturingAnonymousInstance() {
+ //noinspection Convert2Lambda
+ return new Runnable() {
+ @Override
+ public void run() {
+ System.out.println(DefaultUserObjectMarshallerWithArbitraryObjectsTest.this);
+ }
+ };
}
@Test
- @Disabled("IGNITE-16258")
- // TODO: IGNITE-16258 - enable this test when we are able to work with serializable lambdas
- void supportsNonCapturingSerializableLambdas() throws Exception {
- Callable<String> unmarshalled = marshalAndUnmarshalNonNull(nonCapturingSerializableLambda());
-
- assertThat(unmarshalled.call(), is("Hi!"));
- }
+ void doesNotSupportCapturingAnonymousClassInstancesInsideContainers() {
+ Runnable capturingAnonymousInstance = capturingAnonymousInstance();
+ List<Runnable> list = singletonList(capturingAnonymousInstance);
- private static Callable<String> nonCapturingSerializableLambda() {
- return (Callable<String> & Serializable) () -> "Hi!";
+ assertThrows(MarshallingNotSupportedException.class, () -> marshaller.marshal(list));
}
+ /**
+ * We should not support non-capturing non-serializable Lambdas. Even though it's possible to marshal and unmarshal
+ * such lambda inside the same JVM, it's impossible to load its class by name (even when it exists in the JVM with
+ * that same name!), so such lambdas will be impossible to unmarshal at another JVM.
+ *
+ */
@Test
- void doesNotSupportInnerClassInstances() {
- Throwable ex = assertThrows(IllegalArgumentException.class, () -> marshaller.marshal(new Inner()));
- assertThat(ex.getMessage(), is("Non-static inner class instances are not supported for marshalling: " + Inner.class));
+ void doesNotSupportNonCapturingNonSerializableLambdas() {
+ assertThrows(MarshallingNotSupportedException.class, () -> marshalAndUnmarshalNonNull(nonCapturingLambda()));
}
- @Test
- void doesNotSupportInnerClassInstancesInsideContainers() {
- List<Inner> list = singletonList(new Inner());
-
- Throwable ex = assertThrows(IllegalArgumentException.class, () -> marshaller.marshal(list));
- assertThat(ex.getMessage(), is("Non-static inner class instances are not supported for marshalling: " + Inner.class));
+ private static Callable<String> nonCapturingLambda() {
+ return () -> "Hi!";
}
@Test
- void doesNotSupportCapturingAnonymousClassInstances() {
- Runnable capturingClosure = capturingAnonymousInstance();
+ void supportsNonCapturingSerializableLambdas() throws Exception {
+ Callable<String> unmarshalled = marshalAndUnmarshalNonNull(nonCapturingSerializableLambda());
- Throwable ex = assertThrows(IllegalArgumentException.class, () -> marshaller.marshal(capturingClosure));
- assertThat(ex.getMessage(), startsWith("Capturing nested class instances are not supported for marshalling: "));
+ assertThat(unmarshalled.call(), is("Hi!"));
}
- private Runnable capturingAnonymousInstance() {
- //noinspection Convert2Lambda
- return new Runnable() {
- @Override
- public void run() {
- System.out.println(DefaultUserObjectMarshallerWithArbitraryObjectsTest.this);
- }
- };
+ private static Callable<String> nonCapturingSerializableLambda() {
+ return (Callable<String> & Serializable) () -> "Hi!";
}
@Test
- void doesNotSupportCapturingAnonymousClassInstancesInsideContainers() {
- Runnable capturingAnonymousInstance = capturingAnonymousInstance();
- List<Runnable> list = singletonList(capturingAnonymousInstance);
+ void doesNotSupportCapturingNonSerializableLambdas() {
+ Runnable capturingClosure = capturingNonSerializableLambda();
- Throwable ex = assertThrows(IllegalArgumentException.class, () -> marshaller.marshal(list));
- assertThat(ex.getMessage(), startsWith("Capturing nested class instances are not supported for marshalling: "));
+ assertThrows(MarshallingNotSupportedException.class, () -> marshaller.marshal(capturingClosure));
+ }
+
+ private Runnable capturingNonSerializableLambda() {
+ return () -> System.out.println(DefaultUserObjectMarshallerWithArbitraryObjectsTest.this);
}
@Test
- void doesNotSupportCapturingLambdas() {
- Runnable capturingClosure = capturingLambda();
+ void doesNotSupportCapturingSerializableLambdas() {
+ Runnable capturingClosure = capturingSerializableLambda();
- Throwable ex = assertThrows(IllegalArgumentException.class, () -> marshaller.marshal(capturingClosure));
- assertThat(ex.getMessage(), startsWith("Capturing nested class instances are not supported for marshalling: "));
+ assertThrows(MarshallingNotSupportedException.class, () -> marshaller.marshal(capturingClosure));
}
- private Runnable capturingLambda() {
- return () -> System.out.println(DefaultUserObjectMarshallerWithArbitraryObjectsTest.this);
+ private Runnable capturingSerializableLambda() {
+ return (Runnable & Serializable) () -> System.out.println(DefaultUserObjectMarshallerWithArbitraryObjectsTest.this);
}
@Test
- void doesNotSupportCapturingAnonymousLambdasInsideContainers() {
- Runnable capturingLambda = capturingLambda();
+ void doesNotSupportCapturingLambdasInsideContainers() {
+ Runnable capturingLambda = capturingNonSerializableLambda();
List<Runnable> list = singletonList(capturingLambda);
- Throwable ex = assertThrows(IllegalArgumentException.class, () -> marshaller.marshal(list));
- assertThat(ex.getMessage(), startsWith("Capturing nested class instances are not supported for marshalling: "));
+ assertThrows(MarshallingNotSupportedException.class, () -> marshaller.marshal(list));
}
@Test
@@ -317,8 +322,7 @@ class DefaultUserObjectMarshallerWithArbitraryObjectsTest {
void doesNotSupportCapturingLocalClassInstances() {
Object instance = capturingLocalClassInstance();
- Throwable ex = assertThrows(IllegalArgumentException.class, () -> marshaller.marshal(instance));
- assertThat(ex.getMessage(), startsWith("Capturing nested class instances are not supported for marshalling: "));
+ assertThrows(MarshallingNotSupportedException.class, () -> marshaller.marshal(instance));
}
private Object capturingLocalClassInstance() {
@@ -329,8 +333,8 @@ class DefaultUserObjectMarshallerWithArbitraryObjectsTest {
}
@Test
- void supportsClassesWithoutNoArgConstructor() throws Exception {
- WithoutNoArgConstructor unmarshalled = marshalAndUnmarshalNonNull(new WithoutNoArgConstructor(42));
+ void supportsNonSerializableClassesWithoutNoArgConstructor() throws Exception {
+ NonSerializableWithoutNoArgConstructor unmarshalled = marshalAndUnmarshalNonNull(new NonSerializableWithoutNoArgConstructor(42));
assertThat(unmarshalled.value, is(42));
}
diff --git a/modules/network/src/test/java/org/apache/ignite/internal/network/serialization/marshal/DefaultUserObjectMarshallerWithBuiltinsTest.java b/modules/network/src/test/java/org/apache/ignite/internal/network/serialization/marshal/DefaultUserObjectMarshallerWithBuiltinsTest.java
index 151e19a..4577b9c 100644
--- a/modules/network/src/test/java/org/apache/ignite/internal/network/serialization/marshal/DefaultUserObjectMarshallerWithBuiltinsTest.java
+++ b/modules/network/src/test/java/org/apache/ignite/internal/network/serialization/marshal/DefaultUserObjectMarshallerWithBuiltinsTest.java
@@ -203,15 +203,19 @@ class DefaultUserObjectMarshallerWithBuiltinsTest {
builtInTypeValue(new Enum[]{SimpleEnum.FIRST, SimpleEnum.SECOND}, Enum[].class, BuiltInType.ENUM_ARRAY),
builtInTypeValue(new SimpleEnum[]{SimpleEnum.FIRST, SimpleEnum.SECOND}, SimpleEnum[].class, BuiltInType.ENUM_ARRAY),
builtInTypeValue(EnumWithAnonClassesForMembers.FIRST, EnumWithAnonClassesForMembers.class, BuiltInType.ENUM),
- builtInTypeValue(new Enum[]{EnumWithAnonClassesForMembers.FIRST, EnumWithAnonClassesForMembers.SECOND}, Enum[].class,
- BuiltInType.ENUM_ARRAY),
+ builtInTypeValue(
+ new Enum[]{EnumWithAnonClassesForMembers.FIRST, EnumWithAnonClassesForMembers.SECOND},
+ Enum[].class,
+ BuiltInType.ENUM_ARRAY
+ ),
builtInTypeValue(
new EnumWithAnonClassesForMembers[]{EnumWithAnonClassesForMembers.FIRST, EnumWithAnonClassesForMembers.SECOND},
EnumWithAnonClassesForMembers[].class,
BuiltInType.ENUM_ARRAY
),
builtInTypeValue(BitSet.valueOf(new long[]{42, 43}), BitSet.class, BuiltInType.BIT_SET),
- builtInTypeValue(null, Null.class, BuiltInType.NULL)
+ builtInTypeValue(null, Null.class, BuiltInType.NULL),
+ builtInTypeValue(IntHolder.class, Class.class, BuiltInType.CLASS)
).map(Arguments::of);
}
diff --git a/modules/network/src/test/java/org/apache/ignite/internal/network/serialization/marshal/NoArgConstructorInstantiationTest.java b/modules/network/src/test/java/org/apache/ignite/internal/network/serialization/marshal/NoArgConstructorInstantiationTest.java
index 3357f13..693a276 100644
--- a/modules/network/src/test/java/org/apache/ignite/internal/network/serialization/marshal/NoArgConstructorInstantiationTest.java
+++ b/modules/network/src/test/java/org/apache/ignite/internal/network/serialization/marshal/NoArgConstructorInstantiationTest.java
@@ -43,7 +43,7 @@ class NoArgConstructorInstantiationTest {
@Test
void doesNotSupportClassesWithoutNoArgConstructor() {
- assertFalse(instantiation.supports(WithoutNoArgConstructor.class));
+ assertFalse(instantiation.supports(NonSerializableWithoutNoArgConstructor.class));
}
@Test
diff --git a/modules/network/src/test/java/org/apache/ignite/internal/network/serialization/marshal/WithoutNoArgConstructor.java b/modules/network/src/test/java/org/apache/ignite/internal/network/serialization/marshal/NonSerializableWithoutNoArgConstructor.java
similarity index 89%
rename from modules/network/src/test/java/org/apache/ignite/internal/network/serialization/marshal/WithoutNoArgConstructor.java
rename to modules/network/src/test/java/org/apache/ignite/internal/network/serialization/marshal/NonSerializableWithoutNoArgConstructor.java
index 0516176..f6bbb80 100644
--- a/modules/network/src/test/java/org/apache/ignite/internal/network/serialization/marshal/WithoutNoArgConstructor.java
+++ b/modules/network/src/test/java/org/apache/ignite/internal/network/serialization/marshal/NonSerializableWithoutNoArgConstructor.java
@@ -17,10 +17,10 @@
package org.apache.ignite.internal.network.serialization.marshal;
-class WithoutNoArgConstructor {
+class NonSerializableWithoutNoArgConstructor {
int value;
- public WithoutNoArgConstructor(int value) {
+ public NonSerializableWithoutNoArgConstructor(int value) {
this.value = value;
}
}
diff --git a/modules/network/src/test/java/org/apache/ignite/internal/network/serialization/marshal/UnsafeInstantiationTest.java b/modules/network/src/test/java/org/apache/ignite/internal/network/serialization/marshal/UnsafeInstantiationTest.java
index 7beb536..a45ddbd 100644
--- a/modules/network/src/test/java/org/apache/ignite/internal/network/serialization/marshal/UnsafeInstantiationTest.java
+++ b/modules/network/src/test/java/org/apache/ignite/internal/network/serialization/marshal/UnsafeInstantiationTest.java
@@ -34,7 +34,7 @@ class UnsafeInstantiationTest {
@Test
void supportsClassesWithoutNoArgConstructor() {
- assertTrue(instantiation.supports(WithoutNoArgConstructor.class));
+ assertTrue(instantiation.supports(NonSerializableWithoutNoArgConstructor.class));
}
@Test
@@ -46,7 +46,7 @@ class UnsafeInstantiationTest {
@Test
void instantiatesClassesWithoutNoArgConstructor() throws Exception {
- Object instance = instantiation.newInstance(WithoutNoArgConstructor.class);
+ Object instance = instantiation.newInstance(NonSerializableWithoutNoArgConstructor.class);
assertThat(instance, is(notNullValue()));
}