This is an automated email from the ASF dual-hosted git repository. sdanilov pushed a commit to branch ignite-17962 in repository https://gitbox.apache.org/repos/asf/ignite.git
commit 1cb48a09fbfc28f59cef35ce1c31e6264aae73eb Author: Semyon Danilov <[email protected]> AuthorDate: Fri Oct 21 20:46:09 2022 +0400 IGNITE-17962 Fix serializable lambda serialization with Java17 --- bin/include/jvmdefaults.bat | 2 + bin/include/jvmdefaults.sh | 2 + .../internal/binary/BinaryClassDescriptor.java | 80 ++++---- .../optimized/OptimizedClassDescriptor.java | 220 +++++++++++---------- .../apache/ignite/internal/util/IgniteUtils.java | 31 +++ .../GridMultipleVersionsDeploymentSelfTest.java | 1 + .../IgniteExplicitImplicitDeploymentSelfTest.java | 9 +- .../ignite/internal/util/IgniteUtilsSelfTest.java | 66 +++++++ .../p2p/GridP2PRemoteClassLoadersSelfTest.java | 3 + 9 files changed, 271 insertions(+), 143 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..a6d8e079d10 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,71 @@ 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<>(); + // We don't need fields for serializable lambdas, because we resort to SerializedLambda. + fields = null; + stableFieldsMeta = null; + stableSchema = null; + } else { + Map<Object, BinaryFieldAccessor> fields0; - stableFieldsMeta = metaDataEnabled ? new TreeMap<String, BinaryFieldMetadata>() : null; - } - else { - fields0 = new LinkedHashMap<>(); + if (BinaryUtils.FIELDS_SORTED_ORDER) { + fields0 = new TreeMap<>(); - stableFieldsMeta = metaDataEnabled ? new LinkedHashMap<String, BinaryFieldMetadata>() : null; - } + stableFieldsMeta = metaDataEnabled ? new TreeMap<String, BinaryFieldMetadata>() : null; + } + else { + fields0 = new LinkedHashMap<>(); + + stableFieldsMeta = metaDataEnabled ? new LinkedHashMap<String, BinaryFieldMetadata>() : null; + } - Set<String> duplicates = duplicateFields(cls); + Set<String> duplicates = duplicateFields(cls); - Collection<String> names = new HashSet<>(); - Collection<Integer> ids = new HashSet<>(); + Collection<String> names = new HashSet<>(); + Collection<Integer> ids = new HashSet<>(); - for (Class<?> c = cls; c != null && !c.equals(Object.class); c = c.getSuperclass()) { - for (Field f : c.getDeclaredFields()) { - if (serializeField(f)) { - f.setAccessible(true); + for (Class<?> c = cls; c != null && !c.equals(Object.class); c = c.getSuperclass()) { + for (Field f : c.getDeclaredFields()) { + if (serializeField(f)) { + f.setAccessible(true); - String name = f.getName(); + String name = f.getName(); - if (duplicates.contains(name)) - name = BinaryUtils.qualifiedFieldName(c, name); + if (duplicates.contains(name)) + name = BinaryUtils.qualifiedFieldName(c, name); - boolean added = names.add(name); + boolean added = names.add(name); - assert added : name; + assert added : name; - int fieldId = this.mapper.fieldId(typeId, name); + int fieldId = this.mapper.fieldId(typeId, name); - if (!ids.add(fieldId)) - throw new BinaryObjectException("Duplicate field ID: " + name); + if (!ids.add(fieldId)) + throw new BinaryObjectException("Duplicate field ID: " + name); - BinaryFieldAccessor fieldInfo = BinaryFieldAccessor.create(f, fieldId); + BinaryFieldAccessor fieldInfo = BinaryFieldAccessor.create(f, fieldId); - fields0.put(name, fieldInfo); + fields0.put(name, fieldInfo); - if (metaDataEnabled) - stableFieldsMeta.put(name, new BinaryFieldMetadata(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..e15f3743326 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,165 @@ 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); - 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/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/util/IgniteUtilsSelfTest.java b/modules/core/src/test/java/org/apache/ignite/internal/util/IgniteUtilsSelfTest.java index 9fbd2b916f0..30e31709f3d 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 =
