@Nullable
    @Override
    public Object convertRequest(ServiceRequestContext ctx, AggregatedHttpRequest request,
                                 Class<?> expectedResultType,
                                 @Nullable ParameterizedType expectedParameterizedResultType) throws Exception {

        final MediaType contentType = request.contentType();
        final Charset charset = contentType == null ? StandardCharsets.UTF_8
                                                    : contentType.charset(StandardCharsets.UTF_8);

        if (resultType == ResultType.PROTOBUF ||
            (resultType == ResultType.UNKNOWN && Message.class.isAssignableFrom(expectedResultType))) {
            final Message.Builder messageBuilder = getMessageBuilder(expectedResultType);

            if (isProtobuf(contentType)) {
                try (InputStream is = request.content().toInputStream()) {
                    return messageBuilder.mergeFrom(is, extensionRegistry).build();
                }
            }

            if (isJson(contentType)) {
                jsonParser.merge(request.content(charset), messageBuilder);
                return messageBuilder.build();
            }
        }

        if (!isJson(contentType) || expectedParameterizedResultType == null) {
            return RequestConverterFunction.fallthrough();
        }

        ResultType resultType = this.resultType;
        if (resultType == ResultType.UNKNOWN) {
            resultType = toResultType(expectedParameterizedResultType);
        }

        if (resultType == ResultType.UNKNOWN || resultType == ResultType.PROTOBUF) {
            return RequestConverterFunction.fallthrough();
        }

        final Type[] typeArguments = expectedParameterizedResultType.getActualTypeArguments();
        final String content = request.content(charset);
        final JsonNode jsonNode = mapper.readTree(content);

        switch (resultType) {
            case LIST_PROTOBUF:
            case SET_PROTOBUF:
                if (jsonNode.isArray()) {
                    final ImmutableCollection.Builder<Message> builder;
                    if (resultType == ResultType.LIST_PROTOBUF) {
                        builder = ImmutableList.builderWithExpectedSize(jsonNode.size());
                    } else {
                        builder = ImmutableSet.builderWithExpectedSize(jsonNode.size());
                    }

                    for (JsonNode node : jsonNode) {
                        final Message.Builder msgBuilder = getMessageBuilder((Class<?>) typeArguments[0]);
                        jsonParser.merge(mapper.writeValueAsString(node), msgBuilder);
                        builder.add(msgBuilder.build());
                    }
                    return builder.build();
                }
                break;
            case MAP_PROTOBUF:
                if (jsonNode.isObject()) {
                    final ImmutableMap.Builder<String, Message> builder =
                            ImmutableMap.builderWithExpectedSize(jsonNode.size());

                    for (final Iterator<Entry<String, JsonNode>> i = jsonNode.fields(); i.hasNext();) {
                        final Entry<String, JsonNode> e = i.next();
                        final Message.Builder msgBuilder = getMessageBuilder((Class<?>) typeArguments[1]);
                        jsonParser.merge(mapper.writeValueAsString(e.getValue()), msgBuilder);
                        builder.put(e.getKey(), msgBuilder.build());
                    }
                    return builder.build();
                }
                break;
        }

        return RequestConverterFunction.fallthrough();
    }
Creates an instance with the specified {@link Parser} and {@link ExtensionRegistry}.
protobuf/src/main/java/com/linecorp/armeria/server/protobuf/ProtobufRequestConverterFunction.java