protected JsonElement convert(Memory src, Set<Integer> used, boolean useHandlers) {
        if (useHandlers) {
            Handler handler = typeHandlers.get(src.getRealType());
            if (handler != null) {
                return convert(handler.call(getEnv(), src), used, false);
            }
        }

        switch (src.getRealType()) {
            case BOOL:
                return new JsonPrimitive(src.toBoolean());
            case DOUBLE:
                return new JsonPrimitive(src.toDouble());
            case INT:
                return new JsonPrimitive(src.toLong());
            case STRING: {
                if (numericCheck) {
                    Memory m = StringMemory.toLong(src.toString());
                    if (m != null) {
                        return new JsonPrimitive(m.toLong());
                    } else {
                        return new JsonPrimitive(src.toString());
                    }
                } else {
                    return new JsonPrimitive(unescapedUnicode ? src.toString() : escapeUnicode(src.toString()));
                }
            }
            case NULL:
                return JsonNull.INSTANCE;
            case ARRAY: {
                if (used.add(src.getPointer())) {
                    JsonArray array = new JsonArray();
                    JsonObject object = new JsonObject();

                    boolean isList = !forceObject && src.toValue(ArrayMemory.class).isList();
                    ForeachIterator iterator = src.toValue(ArrayMemory.class).foreachIterator(false, false);
                    while (iterator.next()) {
                        if (isList) {
                            array.add(convert(iterator.getValue(), used, useHandlers));
                        } else {
                            object.add(iterator.getKey().toString(), convert(iterator.getValue(), used, useHandlers));
                        }
                    }
                    used.remove(src.getPointer());
                    return isList ? array : object;
                } else {
                    return JsonNull.INSTANCE;
                }
            }
            case OBJECT: {
                if (used.add(src.getPointer())) {
                    IObject object = src.toValue(ObjectMemory.class).value;

                    if (useHandlers) {
                        Handler handler;

                        ClassEntity pr = object.getReflection();
                        do {
                            handler = classHandlers.get(pr.getLowerName());
                            pr = pr.getParent();
                            if (pr == null) {
                                break;
                            }

                        } while (handler == null);

                        if (handler != null) {
                            return convert(handler.call(getEnv(), src), used, false);
                        }
                    }

                    if (object instanceof JsonSerializable) {
                        Environment env = this.getEnv() == null ? Environment.current() : this.getEnv();

                        env.pushCall(object, "jsonSerialize");
                        try {
                            Memory r = ((JsonSerializable) object).jsonSerialize(Environment.current());
                            return convert(r, used, useHandlers);
                        } finally {
                            env.popCall();
                        }
                    } else {
                        ForeachIterator iterator = object.getProperties().foreachIterator(false, false);
                        JsonObject r = new JsonObject();
                        while (iterator.next()) {
                            String key = iterator.getKey().toString();
                            if (!key.startsWith("\0")) {
                                r.add(iterator.getKey().toString(), convert(iterator.getValue(), used, useHandlers));
                            }
                        }
                        return r;
                    }
                } else {
                    return JsonNull.INSTANCE;
                }
            }
            default:
                return JsonNull.INSTANCE;
        }
    }
Finds first occurrence of unicode character and returns its index or {@code -1} otherwise.
exts/jphp-json-ext/src/main/java/org/develnext/jphp/json/gson/MemorySerializer.java