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/10/26 12:21:12 UTC
[ignite] branch master updated: IGNITE-17962 Fix serializable lambda serialization with Java17 (#10342)
This is an automated email from the ASF dual-hosted git repository.
sdanilov pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/ignite.git
The following commit(s) were added to refs/heads/master by this push:
new dc405c89b0f IGNITE-17962 Fix serializable lambda serialization with Java17 (#10342)
dc405c89b0f is described below
commit dc405c89b0f567d3adb9321e572585a7b62458b1
Author: Semyon Danilov <sa...@yandex.ru>
AuthorDate: Wed Oct 26 15:21:05 2022 +0300
IGNITE-17962 Fix serializable lambda serialization with Java17 (#10342)
---
bin/include/jvmdefaults.bat | 2 +
bin/include/jvmdefaults.sh | 2 +
.../internal/binary/BinaryClassDescriptor.java | 79 +++++---
.../optimized/OptimizedClassDescriptor.java | 223 +++++++++++----------
.../ignite/internal/util/FeatureChecker.java | 6 +-
.../apache/ignite/internal/util/IgniteUtils.java | 31 +++
.../GridMultipleVersionsDeploymentSelfTest.java | 1 +
.../IgniteExplicitImplicitDeploymentSelfTest.java | 9 +-
.../persistence/snapshot/PlainSnapshotTest.java | 25 ++-
.../ignite/internal/util/IgniteUtilsSelfTest.java | 66 ++++++
.../p2p/GridP2PRemoteClassLoadersSelfTest.java | 3 +
parent/pom.xml | 2 +
12 files changed, 298 insertions(+), 151 deletions(-)
diff --git a/bin/include/jvmdefaults.bat b/bin/include/jvmdefaults.bat
index e533e3be51c..e9002a41412 100644
--- a/bin/include/jvmdefaults.bat
+++ b/bin/include/jvmdefaults.bat
@@ -68,8 +68,10 @@ if %java_version% GEQ 15 (
--add-opens=java.base/java.util=ALL-UNNAMED ^
--add-opens=java.base/java.util.concurrent=ALL-UNNAMED ^
--add-opens=java.base/java.util.concurrent.locks=ALL-UNNAMED ^
+ --add-opens=java.base/java.util.concurrent.atomic=ALL-UNNAMED ^
--add-opens=java.base/java.lang=ALL-UNNAMED ^
--add-opens=java.base/java.lang.invoke=ALL-UNNAMED ^
+ --add-opens=java.base/java.math=ALL-UNNAMED ^
--add-opens=java.sql/java.sql=ALL-UNNAMED ^
%current_value%
)
diff --git a/bin/include/jvmdefaults.sh b/bin/include/jvmdefaults.sh
index 4f801a78297..8be1133aeec 100644
--- a/bin/include/jvmdefaults.sh
+++ b/bin/include/jvmdefaults.sh
@@ -65,8 +65,10 @@ getJavaSpecificOpts() {
--add-opens=java.base/java.util=ALL-UNNAMED \
--add-opens=java.base/java.util.concurrent=ALL-UNNAMED \
--add-opens=java.base/java.util.concurrent.locks=ALL-UNNAMED \
+ --add-opens=java.base/java.util.concurrent.atomic=ALL-UNNAMED \
--add-opens=java.base/java.lang=ALL-UNNAMED \
--add-opens=java.base/java.lang.invoke=ALL-UNNAMED \
+ --add-opens=java.base/java.math=ALL-UNNAMED \
--add-opens=java.sql/java.sql=ALL-UNNAMED \
${current_value}"
fi
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/binary/BinaryClassDescriptor.java b/modules/core/src/main/java/org/apache/ignite/internal/binary/BinaryClassDescriptor.java
index 6ded1729edb..0b64d6a94b9 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/binary/BinaryClassDescriptor.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/binary/BinaryClassDescriptor.java
@@ -17,6 +17,7 @@
package org.apache.ignite.internal.binary;
+import java.io.Serializable;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
@@ -54,6 +55,7 @@ import org.apache.ignite.marshaller.MarshallerExclusions;
import org.jetbrains.annotations.Nullable;
import static org.apache.ignite.internal.processors.query.QueryUtils.isGeometryClass;
+import static org.apache.ignite.internal.util.IgniteUtils.isLambda;
/**
* Binary class descriptor.
@@ -318,61 +320,72 @@ public class BinaryClassDescriptor {
// Must not use constructor to honor transient fields semantics.
ctor = null;
- Map<Object, BinaryFieldAccessor> fields0;
+ if (isLambda(cls)) {
+ if (!Serializable.class.isAssignableFrom(cls))
+ throw new BinaryObjectException("Lambda is not serializable: " + cls);
- if (BinaryUtils.FIELDS_SORTED_ORDER) {
- fields0 = new TreeMap<>();
-
- stableFieldsMeta = metaDataEnabled ? new TreeMap<String, BinaryFieldMetadata>() : null;
+ // We don't need fields for serializable lambdas, because we resort to SerializedLambda.
+ fields = null;
+ stableFieldsMeta = null;
+ stableSchema = null;
}
else {
- fields0 = new LinkedHashMap<>();
+ Map<Object, BinaryFieldAccessor> fields0;
- stableFieldsMeta = metaDataEnabled ? new LinkedHashMap<String, BinaryFieldMetadata>() : null;
- }
+ if (BinaryUtils.FIELDS_SORTED_ORDER) {
+ fields0 = new TreeMap<>();
- Set<String> duplicates = duplicateFields(cls);
+ stableFieldsMeta = metaDataEnabled ? new TreeMap<String, BinaryFieldMetadata>() : null;
+ }
+ else {
+ fields0 = new LinkedHashMap<>();
+
+ stableFieldsMeta = metaDataEnabled ? new LinkedHashMap<String, BinaryFieldMetadata>() : null;
+ }
- Collection<String> names = new HashSet<>();
- Collection<Integer> ids = new HashSet<>();
+ Set<String> duplicates = duplicateFields(cls);
- for (Class<?> c = cls; c != null && !c.equals(Object.class); c = c.getSuperclass()) {
- for (Field f : c.getDeclaredFields()) {
- if (serializeField(f)) {
- f.setAccessible(true);
+ Collection<String> names = new HashSet<>();
+ Collection<Integer> ids = new HashSet<>();
- String name = f.getName();
+ for (Class<?> c = cls; c != null && !c.equals(Object.class); c = c.getSuperclass()) {
+ for (Field f : c.getDeclaredFields()) {
+ if (serializeField(f)) {
+ f.setAccessible(true);
- if (duplicates.contains(name))
- name = BinaryUtils.qualifiedFieldName(c, name);
+ String name = f.getName();
- boolean added = names.add(name);
+ if (duplicates.contains(name))
+ name = BinaryUtils.qualifiedFieldName(c, name);
- assert added : name;
+ boolean added = names.add(name);
- int fieldId = this.mapper.fieldId(typeId, name);
+ assert added : name;
- if (!ids.add(fieldId))
- throw new BinaryObjectException("Duplicate field ID: " + name);
+ int fieldId = this.mapper.fieldId(typeId, name);
- BinaryFieldAccessor fieldInfo = BinaryFieldAccessor.create(f, fieldId);
+ if (!ids.add(fieldId))
+ throw new BinaryObjectException("Duplicate field ID: " + name);
- fields0.put(name, fieldInfo);
+ BinaryFieldAccessor fieldInfo = BinaryFieldAccessor.create(f, fieldId);
- if (metaDataEnabled)
- stableFieldsMeta.put(name, new BinaryFieldMetadata(fieldInfo));
+ fields0.put(name, fieldInfo);
+
+ if (metaDataEnabled)
+ stableFieldsMeta.put(name, new BinaryFieldMetadata(fieldInfo));
+ }
}
}
- }
- fields = fields0.values().toArray(new BinaryFieldAccessor[fields0.size()]);
+ fields = fields0.values().toArray(new BinaryFieldAccessor[fields0.size()]);
- BinarySchema.Builder schemaBuilder = BinarySchema.Builder.newBuilder();
+ BinarySchema.Builder schemaBuilder = BinarySchema.Builder.newBuilder();
- for (BinaryFieldAccessor field : fields)
- schemaBuilder.addField(field.id);
+ for (BinaryFieldAccessor field : fields)
+ schemaBuilder.addField(field.id);
- stableSchema = schemaBuilder.build();
+ stableSchema = schemaBuilder.build();
+ }
intfs = null;
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/marshaller/optimized/OptimizedClassDescriptor.java b/modules/core/src/main/java/org/apache/ignite/internal/marshaller/optimized/OptimizedClassDescriptor.java
index c6917c7bc24..ac1a8b61d72 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/marshaller/optimized/OptimizedClassDescriptor.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/marshaller/optimized/OptimizedClassDescriptor.java
@@ -95,6 +95,7 @@ import static org.apache.ignite.internal.marshaller.optimized.OptimizedMarshalle
import static org.apache.ignite.internal.marshaller.optimized.OptimizedMarshallerUtils.STR;
import static org.apache.ignite.internal.marshaller.optimized.OptimizedMarshallerUtils.UUID;
import static org.apache.ignite.internal.marshaller.optimized.OptimizedMarshallerUtils.computeSerialVersionUid;
+import static org.apache.ignite.internal.util.IgniteUtils.isLambda;
import static org.apache.ignite.marshaller.MarshallerUtils.jobReceiverVersion;
import static org.apache.ignite.marshaller.MarshallerUtils.jobSenderVersion;
@@ -446,160 +447,166 @@ class OptimizedClassDescriptor {
readObjMtds = new ArrayList<>();
List<ClassFields> fields = new ArrayList<>();
- for (c = cls; c != null && !c.equals(Object.class); c = c.getSuperclass()) {
- Method mtd;
+ if (isLambda(cls)) {
+ if (!isSerial)
+ throw new NotSerializableException("Lambda is not serializable: " + cls);
+ }
+ else {
+ for (c = cls; c != null && !c.equals(Object.class); c = c.getSuperclass()) {
+ Method mtd;
- try {
- mtd = c.getDeclaredMethod("writeObject", ObjectOutputStream.class);
+ try {
+ mtd = c.getDeclaredMethod("writeObject", ObjectOutputStream.class);
- int mod = mtd.getModifiers();
+ int mod = mtd.getModifiers();
- if (!isStatic(mod) && isPrivate(mod) && mtd.getReturnType() == Void.TYPE)
- mtd.setAccessible(true);
- else
- // Set method back to null if it has incorrect signature.
+ if (!isStatic(mod) && isPrivate(mod) && mtd.getReturnType() == Void.TYPE)
+ mtd.setAccessible(true);
+ else
+ // Set method back to null if it has incorrect signature.
+ mtd = null;
+ }
+ catch (NoSuchMethodException ignored) {
mtd = null;
- }
- catch (NoSuchMethodException ignored) {
- mtd = null;
- }
+ }
- writeObjMtds.add(mtd);
+ writeObjMtds.add(mtd);
- try {
- mtd = c.getDeclaredMethod("readObject", ObjectInputStream.class);
+ try {
+ mtd = c.getDeclaredMethod("readObject", ObjectInputStream.class);
- int mod = mtd.getModifiers();
+ int mod = mtd.getModifiers();
- if (!isStatic(mod) && isPrivate(mod) && mtd.getReturnType() == Void.TYPE)
- mtd.setAccessible(true);
- else
- // Set method back to null if it has incorrect signature.
+ if (!isStatic(mod) && isPrivate(mod) && mtd.getReturnType() == Void.TYPE)
+ mtd.setAccessible(true);
+ else
+ // Set method back to null if it has incorrect signature.
+ mtd = null;
+ }
+ catch (NoSuchMethodException ignored) {
mtd = null;
- }
- catch (NoSuchMethodException ignored) {
- mtd = null;
- }
+ }
- readObjMtds.add(mtd);
+ readObjMtds.add(mtd);
- final SerializableTransient serTransAn = c.getAnnotation(SerializableTransient.class);
- final TransientSerializable transSerAn = c.getAnnotation(TransientSerializable.class);
+ final SerializableTransient serTransAn = c.getAnnotation(SerializableTransient.class);
+ final TransientSerializable transSerAn = c.getAnnotation(TransientSerializable.class);
- // Custom serialization policy for transient fields.
- if (serTransAn != null) {
- try {
- serTransMtd = c.getDeclaredMethod(serTransAn.methodName(), IgniteProductVersion.class);
+ // Custom serialization policy for transient fields.
+ if (serTransAn != null) {
+ try {
+ serTransMtd = c.getDeclaredMethod(serTransAn.methodName(), IgniteProductVersion.class);
- int mod = serTransMtd.getModifiers();
+ int mod = serTransMtd.getModifiers();
- if (isStatic(mod) && isPrivate(mod) && serTransMtd.getReturnType() == String[].class)
- serTransMtd.setAccessible(true);
- else
- // Set method back to null if it has incorrect signature.
+ if (isStatic(mod) && isPrivate(mod) && serTransMtd.getReturnType() == String[].class)
+ serTransMtd.setAccessible(true);
+ else
+ // Set method back to null if it has incorrect signature.
+ serTransMtd = null;
+ }
+ catch (NoSuchMethodException ignored) {
serTransMtd = null;
+ }
}
- catch (NoSuchMethodException ignored) {
- serTransMtd = null;
- }
- }
- // Custom serialization policy for non-transient fields.
- if (transSerAn != null) {
- try {
- transSerMtd = c.getDeclaredMethod(transSerAn.methodName(), IgniteProductVersion.class);
+ // Custom serialization policy for non-transient fields.
+ if (transSerAn != null) {
+ try {
+ transSerMtd = c.getDeclaredMethod(transSerAn.methodName(), IgniteProductVersion.class);
- int mod = transSerMtd.getModifiers();
+ int mod = transSerMtd.getModifiers();
- if (isStatic(mod) && isPrivate(mod) && transSerMtd.getReturnType() == String[].class)
- transSerMtd.setAccessible(true);
- else
- // Set method back to null if it has incorrect signature.
+ if (isStatic(mod) && isPrivate(mod) && transSerMtd.getReturnType() == String[].class)
+ transSerMtd.setAccessible(true);
+ else
+ // Set method back to null if it has incorrect signature.
+ transSerMtd = null;
+ }
+ catch (NoSuchMethodException ignored) {
transSerMtd = null;
+ }
}
- catch (NoSuchMethodException ignored) {
- transSerMtd = null;
- }
- }
- Field[] clsFields0 = c.getDeclaredFields();
+ Field[] clsFields0 = c.getDeclaredFields();
- Map<String, Field> fieldNames = new HashMap<>();
+ Map<String, Field> fieldNames = new HashMap<>();
- for (Field f : clsFields0)
- fieldNames.put(f.getName(), f);
+ for (Field f : clsFields0)
+ fieldNames.put(f.getName(), f);
- List<FieldInfo> clsFields = new ArrayList<>(clsFields0.length);
+ List<FieldInfo> clsFields = new ArrayList<>(clsFields0.length);
- boolean hasSerialPersistentFields = false;
+ boolean hasSerialPersistentFields = false;
- try {
- Field serFieldsDesc = c.getDeclaredField("serialPersistentFields");
+ try {
+ Field serFieldsDesc = c.getDeclaredField("serialPersistentFields");
- int mod = serFieldsDesc.getModifiers();
+ int mod = serFieldsDesc.getModifiers();
- if (serFieldsDesc.getType() == ObjectStreamField[].class &&
- isPrivate(mod) && isStatic(mod) && isFinal(mod)) {
- hasSerialPersistentFields = true;
+ if (serFieldsDesc.getType() == ObjectStreamField[].class &&
+ isPrivate(mod) && isStatic(mod) && isFinal(mod)) {
+ hasSerialPersistentFields = true;
- serFieldsDesc.setAccessible(true);
+ serFieldsDesc.setAccessible(true);
- ObjectStreamField[] serFields = (ObjectStreamField[])serFieldsDesc.get(null);
+ ObjectStreamField[] serFields = (ObjectStreamField[])serFieldsDesc.get(null);
- for (int i = 0; i < serFields.length; i++) {
- ObjectStreamField serField = serFields[i];
+ for (int i = 0; i < serFields.length; i++) {
+ ObjectStreamField serField = serFields[i];
- FieldInfo fieldInfo;
+ FieldInfo fieldInfo;
- if (!fieldNames.containsKey(serField.getName())) {
- fieldInfo = new FieldInfo(null,
- serField.getName(),
- -1,
- fieldType(serField.getType()));
- }
- else {
- Field f = fieldNames.get(serField.getName());
+ if (!fieldNames.containsKey(serField.getName())) {
+ fieldInfo = new FieldInfo(null,
+ serField.getName(),
+ -1,
+ fieldType(serField.getType()));
+ }
+ else {
+ Field f = fieldNames.get(serField.getName());
- fieldInfo = new FieldInfo(f,
- serField.getName(),
- GridUnsafe.objectFieldOffset(f),
- fieldType(serField.getType()));
- }
+ fieldInfo = new FieldInfo(f,
+ serField.getName(),
+ GridUnsafe.objectFieldOffset(f),
+ fieldType(serField.getType()));
+ }
- clsFields.add(fieldInfo);
+ clsFields.add(fieldInfo);
+ }
}
}
- }
- catch (NoSuchFieldException ignored) {
- // No-op.
- }
- catch (IllegalAccessException e) {
- throw new IOException("Failed to get value of 'serialPersistentFields' field in class: " +
- cls.getName(), e);
- }
+ catch (NoSuchFieldException ignored) {
+ // No-op.
+ }
+ catch (IllegalAccessException e) {
+ throw new IOException("Failed to get value of 'serialPersistentFields' field in class: " +
+ cls.getName(), e);
+ }
- if (!hasSerialPersistentFields) {
- for (int i = 0; i < clsFields0.length; i++) {
- Field f = clsFields0[i];
+ if (!hasSerialPersistentFields) {
+ for (int i = 0; i < clsFields0.length; i++) {
+ Field f = clsFields0[i];
- int mod = f.getModifiers();
+ int mod = f.getModifiers();
- if (!isStatic(mod) && !isTransient(mod)) {
- FieldInfo fieldInfo = new FieldInfo(f, f.getName(),
- GridUnsafe.objectFieldOffset(f), fieldType(f.getType()));
+ if (!isStatic(mod) && !isTransient(mod)) {
+ FieldInfo fieldInfo = new FieldInfo(f, f.getName(),
+ GridUnsafe.objectFieldOffset(f), fieldType(f.getType()));
- clsFields.add(fieldInfo);
+ clsFields.add(fieldInfo);
+ }
}
}
- }
- Collections.sort(clsFields, new Comparator<FieldInfo>() {
- @Override public int compare(FieldInfo t1, FieldInfo t2) {
- return t1.name().compareTo(t2.name());
- }
- });
+ Collections.sort(clsFields, new Comparator<FieldInfo>() {
+ @Override public int compare(FieldInfo t1, FieldInfo t2) {
+ return t1.name().compareTo(t2.name());
+ }
+ });
- fields.add(new ClassFields(clsFields));
+ fields.add(new ClassFields(clsFields));
+ }
}
Collections.reverse(writeObjMtds);
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/util/FeatureChecker.java b/modules/core/src/main/java/org/apache/ignite/internal/util/FeatureChecker.java
index 3a6775b6ec7..f017be33a8b 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/util/FeatureChecker.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/util/FeatureChecker.java
@@ -43,7 +43,11 @@ public class FeatureChecker {
"--add-opens=java.base/java.util=ALL-UNNAMED\n" +
"--add-opens=java.base/java.util.concurrent=ALL-UNNAMED\n" +
"--add-opens=java.base/java.util.concurrent.locks=ALL-UNNAMED\n" +
- "--add-opens=java.base/java.lang=ALL-UNNAMED";
+ "--add-opens=java.base/java.util.concurrent.atomic=ALL-UNNAMED\n" +
+ "--add-opens=java.base/java.lang=ALL-UNNAMED\n" +
+ "--add-opens=java.base/java.lang.invoke=ALL-UNNAMED\n" +
+ "--add-opens=java.base/java.math=ALL-UNNAMED\n" +
+ "--add-opens=java.sql/java.sql=ALL-UNNAMED";
/** Java version specific warning to be added in case access failed */
public static final String JAVA_VER_SPECIFIC_WARN =
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/util/IgniteUtils.java b/modules/core/src/main/java/org/apache/ignite/internal/util/IgniteUtils.java
index ec8764393c0..49b8954cfa1 100755
--- a/modules/core/src/main/java/org/apache/ignite/internal/util/IgniteUtils.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/util/IgniteUtils.java
@@ -12419,4 +12419,35 @@ public abstract class IgniteUtils {
public static boolean isRestartEnabled() {
return IGNITE_SUCCESS_FILE_PROPERTY != null;
}
+
+ /**
+ * Returns {@code true} if class is a lambda.
+ *
+ * @param objectClass Class.
+ * @return {@code true} if class is a lambda, {@code false} otherwise.
+ */
+ public static boolean isLambda(Class<?> objectClass) {
+ return !objectClass.isPrimitive() && !objectClass.isArray()
+ // Order is crucial here, isAnonymousClass and isLocalClass may fail if
+ // class' outer class was loaded with different classloader.
+ && objectClass.isSynthetic()
+ && !objectClass.isAnonymousClass() && !objectClass.isLocalClass()
+ && classCannotBeLoadedByName(objectClass);
+ }
+
+ /**
+ * Returns {@code true} if class can not be loaded by name.
+ *
+ * @param objectClass Class.
+ * @return {@code true} if class can not be loaded by name, {@code false} otherwise.
+ */
+ public static boolean classCannotBeLoadedByName(Class<?> objectClass) {
+ try {
+ Class.forName(objectClass.getName());
+ return false;
+ }
+ catch (ClassNotFoundException e) {
+ return true;
+ }
+ }
}
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/GridMultipleVersionsDeploymentSelfTest.java b/modules/core/src/test/java/org/apache/ignite/internal/GridMultipleVersionsDeploymentSelfTest.java
index 64f07420e9e..b4e424fc90d 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/GridMultipleVersionsDeploymentSelfTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/GridMultipleVersionsDeploymentSelfTest.java
@@ -58,6 +58,7 @@ import static org.apache.ignite.events.EventType.EVT_TASK_UNDEPLOYED;
public class GridMultipleVersionsDeploymentSelfTest extends GridCommonAbstractTest {
/** Excluded classes. */
private static final String[] EXCLUDE_CLASSES = new String[] {
+ GridMultipleVersionsDeploymentSelfTest.class.getName(),
GridDeploymentTestTask.class.getName(),
GridDeploymentTestJob.class.getName()
};
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/IgniteExplicitImplicitDeploymentSelfTest.java b/modules/core/src/test/java/org/apache/ignite/internal/IgniteExplicitImplicitDeploymentSelfTest.java
index fb89b410ee9..fd17c01471e 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/IgniteExplicitImplicitDeploymentSelfTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/IgniteExplicitImplicitDeploymentSelfTest.java
@@ -64,8 +64,11 @@ public class IgniteExplicitImplicitDeploymentSelfTest extends GridCommonAbstract
IgniteConfiguration cfg = super.getConfiguration(igniteInstanceName);
// Override P2P configuration to exclude Task and Job classes
- cfg.setPeerClassLoadingLocalClassPathExclude(GridDeploymentResourceTestTask.class.getName(),
- GridDeploymentResourceTestJob.class.getName());
+ cfg.setPeerClassLoadingLocalClassPathExclude(
+ IgniteExplicitImplicitDeploymentSelfTest.class.getName(),
+ GridDeploymentResourceTestTask.class.getName(),
+ GridDeploymentResourceTestJob.class.getName()
+ );
cfg.setDeploymentMode(DeploymentMode.ISOLATED);
@@ -316,6 +319,7 @@ public class IgniteExplicitImplicitDeploymentSelfTest extends GridCommonAbstract
ClassLoader ldr1 = new GridTestClassLoader(
Collections.singletonMap("testResource", "1"),
getClass().getClassLoader(),
+ IgniteExplicitImplicitDeploymentSelfTest.class.getName(),
GridDeploymentResourceTestTask.class.getName(),
GridDeploymentResourceTestJob.class.getName()
);
@@ -323,6 +327,7 @@ public class IgniteExplicitImplicitDeploymentSelfTest extends GridCommonAbstract
ClassLoader ldr2 = new GridTestClassLoader(
Collections.singletonMap("testResource", "2"),
getClass().getClassLoader(),
+ IgniteExplicitImplicitDeploymentSelfTest.class.getName(),
GridDeploymentResourceTestTask.class.getName(),
GridDeploymentResourceTestJob.class.getName()
);
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/persistence/snapshot/PlainSnapshotTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/persistence/snapshot/PlainSnapshotTest.java
index 3e0a32c3c26..c916610a758 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/persistence/snapshot/PlainSnapshotTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/persistence/snapshot/PlainSnapshotTest.java
@@ -52,6 +52,22 @@ public class PlainSnapshotTest extends AbstractSnapshotSelfTest {
return Collections.singletonList(false);
}
+ /** {@link AbstractSnapshotSelfTest.Account} with custom toString method. */
+ private static class AccountOverrideToString extends AbstractSnapshotSelfTest.Account {
+ /**
+ * @param id User id.
+ * @param balance User balance.
+ */
+ public AccountOverrideToString(int id, int balance) {
+ super(id, balance);
+ }
+
+ /** {@inheritDoc} */
+ @Override public String toString() {
+ return "_" + super.toString();
+ }
+ }
+
/**
* Checks, compares CRCs of partitions in snapshot data files against the source.
* <p>
@@ -70,13 +86,8 @@ public class PlainSnapshotTest extends AbstractSnapshotSelfTest {
IgniteEx ig = startGridsWithCache(1, 4096, key -> new AbstractSnapshotSelfTest.Account(key, key),
new CacheConfiguration<>(DEFAULT_CACHE_NAME));
- for (int i = 4096; i < 8192; i++) {
- ig.cache(DEFAULT_CACHE_NAME).put(i, new AbstractSnapshotSelfTest.Account(i, i) {
- @Override public String toString() {
- return "_" + super.toString();
- }
- });
- }
+ for (int i = 4096; i < 8192; i++)
+ ig.cache(DEFAULT_CACHE_NAME).put(i, new AccountOverrideToString(i, i));
GridCacheSharedContext<?, ?> cctx = ig.context().cache().context();
IgniteSnapshotManager mgr = snp(ig);
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/util/IgniteUtilsSelfTest.java b/modules/core/src/test/java/org/apache/ignite/internal/util/IgniteUtilsSelfTest.java
index 9fbd2b916f0..86af58cf6fa 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/util/IgniteUtilsSelfTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/util/IgniteUtilsSelfTest.java
@@ -78,6 +78,7 @@ import org.apache.ignite.lang.IgniteBiTuple;
import org.apache.ignite.lang.IgnitePredicate;
import org.apache.ignite.lang.IgniteProductVersion;
import org.apache.ignite.spi.discovery.tcp.internal.TcpDiscoveryNode;
+import org.apache.ignite.testframework.GridTestClassLoader;
import org.apache.ignite.testframework.GridTestUtils;
import org.apache.ignite.testframework.http.GridEmbeddedHttpServer;
import org.apache.ignite.testframework.junits.WithSystemProperty;
@@ -1511,6 +1512,71 @@ public class IgniteUtilsSelfTest extends GridCommonAbstractTest {
testAddressResolveWithLocalHostDefined();
}
+ /**
+ * Tests {@link IgniteUtils#isLambda(Class)} on lambdas.
+ */
+ @Test
+ public void testIsLambdaOnLambdas() {
+ Runnable someLambda = () -> {};
+
+ int localVar = 0;
+ Runnable capturingLocalLambda = () -> {
+ System.out.println(localVar);
+ };
+
+ Runnable capturingOuterClassLambda = () -> {
+ System.out.println(repeatRule);
+ };
+
+ Runnable methodReference = this::testIsLambdaOnLambdas;
+
+ assertTrue(IgniteUtils.isLambda(someLambda.getClass()));
+ assertTrue(IgniteUtils.isLambda(capturingLocalLambda.getClass()));
+ assertTrue(IgniteUtils.isLambda(capturingOuterClassLambda.getClass()));
+ assertTrue(IgniteUtils.isLambda(methodReference.getClass()));
+ }
+
+ /** Test nested class. */
+ private static class TestNestedClass {
+ }
+
+ /** Test inner class. */
+ private class TestInnerClass {
+ }
+
+ /**
+ * Tests {@link IgniteUtils#isLambda(Class)} on non-lambda classes.
+ */
+ @Test
+ public void testIsLambdaOnOrdinaryClasses() throws Exception {
+ assertFalse(IgniteUtils.isLambda(Object.class));
+
+ Runnable anonCls = new Runnable() {
+ /** {@inheritDoc} */
+ @Override public void run() {
+ // No-op.
+ }
+ };
+
+ assertFalse(IgniteUtils.isLambda(anonCls.getClass()));
+ assertFalse(IgniteUtils.isLambda(TestEnum.class));
+
+ // Loading only inner class with test classloader, while outer class
+ // will be loaded with the default classloader. Thus, if we execute method like isAnonymousClass
+ // on the loaded class, it will fail with the IncompatibleClassChangeError. That's why order in
+ // IgniteUtils isLambda is important.
+ GridTestClassLoader clsLdr = new GridTestClassLoader(
+ TestNestedClass.class.getName(),
+ TestInnerClass.class.getName()
+ );
+
+ Class<?> nestedCls = clsLdr.loadClass(TestNestedClass.class.getName());
+ assertFalse(IgniteUtils.isLambda(nestedCls));
+
+ Class<?> innerCls = clsLdr.loadClass(TestInnerClass.class.getName());
+ assertFalse(IgniteUtils.isLambda(innerCls));
+ }
+
/**
* Tests {@link IgniteUtils#resolveLocalAddresses(InetAddress)} with different values set to
* {@link IgniteSystemProperties#IGNITE_LOCAL_HOST} and {@link IgniteSystemProperties#IGNITE_IGNORE_LOCAL_HOST_NAME}.
diff --git a/modules/core/src/test/java/org/apache/ignite/p2p/GridP2PRemoteClassLoadersSelfTest.java b/modules/core/src/test/java/org/apache/ignite/p2p/GridP2PRemoteClassLoadersSelfTest.java
index a19fb8c570a..7364efbddfd 100644
--- a/modules/core/src/test/java/org/apache/ignite/p2p/GridP2PRemoteClassLoadersSelfTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/p2p/GridP2PRemoteClassLoadersSelfTest.java
@@ -84,6 +84,7 @@ public class GridP2PRemoteClassLoadersSelfTest extends GridCommonAbstractTest {
ClassLoader tstClsLdr =
new GridTestClassLoader(
Collections.<String, String>emptyMap(), getClass().getClassLoader(),
+ GridP2PRemoteClassLoadersSelfTest.class.getName(),
GridP2PRemoteTestTask.class.getName(), GridP2PRemoteTestTask1.class.getName(),
GridP2PRemoteTestJob.class.getName());
@@ -136,12 +137,14 @@ public class GridP2PRemoteClassLoadersSelfTest extends GridCommonAbstractTest {
ClassLoader tstClsLdr1 =
new GridTestClassLoader(
Collections.EMPTY_MAP, getClass().getClassLoader(),
+ GridP2PRemoteClassLoadersSelfTest.class.getName(),
GridP2PRemoteTestTask.class.getName(), GridP2PRemoteTestJob.class.getName()
);
ClassLoader tstClsLdr2 =
new GridTestClassLoader(
Collections.EMPTY_MAP, getClass().getClassLoader(),
+ GridP2PRemoteClassLoadersSelfTest.class.getName(),
GridP2PRemoteTestTask1.class.getName(), GridP2PRemoteTestJob.class.getName());
Class<? extends ComputeTask<?, ?>> task1 =
diff --git a/parent/pom.xml b/parent/pom.xml
index bfcfaed6b88..7f2af3df26c 100644
--- a/parent/pom.xml
+++ b/parent/pom.xml
@@ -1024,8 +1024,10 @@
--add-opens=java.base/java.util=ALL-UNNAMED
--add-opens=java.base/java.util.concurrent=ALL-UNNAMED
--add-opens=java.base/java.util.concurrent.locks=ALL-UNNAMED
+ --add-opens=java.base/java.util.concurrent.atomic=ALL-UNNAMED
--add-opens=java.base/java.lang=ALL-UNNAMED
--add-opens=java.base/java.lang.invoke=ALL-UNNAMED
+ --add-opens=java.base/java.math=ALL-UNNAMED
--add-opens=java.sql/java.sql=ALL-UNNAMED
</argLine>
</configuration>