class CacheScanJob extends VisorJob<CacheScanCommandArg, CacheScanTaskResult> {
        /** */
        private static final long serialVersionUID = 0L;

        /**
         * Create job.
         *
         * @param arg Task argument.
         * @param debug Debug flag.
         */
        private CacheScanJob(CacheScanCommandArg arg, boolean debug) {
            super(arg, debug);
        }

        /** {@inheritDoc} */
        @Override protected CacheScanTaskResult run(CacheScanCommandArg arg) {
            if (F.isEmpty(arg.cacheName()))
                throw new IllegalStateException("Cache name was not specified.");

            if (arg.limit() <= 0)
                throw new IllegalStateException("Invalid limit value.");

            IgniteCache<Object, Object> cache = ignite.cache(arg.cacheName()).withKeepBinary();

            List<String> titles = Arrays.asList("Key Class", "Key", "Value Class", "Value");

            int cnt = 0;
            List<List<?>> entries = new ArrayList<>();

            ScanQuery<Object, Object> scanQry = new ScanQuery<>().setPageSize(min(arg.limit(), DFLT_PAGE_SIZE));

            try (QueryCursor<Cache.Entry<Object, Object>> qry = cache.query(scanQry)) {
                Iterator<Cache.Entry<Object, Object>> iter = qry.iterator();

                while (cnt++ < arg.limit() && iter.hasNext()) {
                    Cache.Entry<Object, Object> next = iter.next();

                    Object k = next.getKey();
                    Object v = next.getValue();

                    entries.add(Arrays.asList(typeOf(k), valueOf(k), typeOf(v), valueOf(v)));
                }
            }

            return new CacheScanTaskResult(titles, entries);
        }

        /** {@inheritDoc} */
        @Override public SecurityPermissionSet requiredPermissions() {
            // This task does nothing but delegates the call to the Ignite public API.
            // Therefore, it is safe to execute task without any additional permissions check.
            return NO_PERMISSIONS;
        }

        /**
         * @param o Source object.
         * @return String representation of object class.
         */
        private static String typeOf(Object o) {
            if (o != null) {
                Class<?> clazz = o.getClass();

                return clazz.isArray() ? IgniteUtils.compact(clazz.getComponentType().getName()) + "[]"
                    : IgniteUtils.compact(o.getClass().getName());
            }
            else
                return "n/a";
        }

        /**
         * @param o Object.
         * @return String representation of value.
         */
        private static String valueOf(Object o) {
            if (o == null)
                return "null";

            if (o instanceof byte[])
                return "size=" + ((byte[])o).length;

            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) + "]";
            }

            if (o instanceof BinaryObject)
                return binaryToString((BinaryObject)o);

            return o.toString();
        }

        /**
         * Convert Binary object to string.
         *
         * @param obj Binary object.
         * @return String representation of Binary object.
         */
        public static String binaryToString(BinaryObject obj) {<FILL_FUNCTION_BODY>}

        /** {@inheritDoc} */
        @Override public String toString() {
            return S.toString(CacheScanJob.class, this);
        }
    }

            int hash = obj.hashCode();

            if (obj instanceof BinaryObjectEx) {
                BinaryObjectEx objEx = (BinaryObjectEx)obj;

                BinaryType meta;

                try {
                    meta = ((BinaryObjectEx)obj).rawType();
                }
                catch (BinaryObjectException ignore) {
                    meta = null;
                }

                if (meta != null) {
                    if (meta.isEnum()) {
                        try {
                            return obj.deserialize().toString();
                        }
                        catch (BinaryObjectException ignore) {
                            // NO-op.
                        }
                    }

                    SB buf = new SB(meta.typeName());

                    if (meta.fieldNames() != null) {
                        buf.a(" [hash=").a(hash);

                        for (String name : meta.fieldNames()) {
                            Object val = objEx.field(name);

                            buf.a(", ").a(name).a('=').a(val);
                        }

                        buf.a(']');

                        return buf.toString();
                    }
                }
            }

            return S.toString(obj.getClass().getSimpleName(),
                "hash", hash, false,
                "typeId", obj.type().typeId(), true);
        
<methods>public non-sealed void <init>() <variables>