This is an automated email from the ASF dual-hosted git repository.

timoninmaxim 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 62b38863b7f IGNITE-27865 Use ClassLoader for deserializing users' Pojo 
in collections (#12745)
62b38863b7f is described below

commit 62b38863b7f808620aec92a310cf67b25ecd9bfe
Author: Maksim Timonin <[email protected]>
AuthorDate: Wed Feb 18 23:14:52 2026 +0300

    IGNITE-27865 Use ClassLoader for deserializing users' Pojo in collections 
(#12745)
---
 .../processors/cache/CacheObjectUtils.java         |  30 +++--
 .../p2p/startcache/PojoCollectionComputeTest.java  | 127 +++++++++++++++++++++
 .../cache/ComputeCacheCollectionsP2PTest.java      |  95 +++++++++++++++
 .../IgniteCacheWithIndexingTestSuite.java          |   2 +
 4 files changed, 245 insertions(+), 9 deletions(-)

diff --git 
a/modules/binary/api/src/main/java/org/apache/ignite/internal/processors/cache/CacheObjectUtils.java
 
b/modules/binary/api/src/main/java/org/apache/ignite/internal/processors/cache/CacheObjectUtils.java
index e33e2c12f53..1020783d950 100644
--- 
a/modules/binary/api/src/main/java/org/apache/ignite/internal/processors/cache/CacheObjectUtils.java
+++ 
b/modules/binary/api/src/main/java/org/apache/ignite/internal/processors/cache/CacheObjectUtils.java
@@ -96,16 +96,22 @@ public class CacheObjectUtils {
      * @param col Collection to unwrap.
      * @param keepBinary Keep binary flag.
      * @param cpy Copy flag.
+     * @param ldr Optional classloader.
      * @return Unwrapped collection.
      */
-    private static Collection<Object> 
unwrapKnownCollection(CacheObjectValueContext ctx, Collection<?> col,
-        boolean keepBinary, boolean cpy) {
+    private static Collection<Object> unwrapKnownCollection(
+        CacheObjectValueContext ctx,
+        Collection<?> col,
+        boolean keepBinary,
+        boolean cpy,
+        @Nullable ClassLoader ldr
+    ) {
         Collection<Object> col0 = BinaryUtils.newKnownCollection(col);
 
         assert col0 != null;
 
         for (Object obj : col)
-            col0.add(unwrapBinary(ctx, obj, keepBinary, cpy, null));
+            col0.add(unwrapBinary(ctx, obj, keepBinary, cpy, ldr));
 
         return (col0 instanceof MutableSingletonList) ? 
CommonUtils.convertToSingletonList(col0) : col0;
     }
@@ -115,10 +121,16 @@ public class CacheObjectUtils {
      *
      * @param map Map to unwrap.
      * @param keepBinary Keep binary flag.
+     * @param ldr Optional class loader.
      * @return Unwrapped collection.
      */
-    private static Map<Object, Object> 
unwrapBinariesIfNeeded(CacheObjectValueContext ctx, Map<Object, Object> map,
-        boolean keepBinary, boolean cpy) {
+    private static Map<Object, Object> unwrapBinariesIfNeeded(
+        CacheObjectValueContext ctx,
+        Map<Object, Object> map,
+        boolean keepBinary,
+        boolean cpy,
+        @Nullable ClassLoader ldr
+    ) {
         if (keepBinary)
             return map;
 
@@ -127,8 +139,8 @@ public class CacheObjectUtils {
         for (Map.Entry<Object, Object> e : map.entrySet())
             // TODO why don't we use keepBinary parameter here?
             map0.put(
-                unwrapBinary(ctx, e.getKey(), false, cpy, null),
-                unwrapBinary(ctx, e.getValue(), false, cpy, null));
+                unwrapBinary(ctx, e.getKey(), false, cpy, ldr),
+                unwrapBinary(ctx, e.getValue(), false, cpy, ldr));
 
         return map0;
     }
@@ -204,9 +216,9 @@ public class CacheObjectUtils {
         }
 
         if (BinaryUtils.knownCollection(o))
-            return unwrapKnownCollection(ctx, (Collection<Object>)o, 
keepBinary, cpy);
+            return unwrapKnownCollection(ctx, (Collection<Object>)o, 
keepBinary, cpy, ldr);
         else if (BinaryUtils.knownMap(o))
-            return unwrapBinariesIfNeeded(ctx, (Map<Object, Object>)o, 
keepBinary, cpy);
+            return unwrapBinariesIfNeeded(ctx, (Map<Object, Object>)o, 
keepBinary, cpy, ldr);
         else if (o instanceof Object[] && !BinaryUtils.useBinaryArrays())
             return unwrapBinariesInArrayIfNeeded(ctx, (Object[])o, keepBinary, 
cpy);
         else if (BinaryUtils.isBinaryArray(o) && !keepBinary)
diff --git 
a/modules/extdata/p2p/src/main/java/org/apache/ignite/tests/p2p/startcache/PojoCollectionComputeTest.java
 
b/modules/extdata/p2p/src/main/java/org/apache/ignite/tests/p2p/startcache/PojoCollectionComputeTest.java
new file mode 100644
index 00000000000..a5b7d8c85de
--- /dev/null
+++ 
b/modules/extdata/p2p/src/main/java/org/apache/ignite/tests/p2p/startcache/PojoCollectionComputeTest.java
@@ -0,0 +1,127 @@
+/*
+ * 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.tests.p2p.startcache;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import org.apache.ignite.Ignite;
+import org.apache.ignite.IgniteCache;
+import org.apache.ignite.Ignition;
+import org.apache.ignite.configuration.IgniteConfiguration;
+import org.apache.ignite.lang.IgniteRunnable;
+import org.apache.ignite.resources.IgniteInstanceResource;
+import org.apache.ignite.spi.discovery.tcp.TcpDiscoverySpi;
+import org.apache.ignite.spi.discovery.tcp.ipfinder.vm.TcpDiscoveryVmIpFinder;
+import org.apache.ignite.tests.p2p.cache.Person;
+
+import static org.junit.Assert.assertEquals;
+
+/** */
+public class PojoCollectionComputeTest {
+    /** */
+    private void run(String taskName) {
+        IgniteConfiguration cfg = new IgniteConfiguration()
+            .setPeerClassLoadingEnabled(true)
+            .setClientMode(true)
+            .setLocalHost("127.0.0.1")
+            .setDiscoverySpi(new TcpDiscoverySpi()
+                .setIpFinder(new TcpDiscoveryVmIpFinder()
+                    
.setAddresses(Collections.singletonList("127.0.0.1:47500..47509"))));
+
+        try (Ignite ignite = Ignition.start(cfg)) {
+            IgniteRunnable task;
+
+            if (PojoArrayTask.class.getSimpleName().equals(taskName))
+                task = new PojoArrayTask();
+            else if (PojoListTask.class.getSimpleName().equals(taskName))
+                task = new PojoListTask();
+            else
+                task = new PojoMapTask();
+
+            ignite.compute().run(task);
+        }
+    }
+
+    /** */
+    private static class PojoArrayTask implements IgniteRunnable {
+        /** */
+        @IgniteInstanceResource
+        private transient Ignite ignite;
+
+        /** */
+        @Override public void run() {
+            IgniteCache<Integer, Object[]> cache = 
ignite.getOrCreateCache("personArrayCache");
+
+            Object[] objs = new Object[1];
+            objs[0] = new Person("name0");
+
+            cache.put(0, objs);
+
+            Object[] get = cache.get(0);
+            assertEquals(objs[0], get[0]);
+        }
+    }
+
+    /** */
+    private static class PojoListTask implements IgniteRunnable {
+        /** */
+        @IgniteInstanceResource
+        private transient Ignite ignite;
+
+        /** */
+        @Override public void run() {
+            IgniteCache<Integer, List<Person>> personListCache = 
ignite.getOrCreateCache("personListCache");
+
+            List<Person> persons = new ArrayList<>();
+            persons.add(new Person("name0"));
+
+            personListCache.put(0, persons);
+
+            List<Person> get = personListCache.get(0);
+            assertEquals(persons.get(0), get.get(0));
+        }
+    }
+
+    /** */
+    private static class PojoMapTask implements IgniteRunnable {
+        /** */
+        @IgniteInstanceResource
+        private transient Ignite ignite;
+
+        /** */
+        @Override public void run() {
+            IgniteCache<Person, Map<Person, Person>> personMapCache = 
ignite.getOrCreateCache("personMapCache");
+
+            Map<Person, Person> persons = new HashMap<>();
+            persons.put(new Person("nameValKey"), new Person("nameValVal"));
+
+            personMapCache.put(new Person("nameKey"), persons);
+
+            Map<Person, Person> get = personMapCache.get(new 
Person("nameKey"));
+            assertEquals(persons, get);
+        }
+    }
+
+    /** */
+    public static void main(String[] args) {
+        new PojoCollectionComputeTest().run(args[0]);
+    }
+}
diff --git 
a/modules/indexing/src/test/java/org/apache/ignite/internal/processors/cache/ComputeCacheCollectionsP2PTest.java
 
b/modules/indexing/src/test/java/org/apache/ignite/internal/processors/cache/ComputeCacheCollectionsP2PTest.java
new file mode 100644
index 00000000000..4a8e6cba089
--- /dev/null
+++ 
b/modules/indexing/src/test/java/org/apache/ignite/internal/processors/cache/ComputeCacheCollectionsP2PTest.java
@@ -0,0 +1,95 @@
+/*
+ * 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.processors.cache;
+
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import org.apache.ignite.Ignite;
+import org.apache.ignite.Ignition;
+import org.apache.ignite.configuration.IgniteConfiguration;
+import org.apache.ignite.internal.util.GridJavaProcess;
+import org.apache.ignite.internal.util.typedef.internal.U;
+import org.apache.ignite.spi.discovery.tcp.TcpDiscoverySpi;
+import org.apache.ignite.spi.discovery.tcp.ipfinder.vm.TcpDiscoveryVmIpFinder;
+import org.apache.ignite.testframework.junits.WithSystemProperty;
+import org.apache.ignite.testframework.junits.common.GridCommonAbstractTest;
+import org.junit.Test;
+
+import static 
org.apache.ignite.IgniteCommonsSystemProperties.IGNITE_USE_BINARY_ARRAYS;
+
+/** */
+public class ComputeCacheCollectionsP2PTest extends GridCommonAbstractTest {
+    /** */
+    private static final String CLIENT_CLS_NAME =
+        "org.apache.ignite.tests.p2p.startcache.PojoCollectionComputeTest";
+
+    /** */
+    @Test
+    @WithSystemProperty(key = IGNITE_USE_BINARY_ARRAYS, value = "true")
+    public void testBinaryArray() throws Exception {
+        runTest("PojoArrayTask");
+    }
+
+    /** */
+    @Test
+    public void testArrayList() throws Exception {
+        runTest("PojoListTask");
+    }
+
+    /** */
+    @Test
+    public void testHashMap() throws Exception {
+        runTest("PojoMapTask");
+    }
+
+    /** */
+    private void runTest(String taskName) throws Exception {
+        try (Ignite ignore = Ignition.start(createConfiguration())) {
+            Collection<String> jvmArgs = Arrays.asList("-ea", 
"-DIGNITE_QUIET=false");
+            String cp = U.getIgniteHome() + 
"/modules/extdata/p2p/target/classes/";
+
+            GridJavaProcess clientNode = GridJavaProcess.exec(
+                CLIENT_CLS_NAME,
+                taskName,
+                log,
+                null,
+                null,
+                null,
+                jvmArgs,
+                cp
+            );
+
+            int exitCode = clientNode.getProcess().waitFor();
+
+            assertEquals("Unexpected exit code", 0, exitCode);
+        }
+    }
+
+    /** */
+    private IgniteConfiguration createConfiguration() {
+        return new IgniteConfiguration()
+            .setPeerClassLoadingEnabled(true)
+            .setLocalHost("127.0.0.1")
+            .setDiscoverySpi(new TcpDiscoverySpi()
+                .setIpFinder(
+                    new TcpDiscoveryVmIpFinder()
+                        
.setAddresses(Collections.singletonList("127.0.0.1:47500..47509"))
+                ));
+    }
+}
diff --git 
a/modules/indexing/src/test/java/org/apache/ignite/testsuites/IgniteCacheWithIndexingTestSuite.java
 
b/modules/indexing/src/test/java/org/apache/ignite/testsuites/IgniteCacheWithIndexingTestSuite.java
index 9b8c26ab6b2..2e78be26fda 100644
--- 
a/modules/indexing/src/test/java/org/apache/ignite/testsuites/IgniteCacheWithIndexingTestSuite.java
+++ 
b/modules/indexing/src/test/java/org/apache/ignite/testsuites/IgniteCacheWithIndexingTestSuite.java
@@ -33,6 +33,7 @@ import 
org.apache.ignite.internal.processors.cache.CacheRegisterMetadataLocallyT
 import 
org.apache.ignite.internal.processors.cache.ClientReconnectAfterClusterRestartTest;
 import 
org.apache.ignite.internal.processors.cache.ClusterReadOnlyModeDoesNotBreakSqlSelectTest;
 import org.apache.ignite.internal.processors.cache.ClusterReadOnlyModeSqlTest;
+import 
org.apache.ignite.internal.processors.cache.ComputeCacheCollectionsP2PTest;
 import 
org.apache.ignite.internal.processors.cache.EnumClassImplementingIndexedInterfaceTest;
 import org.apache.ignite.internal.processors.cache.FieldsPrecisionTest;
 import org.apache.ignite.internal.processors.cache.GridCacheOffHeapSelfTest;
@@ -105,6 +106,7 @@ import org.junit.runners.Suite;
 
     ClusterReadOnlyModeSqlTest.class,
     GridCacheSqlDdlClusterReadOnlyModeTest.class,
+    ComputeCacheCollectionsP2PTest.class,
 
     ClusterReadOnlyModeDoesNotBreakSqlSelectTest.class,
 

Reply via email to