@Override
    public TMessage readMessageBegin() throws TException {
        root = null;
        try {
            readRoot();
        } catch (IOException e) {
            throw new TException("Could not parse input, is it valid json?", e);
        }
        assert root != null;
        if (!root.isObject()) {
            throw new TException("The top level of the input must be a json object with method and args!");
        }

        if (!root.has("method")) {
            throw new TException("Object must have field 'method' with the rpc method name!");
        }
        final String methodName = root.get("method").asText();

        if (!root.has("type")) {
            throw new TException(
                    "Object must have field 'type' with the message type (CALL, REPLY, EXCEPTION, ONEWAY)!");
        }
        final Byte messageType = TypedParser.TMESSAGE_TYPE.readFromJsonElement(root.get("type"));

        if (!root.has("args") || !root.get("args").isObject()) {
            throw new TException("Object must have field 'args' with the rpc method args!");
        }

        final int sequenceId = root.has("seqid") ? root.get("seqid").asInt() : 0;

        // Override the root with the content of args - thrift's rpc reading will
        // proceed to read it as a message object.
        root = root.get("args");

        return new TMessage(methodName, messageType, sequenceId);
    }
Write out the given value, either as a JSON name (meaning it's
escaped by quotes), or a value. The TypedParser knows how to
handle the writing.
thrift/thrift0.13/src/main/java/com/linecorp/armeria/common/thrift/text/TTextProtocol.java