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

nizhikov 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 ce12249e28f IGNITE-22549 CacheScanTask json output format (#11402)
ce12249e28f is described below

commit ce12249e28f019dab620aad48d2659df5f9e4b66
Author: Nikolay <[email protected]>
AuthorDate: Thu Jun 27 14:32:46 2024 +0300

    IGNITE-22549 CacheScanTask json output format (#11402)
---
 modules/bom/pom.xml                                |   5 +
 .../common/AbstractEventSecurityContextTest.java   |   4 +-
 .../rest/JettyRestProcessorCommonSelfTest.java     |   4 +-
 modules/control-utility/pom.xml                    |   6 +
 .../util/GridCommandHandlerClusterByClassTest.java | 199 ++++++++++++++++++-
 .../java/org/apache/ignite/dump/DumpReader.java    |   6 +-
 .../cache/scan/DefaultCacheScanTaskFormat.java     |  46 ++++-
 .../cache/persistence/snapshot/dump/Dump.java      |   5 +
 .../dump/DumpConsumerKernalContextAware.java       |  33 ++++
 .../snapshot/dump/AbstractCacheDumpTest.java       | 215 ++++++++++++---------
 .../snapshot/dump/IgniteCacheDumpSelfTest.java     |  33 ++--
 modules/json/README.txt                            |   4 +
 modules/{rest-http => json}/pom.xml                |  77 +-------
 .../org/apache/ignite/dump/JsonDumpConsumer.java   | 151 +++++++++++++++
 .../IgniteBinaryObjectJsonDeserializer.java        |   2 +-
 .../internal/jackson/IgniteObjectMapper.java}      |  16 +-
 .../cache/scan/JsonCacheScanTaskFormat.java        |  57 ++++++
 ...ernal.management.cache.scan.CacheScanTaskFormat |   1 +
 .../org/apache/ignite/dump/IgniteJsonSuite.java    |  31 +++
 .../apache/ignite/dump/JsonDumpConsumerTest.java   | 194 +++++++++++++++++++
 modules/rest-http/pom.xml                          |  23 +--
 .../protocols/http/jetty/GridJettyRestHandler.java |   4 +-
 pom.xml                                            |   1 +
 23 files changed, 905 insertions(+), 212 deletions(-)

diff --git a/modules/bom/pom.xml b/modules/bom/pom.xml
index 40ea220bdd2..32d6659279a 100644
--- a/modules/bom/pom.xml
+++ b/modules/bom/pom.xml
@@ -116,6 +116,11 @@
                 <artifactId>ignite-opencensus</artifactId>
                 <version>${revision}</version>
             </dependency>
+            <dependency>
+                <groupId>${project.groupId}</groupId>
+                <artifactId>ignite-json</artifactId>
+                <version>${revision}</version>
+            </dependency>
             <dependency>
                 <groupId>${project.groupId}</groupId>
                 <artifactId>ignite-rest-http</artifactId>
diff --git 
a/modules/clients/src/test/java/org/apache/ignite/common/AbstractEventSecurityContextTest.java
 
b/modules/clients/src/test/java/org/apache/ignite/common/AbstractEventSecurityContextTest.java
index de0b11b7ead..81b17713c2c 100644
--- 
a/modules/clients/src/test/java/org/apache/ignite/common/AbstractEventSecurityContextTest.java
+++ 
b/modules/clients/src/test/java/org/apache/ignite/common/AbstractEventSecurityContextTest.java
@@ -42,8 +42,8 @@ import org.apache.ignite.events.Event;
 import org.apache.ignite.events.JobEvent;
 import org.apache.ignite.events.TaskEvent;
 import org.apache.ignite.internal.IgniteEx;
+import org.apache.ignite.internal.jackson.IgniteObjectMapper;
 import org.apache.ignite.internal.processors.rest.GridRestCommand;
-import 
org.apache.ignite.internal.processors.rest.protocols.http.jetty.GridJettyObjectMapper;
 import org.apache.ignite.internal.processors.security.AbstractSecurityTest;
 import org.apache.ignite.internal.processors.security.impl.TestSecurityData;
 import 
org.apache.ignite.internal.processors.security.impl.TestSecurityPluginProvider;
@@ -64,7 +64,7 @@ public abstract class AbstractEventSecurityContextTest 
extends AbstractSecurityT
     protected static final Map<ClusterNode, Collection<Event>> LISTENED_EVTS = 
new ConcurrentHashMap<>();
 
     /** Custom object mapper for HTTP REST API.  */
-    private static final ObjectMapper OBJECT_MAPPER = new 
GridJettyObjectMapper();
+    private static final ObjectMapper OBJECT_MAPPER = new IgniteObjectMapper();
 
     /** Port for REST client connection. */
     private static final String DFLT_REST_PORT = "11080";
diff --git 
a/modules/clients/src/test/java/org/apache/ignite/internal/processors/rest/JettyRestProcessorCommonSelfTest.java
 
b/modules/clients/src/test/java/org/apache/ignite/internal/processors/rest/JettyRestProcessorCommonSelfTest.java
index 9976c1c52ca..e38386d8bdc 100644
--- 
a/modules/clients/src/test/java/org/apache/ignite/internal/processors/rest/JettyRestProcessorCommonSelfTest.java
+++ 
b/modules/clients/src/test/java/org/apache/ignite/internal/processors/rest/JettyRestProcessorCommonSelfTest.java
@@ -29,7 +29,7 @@ import java.util.LinkedHashMap;
 import java.util.Map;
 import com.fasterxml.jackson.databind.JsonNode;
 import com.fasterxml.jackson.databind.ObjectMapper;
-import 
org.apache.ignite.internal.processors.rest.protocols.http.jetty.GridJettyObjectMapper;
+import org.apache.ignite.internal.jackson.IgniteObjectMapper;
 import org.apache.ignite.internal.util.typedef.internal.SB;
 
 import static org.apache.ignite.IgniteSystemProperties.IGNITE_JETTY_PORT;
@@ -48,7 +48,7 @@ public abstract class JettyRestProcessorCommonSelfTest 
extends AbstractRestProce
     private static final int DFLT_REST_PORT = 8091;
 
     /** JSON to java mapper. */
-    protected static final ObjectMapper JSON_MAPPER = new 
GridJettyObjectMapper();
+    protected static final ObjectMapper JSON_MAPPER = new IgniteObjectMapper();
 
     /** {@inheritDoc} */
     @Override protected void beforeTestsStarted() throws Exception {
diff --git a/modules/control-utility/pom.xml b/modules/control-utility/pom.xml
index 56964c5a55a..6dd782bf2a2 100644
--- a/modules/control-utility/pom.xml
+++ b/modules/control-utility/pom.xml
@@ -85,6 +85,12 @@
             <scope>test</scope>
         </dependency>
 
+        <dependency>
+            <groupId>${project.groupId}</groupId>
+            <artifactId>ignite-json</artifactId>
+            <scope>test</scope>
+        </dependency>
+
         <dependency>
             <groupId>org.apache.logging.log4j</groupId>
             <artifactId>log4j-slf4j-impl</artifactId>
diff --git 
a/modules/control-utility/src/test/java/org/apache/ignite/util/GridCommandHandlerClusterByClassTest.java
 
b/modules/control-utility/src/test/java/org/apache/ignite/util/GridCommandHandlerClusterByClassTest.java
index 13d380ddc6c..99a2b156432 100644
--- 
a/modules/control-utility/src/test/java/org/apache/ignite/util/GridCommandHandlerClusterByClassTest.java
+++ 
b/modules/control-utility/src/test/java/org/apache/ignite/util/GridCommandHandlerClusterByClassTest.java
@@ -32,6 +32,8 @@ import java.util.HashMap;
 import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
+import java.util.Objects;
+import java.util.Scanner;
 import java.util.Set;
 import java.util.TreeMap;
 import java.util.TreeSet;
@@ -51,6 +53,8 @@ import java.util.logging.StreamHandler;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
 import java.util.stream.Collectors;
+import com.fasterxml.jackson.core.type.TypeReference;
+import com.fasterxml.jackson.databind.ObjectMapper;
 import com.github.difflib.text.DiffRow;
 import com.github.difflib.text.DiffRowGenerator;
 import org.apache.ignite.Ignite;
@@ -75,6 +79,7 @@ import org.apache.ignite.internal.client.thin.TcpIgniteClient;
 import org.apache.ignite.internal.commandline.ArgumentParser;
 import org.apache.ignite.internal.commandline.CommandHandler;
 import org.apache.ignite.internal.dto.IgniteDataTransferObject;
+import org.apache.ignite.internal.jackson.IgniteObjectMapper;
 import org.apache.ignite.internal.management.IgniteCommandRegistry;
 import org.apache.ignite.internal.management.api.HelpCommand;
 import org.apache.ignite.internal.management.api.Positional;
@@ -83,6 +88,7 @@ import 
org.apache.ignite.internal.management.cache.CacheCommand;
 import org.apache.ignite.internal.management.cache.CacheDestroyCommand;
 import org.apache.ignite.internal.management.cache.IdleVerifyDumpTask;
 import 
org.apache.ignite.internal.management.cache.scan.DefaultCacheScanTaskFormat;
+import 
org.apache.ignite.internal.management.cache.scan.JsonCacheScanTaskFormat;
 import 
org.apache.ignite.internal.management.cache.scan.TableCacheScanTaskFormat;
 import org.apache.ignite.internal.management.tx.TxTaskResult;
 import org.apache.ignite.internal.processors.cache.CacheGroupContext;
@@ -1693,7 +1699,13 @@ public class GridCommandHandlerClusterByClassTest 
extends GridCommandHandlerClus
 
         c3.put(1, new TestClass2(
             1,
+            new boolean[]{true, false},
+            new char[] {'t', 'e', 's', 't'},
+            new short[] {1, 2, 3},
             new int[]{2, 3},
+            new long[] {4, 5},
+            new float[]{},
+            new double[]{42.0},
             Collections.singletonMap("some_key", "some_value"),
             new String[] {"s1", "s2", "s3"},
             DATE,
@@ -1703,7 +1715,13 @@ public class GridCommandHandlerClusterByClassTest 
extends GridCommandHandlerClus
 
         c3.put(2, new TestClass2(
             2,
-            new int[]{3, 4},
+            new boolean[]{true, false},
+            new char[] {'t', 'e', 's', 't'},
+            new short[] {1, 2, 3},
+            new int[]{2, 3},
+            new long[] {4, 5},
+            new float[]{123.0f},
+            new double[] {0},
             Collections.singletonMap("1", "2"),
             new String[] {"s4", "s5", "s6"},
             DATE,
@@ -1713,7 +1731,13 @@ public class GridCommandHandlerClusterByClassTest 
extends GridCommandHandlerClus
 
         c3.put(3, new TestClass2(
             3,
-            new int[]{4, 5},
+            new boolean[]{true, false},
+            new char[] {'t', 'e', 's', 't'},
+            new short[] {1, 2, 3},
+            new int[]{2, 3},
+            new long[] {4, 5},
+            new float[]{123.0f},
+            new double[] {1},
             Collections.singletonMap("xxx", "yyy"),
             new String[] {"s7", "s8", "s9"},
             DATE,
@@ -1753,9 +1777,140 @@ public class GridCommandHandlerClusterByClassTest 
extends GridCommandHandlerClus
 
         assertContains(log, testOut.toString(), "some_key=some_value");
         assertContains(log, testOut.toString(), "xxx=yyy");
+        assertContains(log, testOut.toString(), "[s1, s2, s3]");
         assertContains(log, testOut.toString(), DATE.toString());
     }
 
+    /** */
+    @Test
+    public void testCacheScanJsonFormat() throws Exception {
+        injectTestSystemOut();
+
+        autoConfirmation = false;
+
+        dataForScanTest();
+
+        assertEquals(EXIT_CODE_OK, execute("--cache", SCAN, "--output-format", 
JsonCacheScanTaskFormat.NAME, "cache1"));
+
+        Scanner sc = new Scanner(testOut.toString());
+
+        while (sc.hasNextLine() && !Objects.equals(sc.nextLine().trim(), 
"data")) ;
+
+        TypeReference<HashMap<String, Object>> typeRef = new 
TypeReference<HashMap<String, Object>>() {
+            // No-op.
+        };
+
+        ObjectMapper mapper = new ObjectMapper();
+
+        Set<Integer> keys = new HashSet<>();
+
+        for (int i = 0; i < 3; i++) {
+            assertTrue(sc.hasNextLine());
+
+            Map<String, Object> entryFromJson = 
mapper.readValue(sc.nextLine(), typeRef);
+
+            int key = (int)((Map<String, 
Object>)entryFromJson.get("key")).get("id");
+
+            keys.add(key);
+
+            Map<String, Object> val = (Map<String, 
Object>)entryFromJson.get("value");
+
+            if (key == 1)
+                assertEquals(JOHN, val.get("fio"));
+            else if (key == 2)
+                assertEquals(SARAH, val.get("fio"));
+            else
+                assertEquals(KYLE, val.get("fio"));
+
+            assertEquals(key + 1, val.get("salary"));
+        }
+
+        assertTrue(keys.containsAll(Arrays.asList(1, 2, 3)));
+
+        keys.clear();
+
+        assertEquals(EXIT_CODE_OK, execute("--cache", SCAN, "--output-format", 
JsonCacheScanTaskFormat.NAME, "cache2"));
+
+        sc = new Scanner(testOut.toString());
+
+        while (sc.hasNextLine() && !Objects.equals(sc.nextLine().trim(), 
"data")) ;
+
+        for (int i = 0; i < 3; i++) {
+            assertTrue(sc.hasNextLine());
+
+            Map<String, Object> entryFromJson = 
mapper.readValue(sc.nextLine(), typeRef);
+
+            int key = (int)entryFromJson.get("key");
+
+            keys.add(key);
+
+            String val = (String)entryFromJson.get("value");
+
+            if (key == 1)
+                assertEquals(JOHN, val);
+            else if (key == 2)
+                assertEquals(SARAH, val);
+            else
+                assertEquals(KYLE, val);
+        }
+
+        assertTrue(keys.containsAll(Arrays.asList(1, 2, 3)));
+
+        keys.clear();
+
+        assertEquals(EXIT_CODE_OK, execute("--cache", SCAN, "--output-format", 
JsonCacheScanTaskFormat.NAME, "cache3"));
+
+        sc = new Scanner(testOut.toString());
+
+        while (sc.hasNextLine() && !Objects.equals(sc.nextLine().trim(), 
"data")) ;
+
+        for (int i = 0; i < 3; i++) {
+            assertTrue(sc.hasNextLine());
+
+            Map<String, Object> entryFromJson = 
mapper.readValue(sc.nextLine(), typeRef);
+
+            int key = (int)entryFromJson.get("key");
+
+            keys.add(key);
+
+            Map<String, Object> val = (Map<String, 
Object>)entryFromJson.get("value");
+
+            assertEquals(key, val.get("i"));
+            assertEquals(Arrays.asList(true, false), val.get("booleans"));
+            assertEquals("test", val.get("chars"));
+            assertEquals(Arrays.asList(1, 2, 3), val.get("shorts"));
+            assertEquals(Arrays.asList(2, 3), val.get("ints"));
+            assertEquals(Arrays.asList(4, 5), val.get("longs"));
+            assertEquals(Arrays.asList(1, 2, 3), val.get("list"));
+            assertEquals(IgniteObjectMapper.DATE_FORMAT.format(DATE), 
val.get("date"));
+
+            int firstIdx = i * 3 + 1;
+
+            assertEquals(Arrays.asList("s" + firstIdx, "s" + (firstIdx + 1), 
"s" + (firstIdx + 2)), val.get("strArr"));
+
+            if (key == 1) {
+                assertTrue(((List<?>)val.get("floats")).isEmpty());
+                assertEquals(Arrays.asList(42.0d), val.get("doubles"));
+                assertEquals(Collections.singletonMap("some_key", 
"some_value"), val.get("map"));
+                assertEquals(AccessLevel.USER.toString(), val.get("enm"));
+            }
+            else if (key == 2) {
+                assertEquals(Arrays.asList(123d), val.get("floats"));
+                assertEquals(Arrays.asList(0d), val.get("doubles"));
+                assertEquals(Collections.singletonMap("1", "2"), 
val.get("map"));
+                assertEquals(AccessLevel.USER.toString(), val.get("enm"));
+            }
+            else {
+                assertEquals(Arrays.asList(123d), val.get("floats"));
+                assertEquals(Arrays.asList(1d), val.get("doubles"));
+                assertEquals(Collections.singletonMap("xxx", "yyy"), 
val.get("map"));
+                assertEquals(AccessLevel.SUPER.toString(), val.get("enm"));
+            }
+        }
+
+        assertTrue(keys.containsAll(Arrays.asList(1, 2, 3)));
+    }
+
     /** */
     @Test
     public void testCacheScanLimit() {
@@ -2378,9 +2533,27 @@ public class GridCommandHandlerClusterByClassTest 
extends GridCommandHandlerClus
         /** */
         private final int i;
 
+        /** */
+        private final boolean[] booleans;
+
+        /** */
+        private final char[] chars;
+
+        /** */
+        private final short[] shorts;
+
         /** */
         private final int[] ints;
 
+        /** */
+        private final long[] longs;
+
+        /** */
+        private final float[] floats;
+
+        /** */
+        private final double[] doubles;
+
         /** */
         private final Map<?, ?> map;
 
@@ -2397,9 +2570,29 @@ public class GridCommandHandlerClusterByClassTest 
extends GridCommandHandlerClus
         private final AccessLevel enm;
 
         /** */
-        public TestClass2(int i, int[] ints, Map<?, ?> map, String[] strArr, 
Date date, List<?> list, AccessLevel enm) {
+        public TestClass2(
+            int i,
+            boolean[] booleans,
+            char[] chars,
+            short[] shorts,
+            int[] ints,
+            long[] longs,
+            float[] floats,
+            double[] doubles,
+            Map<?, ?> map,
+            String[] strArr,
+            Date date,
+            List<?> list,
+            AccessLevel enm
+        ) {
             this.i = i;
+            this.booleans = booleans;
+            this.chars = chars;
+            this.shorts = shorts;
             this.ints = ints;
+            this.longs = longs;
+            this.floats = floats;
+            this.doubles = doubles;
             this.map = map;
             this.strArr = strArr;
             this.date = date;
diff --git a/modules/core/src/main/java/org/apache/ignite/dump/DumpReader.java 
b/modules/core/src/main/java/org/apache/ignite/dump/DumpReader.java
index 125d9c959fe..b290b319bb1 100644
--- a/modules/core/src/main/java/org/apache/ignite/dump/DumpReader.java
+++ b/modules/core/src/main/java/org/apache/ignite/dump/DumpReader.java
@@ -37,6 +37,7 @@ import org.apache.ignite.internal.cdc.CdcMain;
 import 
org.apache.ignite.internal.processors.cache.persistence.snapshot.SnapshotMetadata;
 import 
org.apache.ignite.internal.processors.cache.persistence.snapshot.dump.Dump;
 import 
org.apache.ignite.internal.processors.cache.persistence.snapshot.dump.Dump.DumpedPartitionIterator;
+import 
org.apache.ignite.internal.processors.cache.persistence.snapshot.dump.DumpConsumerKernalContextAware;
 import org.apache.ignite.internal.util.typedef.F;
 import org.apache.ignite.internal.util.typedef.internal.CU;
 import org.apache.ignite.internal.util.typedef.internal.U;
@@ -80,7 +81,10 @@ public class DumpReader implements Runnable {
         try (Dump dump = new Dump(cfg.dumpRoot(), null, cfg.keepBinary(), 
cfg.keepRaw(), encryptionSpi(), log)) {
             DumpConsumer cnsmr = cfg.consumer();
 
-            cnsmr.start();
+            if (cnsmr instanceof DumpConsumerKernalContextAware)
+                ((DumpConsumerKernalContextAware)cnsmr).start(dump.context());
+            else
+                cnsmr.start();
 
             try {
                 File[] files = new File(cfg.dumpRoot(), 
DFLT_MARSHALLER_PATH).listFiles(BinaryUtils::notTmpFile);
diff --git 
a/modules/core/src/main/java/org/apache/ignite/internal/management/cache/scan/DefaultCacheScanTaskFormat.java
 
b/modules/core/src/main/java/org/apache/ignite/internal/management/cache/scan/DefaultCacheScanTaskFormat.java
index f6aa82b0fa8..d683cfbf6c9 100644
--- 
a/modules/core/src/main/java/org/apache/ignite/internal/management/cache/scan/DefaultCacheScanTaskFormat.java
+++ 
b/modules/core/src/main/java/org/apache/ignite/internal/management/cache/scan/DefaultCacheScanTaskFormat.java
@@ -79,15 +79,42 @@ public class DefaultCacheScanTaskFormat implements 
CacheScanTaskFormat {
         if (o == null)
             return "null";
 
-        if (o instanceof byte[])
+        if (o instanceof byte[]) {
             return "size=" + ((byte[])o).length;
-
-        if (o instanceof Byte[])
+        }
+        else if (o instanceof Byte[]) {
             return "size=" + ((Byte[])o).length;
-
-        if (o instanceof Object[]) {
-            return "size=" + ((Object[])o).length +
-                ", values=[" + S.joinToString(Arrays.asList((Object[])o), ", 
", "...", 120, 0) + "]";
+        }
+        else if (o instanceof boolean[]) {
+            boolean[] arr = (boolean[])o;
+            return arrayValue(arr.length, Arrays.toString(arr));
+        }
+        else if (o instanceof char[]) {
+            char[] arr = (char[])o;
+            return arrayValue(arr.length, Arrays.toString(arr));
+        }
+        else if (o instanceof short[]) {
+            short[] arr = (short[])o;
+            return arrayValue(arr.length, Arrays.toString(arr));
+        }
+        else if (o instanceof int[]) {
+            int[] arr = (int[])o;
+            return arrayValue(arr.length, Arrays.toString(arr));
+        }
+        else if (o instanceof long[]) {
+            long[] arr = (long[])o;
+            return arrayValue(arr.length, Arrays.toString(arr));
+        }
+        else if (o instanceof float[]) {
+            float[] arr = (float[])o;
+            return arrayValue(arr.length, Arrays.toString(arr));
+        }
+        else if (o instanceof double[]) {
+            double[] arr = (double[])o;
+            return arrayValue(arr.length, Arrays.toString(arr));
+        }
+        else if (o instanceof Object[]) {
+            return arrayValue(((Object[])o).length, "[" + 
S.joinToString(Arrays.asList((Object[])o), ", ", "...", 120, 0)) + "]";
         }
 
         if (o instanceof BinaryObject)
@@ -96,6 +123,11 @@ public class DefaultCacheScanTaskFormat implements 
CacheScanTaskFormat {
         return o.toString();
     }
 
+    /** */
+    static String arrayValue(int length, String values) {
+        return "size=" + length + ", values=" + values;
+    }
+
     /**
      * Convert Binary object to string.
      *
diff --git 
a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/snapshot/dump/Dump.java
 
b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/snapshot/dump/Dump.java
index c26c56f88b1..7cefa552380 100644
--- 
a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/snapshot/dump/Dump.java
+++ 
b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/snapshot/dump/Dump.java
@@ -386,6 +386,11 @@ public class Dump implements AutoCloseable {
         return grpDirs[0];
     }
 
+    /** @return Kernal context. */
+    public GridKernalContext context() {
+        return cctx;
+    }
+
     /** {@inheritDoc} */
     @Override public void close() throws Exception {
         closeAllComponents(cctx);
diff --git 
a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/snapshot/dump/DumpConsumerKernalContextAware.java
 
b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/snapshot/dump/DumpConsumerKernalContextAware.java
new file mode 100644
index 00000000000..ec24a4921f8
--- /dev/null
+++ 
b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/snapshot/dump/DumpConsumerKernalContextAware.java
@@ -0,0 +1,33 @@
+/*
+ * 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.persistence.snapshot.dump;
+
+import org.apache.ignite.dump.DumpConsumer;
+import org.apache.ignite.internal.GridKernalContext;
+
+/**
+ * Dump consumer that needs to use {@link GridKernalContext} must implement 
this interface.
+ */
+public interface DumpConsumerKernalContextAware extends DumpConsumer {
+    /**
+     * Starts the consumer with the kernal context provided.
+     *
+     * @param ctx Kernal context.
+     */
+    void start(GridKernalContext ctx);
+}
diff --git 
a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/persistence/snapshot/dump/AbstractCacheDumpTest.java
 
b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/persistence/snapshot/dump/AbstractCacheDumpTest.java
index 38bf7dfb2c0..b518de85c09 100644
--- 
a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/persistence/snapshot/dump/AbstractCacheDumpTest.java
+++ 
b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/persistence/snapshot/dump/AbstractCacheDumpTest.java
@@ -56,7 +56,6 @@ import 
org.apache.ignite.internal.processors.cache.CacheGroupContext;
 import org.apache.ignite.internal.processors.cache.GridCacheContext;
 import org.apache.ignite.internal.processors.cache.StoredCacheData;
 import 
org.apache.ignite.internal.processors.cache.persistence.snapshot.SnapshotMetadata;
-import org.apache.ignite.internal.util.typedef.F;
 import org.apache.ignite.internal.util.typedef.T2;
 import org.apache.ignite.internal.util.typedef.internal.CU;
 import org.apache.ignite.internal.util.typedef.internal.U;
@@ -228,7 +227,9 @@ public abstract class AbstractCacheDumpTest extends 
GridCommonAbstractTest {
     }
 
     /** */
-    protected T2<CountDownLatch, IgniteInternalFuture<?>> 
runDumpAsyncAndStopBeforeStart() throws IgniteInterruptedCheckedException {
+    protected T2<CountDownLatch, IgniteInternalFuture<?>> 
runDumpAsyncAndStopBeforeStart(
+        IgniteEx srv
+    ) throws IgniteInterruptedCheckedException {
         CountDownLatch latch = new CountDownLatch(1);
 
         List<Ignite> ignites = Ignition.allGrids();
@@ -244,7 +245,7 @@ public abstract class AbstractCacheDumpTest extends 
GridCommonAbstractTest {
             });
         }
 
-        IgniteInternalFuture<Object> dumpFut = runAsync(() -> 
createDump((IgniteEx)F.first(ignites)));
+        IgniteInternalFuture<Object> dumpFut = runAsync(() -> createDump(srv));
 
         // Waiting while dump will be setup: task planned after change 
listener set.
         assertTrue(waitForCondition(() -> {
@@ -344,82 +345,7 @@ public abstract class AbstractCacheDumpTest extends 
GridCommonAbstractTest {
 
         assertEquals(nodes, nodesDirs.size());
 
-        TestDumpConsumer cnsmr = new TestDumpConsumer() {
-            final Set<Integer> keys = new HashSet<>();
-
-            final Set<Long> grpParts = new HashSet<>();
-
-            int dfltDumpSz;
-
-            int grpDumpSz;
-
-            @Override public void onCacheConfigs(Iterator<StoredCacheData> 
caches) {
-                super.onCacheConfigs(caches);
-
-                Set<String> cachesFound = new HashSet<>();
-
-                caches.forEachRemaining(data -> {
-                    String cacheName = data.config().getName();
-
-                    assertTrue(cachesFound.add(cacheName));
-
-                    assertEquals(cacheName, data.configuration().getName());
-
-                    assertFalse(data.sql());
-
-                    assertTrue(data.queryEntities().isEmpty());
-
-                    if (cacheName.startsWith("cache-"))
-                        assertEquals(GRP, data.configuration().getGroupName());
-                    else if (!cacheName.equals(DEFAULT_CACHE_NAME))
-                        throw new IgniteException("Unknown cache");
-                });
-
-                assertEquals(expectedFoundCaches, cachesFound);
-            }
-
-            @Override public void onPartition(int grp, int part, 
Iterator<DumpEntry> iter) {
-                if (onlyPrimary)
-                    assertTrue(grpParts.add(toLong(grp, part)));
-
-                if (grp == CU.cacheId(DEFAULT_CACHE_NAME)) {
-                    while (iter.hasNext()) {
-                        DumpEntry e = iter.next();
-
-                        checkDefaultCacheEntry(e);
-
-                        keys.add((Integer)e.key());
-
-                        dfltDumpSz++;
-                    }
-                }
-                else {
-                    while (iter.hasNext()) {
-                        DumpEntry e = iter.next();
-
-                        assertNotNull(e);
-                        assertNotNull(e.version());
-                        assertNull(e.version().otherClusterVersion());
-
-                        if (e.cacheId() == CU.cacheId(CACHE_0))
-                            assertEquals(USER_FACTORY.apply((Integer)e.key()), 
e.value());
-                        else
-                            assertEquals(((Key)e.key()).getId() + "", 
((Value)e.value()).getVal());
-
-                        grpDumpSz++;
-                    }
-                }
-            }
-
-            @Override public void check() {
-                super.check();
-
-                assertEquals(expectedDfltDumpSz, dfltDumpSz);
-                assertEquals(expectedGrpDumpSz, grpDumpSz);
-
-                IntStream.range(0, expectedCnt).forEach(key -> 
assertTrue(keys.contains(key)));
-            }
-        };
+        TestDumpConsumer cnsmr = dumpConsumer(expectedFoundCaches, 
expectedDfltDumpSz, expectedGrpDumpSz, expectedCnt);
 
         new DumpReader(
             new DumpReaderConfiguration(
@@ -440,14 +366,13 @@ public abstract class AbstractCacheDumpTest extends 
GridCommonAbstractTest {
     }
 
     /** */
-    protected void checkDefaultCacheEntry(DumpEntry e) {
-        assertNotNull(e);
-
-        Integer key = (Integer)e.key();
-
-        assertEquals(key, e.value());
-        assertNotNull(e.version());
-        assertNull(e.version().otherClusterVersion());
+    protected TestDumpConsumer dumpConsumer(
+        Set<String> expectedFoundCaches,
+        int expectedDfltDumpSz,
+        int expectedGrpDumpSz,
+        int expectedCnt
+    ) {
+        return new TestDumpConsumerImpl(expectedFoundCaches, 
expectedDfltDumpSz, expectedGrpDumpSz, expectedCnt);
     }
 
     /** */
@@ -577,6 +502,122 @@ public abstract class AbstractCacheDumpTest extends 
GridCommonAbstractTest {
         return encSpi;
     }
 
+    /** */
+    public class TestDumpConsumerImpl extends TestDumpConsumer {
+        /** */
+        private final Set<String> expectedFoundCaches;
+
+        /** */
+        private final int expectedDfltDumpSz;
+
+        /** */
+        private final int expectedGrpDumpSz;
+
+        /** */
+        private final int expectedCnt;
+
+        /** */
+        final Set<Integer> keys = new HashSet<>();
+
+        /** */
+        final Set<Long> grpParts = new HashSet<>();
+
+        /** */
+        int dfltDumpSz;
+
+        /** */
+        int grpDumpSz;
+
+        /** */
+        protected TestDumpConsumerImpl(Set<String> expectedFoundCaches, int 
expectedDfltDumpSz, int expectedGrpDumpSz, int expectedCnt) {
+            this.expectedFoundCaches = expectedFoundCaches;
+            this.expectedDfltDumpSz = expectedDfltDumpSz;
+            this.expectedGrpDumpSz = expectedGrpDumpSz;
+            this.expectedCnt = expectedCnt;
+        }
+
+        /** {@inheritDoc} */
+        @Override public void onCacheConfigs(Iterator<StoredCacheData> caches) 
{
+            super.onCacheConfigs(caches);
+
+            Set<String> cachesFound = new HashSet<>();
+
+            caches.forEachRemaining(data -> {
+                String cacheName = data.config().getName();
+
+                assertTrue(cachesFound.add(cacheName));
+
+                assertEquals(cacheName, data.configuration().getName());
+
+                assertFalse(data.sql());
+
+                assertTrue(data.queryEntities().isEmpty());
+
+                if (cacheName.startsWith("cache-"))
+                    assertEquals(GRP, data.configuration().getGroupName());
+                else if (!cacheName.equals(DEFAULT_CACHE_NAME))
+                    throw new IgniteException("Unknown cache");
+            });
+
+            assertEquals(expectedFoundCaches, cachesFound);
+        }
+
+        /** {@inheritDoc} */
+        @Override public void onPartition(int grp, int part, 
Iterator<DumpEntry> iter) {
+            if (onlyPrimary)
+                assertTrue(grpParts.add(toLong(grp, part)));
+
+            if (grp == CU.cacheId(DEFAULT_CACHE_NAME)) {
+                while (iter.hasNext()) {
+                    DumpEntry e = iter.next();
+
+                    checkDefaultCacheEntry(e);
+
+                    keys.add((Integer)e.key());
+
+                    dfltDumpSz++;
+                }
+            }
+            else {
+                while (iter.hasNext()) {
+                    DumpEntry e = iter.next();
+
+                    assertNotNull(e);
+                    assertNotNull(e.version());
+                    assertNull(e.version().otherClusterVersion());
+
+                    if (e.cacheId() == CU.cacheId(CACHE_0))
+                        assertEquals(USER_FACTORY.apply((Integer)e.key()), 
e.value());
+                    else
+                        assertEquals(((Key)e.key()).getId() + "", 
((Value)e.value()).getVal());
+
+                    grpDumpSz++;
+                }
+            }
+        }
+
+        /** {@inheritDoc} */
+        @Override public void check() {
+            super.check();
+
+            assertEquals(expectedDfltDumpSz, dfltDumpSz);
+            assertEquals(expectedGrpDumpSz, grpDumpSz);
+
+            IntStream.range(0, expectedCnt).forEach(key -> 
assertTrue(keys.contains(key)));
+        }
+
+        /** */
+        protected void checkDefaultCacheEntry(DumpEntry e) {
+            assertNotNull(e);
+
+            Integer key = (Integer)e.key();
+
+            assertEquals(key, e.value());
+            assertNotNull(e.version());
+            assertNull(e.version().otherClusterVersion());
+        }
+    }
+
     /** */
     public abstract static class TestDumpConsumer implements DumpConsumer {
         /** */
diff --git 
a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/persistence/snapshot/dump/IgniteCacheDumpSelfTest.java
 
b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/persistence/snapshot/dump/IgniteCacheDumpSelfTest.java
index 0a44519c776..665b993d92e 100644
--- 
a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/persistence/snapshot/dump/IgniteCacheDumpSelfTest.java
+++ 
b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/persistence/snapshot/dump/IgniteCacheDumpSelfTest.java
@@ -25,6 +25,7 @@ import java.util.Arrays;
 import java.util.Collections;
 import java.util.HashSet;
 import java.util.List;
+import java.util.Set;
 import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.atomic.AtomicBoolean;
 import java.util.concurrent.atomic.AtomicInteger;
@@ -618,7 +619,7 @@ public class IgniteCacheDumpSelfTest extends 
AbstractCacheDumpTest {
             }
         });
 
-        T2<CountDownLatch, IgniteInternalFuture<?>> latchAndFut = 
runDumpAsyncAndStopBeforeStart();
+        T2<CountDownLatch, IgniteInternalFuture<?>> latchAndFut = 
runDumpAsyncAndStopBeforeStart(ign);
 
         cache.put(keyToFail, "test string");
 
@@ -647,7 +648,7 @@ public class IgniteCacheDumpSelfTest extends 
AbstractCacheDumpTest {
     private void doTestDumpWithExpiry() throws Exception {
         IgniteEx ign = startGridAndFillCaches();
 
-        T2<CountDownLatch, IgniteInternalFuture<?>> latchAndFut = 
runDumpAsyncAndStopBeforeStart();
+        T2<CountDownLatch, IgniteInternalFuture<?>> latchAndFut = 
runDumpAsyncAndStopBeforeStart(ign);
 
         Thread.sleep(TTL);
 
@@ -677,7 +678,7 @@ public class IgniteCacheDumpSelfTest extends 
AbstractCacheDumpTest {
     private void doTestConcurrentOperations(Consumer<IgniteEx> op) throws 
Exception {
         IgniteEx ign = startGridAndFillCaches();
 
-        T2<CountDownLatch, IgniteInternalFuture<?>> latchAndFut = 
runDumpAsyncAndStopBeforeStart();
+        T2<CountDownLatch, IgniteInternalFuture<?>> latchAndFut = 
runDumpAsyncAndStopBeforeStart(ign);
 
         // This operations will be catched by change listeners. Old value must 
be stored in dump.
         op.accept(ign);
@@ -707,14 +708,24 @@ public class IgniteCacheDumpSelfTest extends 
AbstractCacheDumpTest {
     }
 
     /** {@inheritDoc} */
-    @Override protected void checkDefaultCacheEntry(DumpEntry e) {
-        super.checkDefaultCacheEntry(e);
-
-        if (explicitTtl != null) {
-            assertTrue("Expire time must be set", e.expireTime() != 0);
-            assertTrue("Expire time must be in past", 
System.currentTimeMillis() >= e.expireTime());
-            assertTrue("Expire time must be set during test run", 
System.currentTimeMillis() - getTestTimeout() < e.expireTime());
-        }
+    @Override protected TestDumpConsumer dumpConsumer(
+        Set<String> expectedFoundCaches,
+        int expectedDfltDumpSz,
+        int expectedGrpDumpSz,
+        int expectedCnt
+    ) {
+        return new TestDumpConsumerImpl(expectedFoundCaches, 
expectedDfltDumpSz, expectedGrpDumpSz, expectedCnt) {
+            /** {@inheritDoc} */
+            @Override protected void checkDefaultCacheEntry(DumpEntry e) {
+                super.checkDefaultCacheEntry(e);
+
+                if (explicitTtl != null) {
+                    assertTrue("Expire time must be set", e.expireTime() != 0);
+                    assertTrue("Expire time must be in past", 
System.currentTimeMillis() >= e.expireTime());
+                    assertTrue("Expire time must be set during test run", 
System.currentTimeMillis() - getTestTimeout() < e.expireTime());
+                }
+            }
+        };
     }
 
     /** */
diff --git a/modules/json/README.txt b/modules/json/README.txt
new file mode 100644
index 00000000000..5eae369e8b3
--- /dev/null
+++ b/modules/json/README.txt
@@ -0,0 +1,4 @@
+Apache Ignite Json Module
+------------------------
+
+Apache Ignite json module provides classes and configurations for integration 
with external tools via json format.
\ No newline at end of file
diff --git a/modules/rest-http/pom.xml b/modules/json/pom.xml
similarity index 58%
copy from modules/rest-http/pom.xml
copy to modules/json/pom.xml
index f326f428621..4cf92c4b842 100644
--- a/modules/rest-http/pom.xml
+++ b/modules/json/pom.xml
@@ -30,17 +30,10 @@
         <relativePath>../../parent-internal/pom.xml</relativePath>
     </parent>
 
-    <artifactId>ignite-rest-http</artifactId>
+    <artifactId>ignite-json</artifactId>
 
     <url>http://ignite.apache.org</url>
 
-    <properties>
-        <osgi.export.package>
-            org.apache.ignite.internal.processors.rest.protocols.http.jetty,
-            {local-packages}
-        </osgi.export.package>
-    </properties>
-
     <dependencies>
         <dependency>
             <groupId>${project.groupId}</groupId>
@@ -48,51 +41,9 @@
         </dependency>
 
         <dependency>
-            <groupId>commons-lang</groupId>
-            <artifactId>commons-lang</artifactId>
-            <version>${commons.lang.version}</version>
-        </dependency>
-
-        <dependency>
-            <groupId>org.eclipse.jetty</groupId>
-            <artifactId>jetty-continuation</artifactId>
-            <version>${jetty.version}</version>
-        </dependency>
-
-        <dependency>
-            <groupId>org.eclipse.jetty</groupId>
-            <artifactId>jetty-http</artifactId>
-            <version>${jetty.version}</version>
-        </dependency>
-
-        <dependency>
-            <groupId>org.eclipse.jetty</groupId>
-            <artifactId>jetty-io</artifactId>
-            <version>${jetty.version}</version>
-        </dependency>
-
-        <dependency>
-            <groupId>org.eclipse.jetty</groupId>
-            <artifactId>jetty-server</artifactId>
-            <version>${jetty.version}</version>
-        </dependency>
-
-        <dependency>
-            <groupId>org.eclipse.jetty</groupId>
-            <artifactId>jetty-util</artifactId>
-            <version>${jetty.version}</version>
-        </dependency>
-
-        <dependency>
-            <groupId>org.eclipse.jetty</groupId>
-            <artifactId>jetty-xml</artifactId>
-            <version>${jetty.version}</version>
-        </dependency>
-
-        <dependency>
-            <groupId>javax.servlet</groupId>
-            <artifactId>javax.servlet-api</artifactId>
-            <version>3.1.0</version>
+            <groupId>${project.groupId}</groupId>
+            <artifactId>ignite-spring</artifactId>
+            <scope>test</scope>
         </dependency>
 
         <dependency>
@@ -131,26 +82,6 @@
             <type>test-jar</type>
             <scope>test</scope>
         </dependency>
-
-        <dependency>
-            <groupId>${project.groupId}</groupId>
-            <artifactId>ignite-tools</artifactId>
-            <scope>test</scope>
-        </dependency>
-
-        <dependency>
-            <groupId>org.springframework</groupId>
-            <artifactId>spring-beans</artifactId>
-            <version>${spring.version}</version>
-            <scope>test</scope>
-        </dependency>
-
-        <dependency>
-            <groupId>org.springframework</groupId>
-            <artifactId>spring-context</artifactId>
-            <version>${spring.version}</version>
-            <scope>test</scope>
-        </dependency>
     </dependencies>
 
     <build>
diff --git 
a/modules/json/src/main/java/org/apache/ignite/dump/JsonDumpConsumer.java 
b/modules/json/src/main/java/org/apache/ignite/dump/JsonDumpConsumer.java
new file mode 100644
index 00000000000..0bf4fe28906
--- /dev/null
+++ b/modules/json/src/main/java/org/apache/ignite/dump/JsonDumpConsumer.java
@@ -0,0 +1,151 @@
+/*
+ * 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.dump;
+
+import java.io.IOException;
+import java.util.Iterator;
+import org.apache.ignite.IgniteException;
+import org.apache.ignite.binary.BinaryType;
+import org.apache.ignite.cache.CacheEntryVersion;
+import org.apache.ignite.cdc.TypeMapping;
+import org.apache.ignite.internal.GridKernalContext;
+import org.apache.ignite.internal.jackson.IgniteObjectMapper;
+import org.apache.ignite.internal.processors.cache.StoredCacheData;
+import 
org.apache.ignite.internal.processors.cache.persistence.snapshot.dump.DumpConsumerKernalContextAware;
+
+/**
+ * Dump consumer that outputs entries in json format.
+ */
+public class JsonDumpConsumer implements DumpConsumerKernalContextAware {
+    /** Ignite specific object mapper. */
+    private IgniteObjectMapper mapper;
+
+    /** {@inheritDoc} */
+    @Override public void start(GridKernalContext ctx) {
+        mapper = new IgniteObjectMapper(ctx);
+    }
+
+    /** {@inheritDoc} */
+    @Override public void onMappings(Iterator<TypeMapping> mappings) {
+        // No-op.
+    }
+
+    /** {@inheritDoc} */
+    @Override public void onTypes(Iterator<BinaryType> types) {
+        // No-op.
+    }
+
+    /** {@inheritDoc} */
+    @Override public void onCacheConfigs(Iterator<StoredCacheData> caches) {
+        // No-op.
+    }
+
+    /** {@inheritDoc} */
+    @Override public void onPartition(int grp, int part, Iterator<DumpEntry> 
data) {
+        data.forEachRemaining(entry -> {
+            try {
+                System.out.println(mapper.writeValueAsString(new 
PrintableDumpEntry(entry)));
+            }
+            catch (IOException e) {
+                throw new IgniteException(e);
+            }
+        });
+    }
+
+    /** {@inheritDoc} */
+    @Override public void stop() {
+        // No-op.
+    }
+
+    /** {@inheritDoc} */
+    @Override public void start() {
+        // No-op.
+    }
+
+    /** */
+    private static class PrintableDumpEntry {
+        /** */
+        private final DumpEntry e;
+
+        /** */
+        public PrintableDumpEntry(DumpEntry e) {
+            this.e = e;
+        }
+
+        /** @see DumpEntry#cacheId() */
+        public int getCacheId() {
+            return e.cacheId();
+        }
+
+        /** @see DumpEntry#expireTime() */
+        public long getExpireTime() {
+            return e.expireTime();
+        }
+
+        /** @see DumpEntry#version() */
+        public PrintableCacheEntryVersion getVersion() {
+            return new PrintableCacheEntryVersion(e.version());
+        }
+
+        /** @see DumpEntry#key() */
+        public Object getKey() {
+            return e.key();
+        }
+
+        /** @see DumpEntry#value() */
+        public Object getValue() {
+            return e.value();
+        }
+    }
+
+    /** */
+    private static class PrintableCacheEntryVersion {
+        /** */
+        private final CacheEntryVersion v;
+
+        /** */
+        public PrintableCacheEntryVersion(CacheEntryVersion v) {
+            this.v = v;
+        }
+
+        /** @see CacheEntryVersion#order() */
+        public long getOrder() {
+            return v.order();
+        }
+
+        /** @see CacheEntryVersion#nodeOrder() */
+        public int getNodeOrder() {
+            return v.nodeOrder();
+        }
+
+        /** @see CacheEntryVersion#clusterId() */
+        public byte getClusterId() {
+            return v.clusterId();
+        }
+
+        /** @see CacheEntryVersion#topologyVersion() */
+        public int getTopologyVersion() {
+            return v.topologyVersion();
+        }
+
+        /** @see CacheEntryVersion#otherClusterVersion() */
+        public PrintableCacheEntryVersion otherClusterVersion() {
+            return new PrintableCacheEntryVersion(v.otherClusterVersion());
+        }
+    }
+}
diff --git 
a/modules/rest-http/src/main/java/org/apache/ignite/internal/processors/rest/protocols/http/jetty/IgniteBinaryObjectJsonDeserializer.java
 
b/modules/json/src/main/java/org/apache/ignite/internal/jackson/IgniteBinaryObjectJsonDeserializer.java
similarity index 98%
rename from 
modules/rest-http/src/main/java/org/apache/ignite/internal/processors/rest/protocols/http/jetty/IgniteBinaryObjectJsonDeserializer.java
rename to 
modules/json/src/main/java/org/apache/ignite/internal/jackson/IgniteBinaryObjectJsonDeserializer.java
index a6d0d6fbe09..08723facfa7 100644
--- 
a/modules/rest-http/src/main/java/org/apache/ignite/internal/processors/rest/protocols/http/jetty/IgniteBinaryObjectJsonDeserializer.java
+++ 
b/modules/json/src/main/java/org/apache/ignite/internal/jackson/IgniteBinaryObjectJsonDeserializer.java
@@ -15,7 +15,7 @@
  * limitations under the License.
  */
 
-package org.apache.ignite.internal.processors.rest.protocols.http.jetty;
+package org.apache.ignite.internal.jackson;
 
 import java.io.IOException;
 import java.util.Collections;
diff --git 
a/modules/rest-http/src/main/java/org/apache/ignite/internal/processors/rest/protocols/http/jetty/GridJettyObjectMapper.java
 
b/modules/json/src/main/java/org/apache/ignite/internal/jackson/IgniteObjectMapper.java
similarity index 96%
rename from 
modules/rest-http/src/main/java/org/apache/ignite/internal/processors/rest/protocols/http/jetty/GridJettyObjectMapper.java
rename to 
modules/json/src/main/java/org/apache/ignite/internal/jackson/IgniteObjectMapper.java
index fc3966a8548..804f5159532 100644
--- 
a/modules/rest-http/src/main/java/org/apache/ignite/internal/processors/rest/protocols/http/jetty/GridJettyObjectMapper.java
+++ 
b/modules/json/src/main/java/org/apache/ignite/internal/jackson/IgniteObjectMapper.java
@@ -15,7 +15,7 @@
  * limitations under the License.
  */
 
-package org.apache.ignite.internal.processors.rest.protocols.http.jetty;
+package org.apache.ignite.internal.jackson;
 
 import java.io.IOException;
 import java.sql.Date;
@@ -59,21 +59,24 @@ import org.apache.ignite.lang.IgniteUuid;
 /**
  * Custom object mapper for HTTP REST API.
  */
-public class GridJettyObjectMapper extends ObjectMapper {
+public class IgniteObjectMapper extends ObjectMapper {
+    /** Date format. */
+    public static final DateFormat DATE_FORMAT = 
DateFormat.getDateTimeInstance(DateFormat.DEFAULT, DateFormat.DEFAULT, 
Locale.US);
+
     /**
      * Default constructor.
      */
-    public GridJettyObjectMapper() {
+    public IgniteObjectMapper() {
         this(null);
     }
 
     /**
      * @param ctx Defines a kernal context to enable deserialization into the 
Ignite binary object.
      */
-    GridJettyObjectMapper(GridKernalContext ctx) {
+    public IgniteObjectMapper(GridKernalContext ctx) {
         super(null, new CustomSerializerProvider(), null);
 
-        setDateFormat(DateFormat.getDateTimeInstance(DateFormat.DEFAULT, 
DateFormat.DEFAULT, Locale.US));
+        setDateFormat(DATE_FORMAT);
 
         SimpleModule module = new SimpleModule();
 
@@ -98,7 +101,8 @@ public class GridJettyObjectMapper extends ObjectMapper {
 
             IgnitePredicate<String> clsFilter = 
ctx.marshallerContext().classNameFilter();
 
-            setDefaultTyping(new 
RestrictedTypeResolverBuilder(clsFilter).init(JsonTypeInfo.Id.CLASS, null));
+            if (clsFilter != null)
+                setDefaultTyping(new 
RestrictedTypeResolverBuilder(clsFilter).init(JsonTypeInfo.Id.CLASS, null));
         }
 
         configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false);
diff --git 
a/modules/json/src/main/java/org/apache/ignite/internal/management/cache/scan/JsonCacheScanTaskFormat.java
 
b/modules/json/src/main/java/org/apache/ignite/internal/management/cache/scan/JsonCacheScanTaskFormat.java
new file mode 100644
index 00000000000..34443987f74
--- /dev/null
+++ 
b/modules/json/src/main/java/org/apache/ignite/internal/management/cache/scan/JsonCacheScanTaskFormat.java
@@ -0,0 +1,57 @@
+/*
+ * 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.management.cache.scan;
+
+import java.util.Collections;
+import java.util.List;
+import javax.cache.Cache;
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import org.apache.ignite.IgniteException;
+import org.apache.ignite.internal.jackson.IgniteObjectMapper;
+
+/**
+ * This format prints cache objects in json format.
+ */
+public class JsonCacheScanTaskFormat implements CacheScanTaskFormat {
+    /** */
+    public static final String NAME = "json";
+
+    /** */
+    private final ObjectMapper mapper = new IgniteObjectMapper();
+
+    /** {@inheritDoc} */
+    @Override public String name() {
+        return NAME;
+    }
+
+    /** {@inheritDoc} */
+    @Override public List<String> titles(Cache.Entry<Object, Object> first) {
+        return Collections.singletonList("data");
+    }
+
+    /** {@inheritDoc} */
+    @Override public List<?> row(Cache.Entry<Object, Object> e) {
+        try {
+            return Collections.singletonList(mapper.writeValueAsString(e));
+        }
+        catch (JsonProcessingException ex) {
+            throw new IgniteException(ex);
+        }
+    }
+}
diff --git 
a/modules/json/src/main/resources/META-INF/services/org.apache.ignite.internal.management.cache.scan.CacheScanTaskFormat
 
b/modules/json/src/main/resources/META-INF/services/org.apache.ignite.internal.management.cache.scan.CacheScanTaskFormat
new file mode 100644
index 00000000000..cfbbc776498
--- /dev/null
+++ 
b/modules/json/src/main/resources/META-INF/services/org.apache.ignite.internal.management.cache.scan.CacheScanTaskFormat
@@ -0,0 +1 @@
+org.apache.ignite.internal.management.cache.scan.JsonCacheScanTaskFormat
\ No newline at end of file
diff --git 
a/modules/json/src/test/java/org/apache/ignite/dump/IgniteJsonSuite.java 
b/modules/json/src/test/java/org/apache/ignite/dump/IgniteJsonSuite.java
new file mode 100644
index 00000000000..b82cbe8ef2b
--- /dev/null
+++ b/modules/json/src/test/java/org/apache/ignite/dump/IgniteJsonSuite.java
@@ -0,0 +1,31 @@
+/*
+ * 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.dump;
+
+import org.junit.runner.RunWith;
+import org.junit.runners.Suite;
+
+/**
+ * Json test suite.
+ */
+@RunWith(Suite.class)
[email protected]({
+    JsonDumpConsumerTest.class
+})
+public class IgniteJsonSuite {
+}
diff --git 
a/modules/json/src/test/java/org/apache/ignite/dump/JsonDumpConsumerTest.java 
b/modules/json/src/test/java/org/apache/ignite/dump/JsonDumpConsumerTest.java
new file mode 100644
index 00000000000..06aff788042
--- /dev/null
+++ 
b/modules/json/src/test/java/org/apache/ignite/dump/JsonDumpConsumerTest.java
@@ -0,0 +1,194 @@
+/*
+ * 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.dump;
+
+import java.io.ByteArrayOutputStream;
+import java.io.PrintStream;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Scanner;
+import java.util.Set;
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.core.type.TypeReference;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import org.apache.ignite.cache.CacheEntryVersion;
+import org.apache.ignite.internal.GridKernalContext;
+import 
org.apache.ignite.internal.processors.cache.persistence.snapshot.dump.DumpConsumerKernalContextAware;
+import 
org.apache.ignite.internal.processors.cache.persistence.snapshot.dump.IgniteCacheDumpSelfTest;
+import org.apache.ignite.internal.util.typedef.internal.CU;
+import org.apache.ignite.internal.util.typedef.internal.U;
+import org.apache.ignite.platform.model.ACL;
+import org.apache.ignite.platform.model.AccessLevel;
+import org.apache.ignite.platform.model.Key;
+import org.apache.ignite.platform.model.Role;
+import org.apache.ignite.platform.model.User;
+import org.apache.ignite.platform.model.Value;
+import org.jetbrains.annotations.NotNull;
+
+/** */
+public class JsonDumpConsumerTest extends IgniteCacheDumpSelfTest {
+    /** {@inheritDoc} */
+    @Override protected TestDumpConsumer dumpConsumer(
+        Set<String> expectedFoundCaches,
+        int expectedDfltDumpSz,
+        int expectedGrpDumpSz,
+        int expectedCnt
+    ) {
+        return new TestJsonDumpConsumer(expectedFoundCaches, 
expectedDfltDumpSz, expectedGrpDumpSz, expectedCnt);
+    }
+
+    /** */
+    public class TestJsonDumpConsumer extends TestDumpConsumerImpl implements 
DumpConsumerKernalContextAware {
+        /** */
+        private final JsonDumpConsumer jsonDumpConsumer = new 
JsonDumpConsumer();
+
+        /** */
+        protected TestJsonDumpConsumer(Set<String> expectedFoundCaches, int 
expectedDfltDumpSz, int expectedGrpDumpSz, int expectedCnt) {
+            super(expectedFoundCaches, expectedDfltDumpSz, expectedGrpDumpSz, 
expectedCnt);
+        }
+
+        /** {@inheritDoc} */
+        @Override public void start(GridKernalContext ctx) {
+            jsonDumpConsumer.start(ctx);
+            start();
+        }
+
+        /** {@inheritDoc} */
+        @Override public void onPartition(int grp, int part, 
Iterator<DumpEntry> data) {
+            ByteArrayOutputStream testOut = new ByteArrayOutputStream((int)(16 
* U.MB));
+
+            PrintStream out = System.out;
+
+            System.setOut(new PrintStream(testOut));
+
+            // Parse entries from System.out.
+            Scanner sc;
+
+            try {
+                // Print out all entries to System.out.
+                jsonDumpConsumer.onPartition(grp, part, data);
+
+                sc = new Scanner(testOut.toString());
+            }
+            finally {
+                System.setOut(out);
+            }
+
+            TypeReference<HashMap<String, Object>> typeRef = new 
TypeReference<HashMap<String, Object>>() {
+                // No-op.
+            };
+
+            ObjectMapper mapper = new ObjectMapper();
+
+            super.onPartition(grp, part, new Iterator<DumpEntry>() {
+                @Override public boolean hasNext() {
+                    return sc.hasNextLine();
+                }
+
+                @Override public DumpEntry next() {
+                    try {
+                        Map<String, Object> entryFromJson = 
mapper.readValue(sc.nextLine(), typeRef);
+
+                        return new DumpEntry() {
+                            @Override public int cacheId() {
+                                return 
Integer.parseInt(entryFromJson.get("cacheId").toString());
+                            }
+
+                            @Override public long expireTime() {
+                                return 
Long.parseLong(entryFromJson.get("expireTime").toString());
+                            }
+
+                            @Override public CacheEntryVersion version() {
+                                return 
JsonDumpConsumerTest.version((Map<String, Object>)entryFromJson.get("version"));
+                            }
+
+                            @Override public Object key() {
+                                if (cacheId() == 
CU.cacheId(DEFAULT_CACHE_NAME) || cacheId() == CU.cacheId(CACHE_0))
+                                    return 
Integer.parseInt(entryFromJson.get("key").toString());
+
+                                Map<String, Object> key = (Map<String, 
Object>)entryFromJson.get("key");
+
+                                return new 
Key(Long.parseLong(key.get("id").toString()));
+                            }
+
+                            @Override public Object value() {
+                                if (cacheId() == 
CU.cacheId(DEFAULT_CACHE_NAME))
+                                    return 
Integer.valueOf(entryFromJson.get("value").toString());
+                                else if (cacheId() == CU.cacheId(CACHE_0)) {
+                                    Map<String, Object> val = (Map<String, 
Object>)entryFromJson.get("value");
+                                    Map<String, Object> role = (Map<String, 
Object>)val.get("role");
+
+                                    return new User(
+                                        (Integer)val.get("id"),
+                                        ACL.valueOf(val.get("acl").toString()),
+                                        new Role(
+                                            role.get("name").toString(),
+                                            
AccessLevel.valueOf(role.get("accessLevel").toString())
+                                        )
+                                    );
+                                }
+                                else if (cacheId() == CU.cacheId(CACHE_1)) {
+                                    Map<String, Object> val = (Map<String, 
Object>)entryFromJson.get("value");
+
+                                    return new 
Value(val.get("val").toString());
+                                }
+
+                                throw new IllegalArgumentException("Unknown 
cache: " + cacheId());
+                            }
+                        };
+                    }
+                    catch (JsonProcessingException e) {
+                        throw new RuntimeException(e);
+                    }
+                }
+            });
+        }
+    }
+
+    /** */
+    private static CacheEntryVersion version(Map<String, Object> version) {
+        return new CacheEntryVersion() {
+            @Override public long order() {
+                return Long.parseLong(version.get("order").toString());
+            }
+
+            @Override public int nodeOrder() {
+                return Integer.parseInt(version.get("nodeOrder").toString());
+            }
+
+            @Override public byte clusterId() {
+                return Byte.parseByte(version.get("clusterId").toString());
+            }
+
+            @Override public int topologyVersion() {
+                return 
Integer.parseInt(version.get("topologyVersion").toString());
+            }
+
+            @Override public CacheEntryVersion otherClusterVersion() {
+                return version.containsKey("otherClusterVersion")
+                        ? version((Map<String, 
Object>)version.get("otherClusterVersion"))
+                        : null;
+            }
+
+            @Override public int compareTo(@NotNull CacheEntryVersion o) {
+                throw new UnsupportedOperationException();
+            }
+        };
+    }
+}
diff --git a/modules/rest-http/pom.xml b/modules/rest-http/pom.xml
index f326f428621..2eb640b145b 100644
--- a/modules/rest-http/pom.xml
+++ b/modules/rest-http/pom.xml
@@ -47,6 +47,11 @@
             <artifactId>ignite-core</artifactId>
         </dependency>
 
+        <dependency>
+            <groupId>${project.groupId}</groupId>
+            <artifactId>ignite-json</artifactId>
+        </dependency>
+
         <dependency>
             <groupId>commons-lang</groupId>
             <artifactId>commons-lang</artifactId>
@@ -95,24 +100,6 @@
             <version>3.1.0</version>
         </dependency>
 
-        <dependency>
-            <groupId>com.fasterxml.jackson.core</groupId>
-            <artifactId>jackson-core</artifactId>
-            <version>${jackson.version}</version>
-        </dependency>
-
-        <dependency>
-            <groupId>com.fasterxml.jackson.core</groupId>
-            <artifactId>jackson-annotations</artifactId>
-            <version>${jackson.version}</version>
-        </dependency>
-
-        <dependency>
-            <groupId>com.fasterxml.jackson.core</groupId>
-            <artifactId>jackson-databind</artifactId>
-            <version>${jackson.version}</version>
-        </dependency>
-
         <dependency>
             <groupId>org.slf4j</groupId>
             <artifactId>slf4j-api</artifactId>
diff --git 
a/modules/rest-http/src/main/java/org/apache/ignite/internal/processors/rest/protocols/http/jetty/GridJettyRestHandler.java
 
b/modules/rest-http/src/main/java/org/apache/ignite/internal/processors/rest/protocols/http/jetty/GridJettyRestHandler.java
index ba09e7ff04b..e9550d7a358 100644
--- 
a/modules/rest-http/src/main/java/org/apache/ignite/internal/processors/rest/protocols/http/jetty/GridJettyRestHandler.java
+++ 
b/modules/rest-http/src/main/java/org/apache/ignite/internal/processors/rest/protocols/http/jetty/GridJettyRestHandler.java
@@ -51,6 +51,8 @@ import org.apache.ignite.binary.BinaryObject;
 import org.apache.ignite.cache.CacheWriteSynchronizationMode;
 import org.apache.ignite.cluster.ClusterState;
 import org.apache.ignite.internal.GridKernalContext;
+import org.apache.ignite.internal.jackson.IgniteBinaryObjectJsonDeserializer;
+import org.apache.ignite.internal.jackson.IgniteObjectMapper;
 import org.apache.ignite.internal.processors.cache.CacheConfigurationOverride;
 import org.apache.ignite.internal.processors.rest.GridRestCommand;
 import org.apache.ignite.internal.processors.rest.GridRestProtocolHandler;
@@ -172,7 +174,7 @@ public class GridJettyRestHandler extends AbstractHandler {
         this.hnd = hnd;
         this.authChecker = authChecker;
         this.log = ctx.log(getClass());
-        this.jsonMapper = new GridJettyObjectMapper(ctx);
+        this.jsonMapper = new IgniteObjectMapper(ctx);
 
         // Init default page and favicon.
         try {
diff --git a/pom.xml b/pom.xml
index de4d928f2dc..91bdcac129f 100644
--- a/pom.xml
+++ b/pom.xml
@@ -52,6 +52,7 @@
         <module>modules/web</module>
         <module>modules/urideploy</module>
         <module>modules/indexing</module>
+        <module>modules/json</module>
         <module>modules/rest-http</module>
         <module>modules/jta</module>
         <module>modules/log4j2</module>

Reply via email to