private void generateOperationSerializerMiddleware()

in codegen/smithy-go-codegen/src/main/java/software/amazon/smithy/go/codegen/integration/HttpBindingProtocolGenerator.java [235:367]


    private void generateOperationSerializerMiddleware(GenerationContext context, OperationShape operation) {
        SymbolProvider symbolProvider = context.getSymbolProvider();
        Model model = context.getModel();
        ServiceShape service = context.getService();
        Shape inputShape = model.expectShape(operation.getInput()
                .orElseThrow(() -> new CodegenException("expect input shape for operation: " + operation.getId())));
        Symbol inputSymbol = symbolProvider.toSymbol(inputShape);
        ApplicationProtocol applicationProtocol = getApplicationProtocol();
        Symbol requestType = applicationProtocol.getRequestType();
        HttpTrait httpTrait = operation.expectTrait(HttpTrait.class);

        GoStackStepMiddlewareGenerator middleware = GoStackStepMiddlewareGenerator.createSerializeStepMiddleware(
                ProtocolGenerator.getSerializeMiddlewareName(operation.getId(), service, getProtocolName()),
                ProtocolUtils.OPERATION_SERIALIZER_MIDDLEWARE_ID);

        middleware.writeMiddleware(context.getWriter().get(), (generator, writer) -> {
            writer.addUseImports(SmithyGoDependency.FMT);
            writer.addUseImports(SmithyGoDependency.SMITHY);
            writer.addUseImports(SmithyGoDependency.SMITHY_HTTP_BINDING);

            writer.write(goTemplate("""
                    _, span := $T(ctx, "OperationSerializer")
                    endTimer := startMetricTimer(ctx, "client.call.serialization_duration")
                    defer endTimer()
                    defer span.End()
                    """, SMITHY_TRACING.func("StartSpan")));

            // cast input request to smithy transport type, check for failures
            writer.write("request, ok := in.Request.($P)", requestType);
            writer.openBlock("if !ok {", "}", () -> {
                writer.write("return out, metadata, "
                        + "&smithy.SerializationError{Err: fmt.Errorf(\"unknown transport type %T\", in.Request)}"
                );
            });
            writer.write("");

            // cast input parameters type to the input type of the operation
            writer.write("input, ok := in.Parameters.($P)", inputSymbol);
            writer.write("_ = input");
            writer.openBlock("if !ok {", "}", () -> {
                writer.write("return out, metadata, "
                        + "&smithy.SerializationError{Err: fmt.Errorf(\"unknown input parameters type %T\","
                        + " in.Parameters)}");
            });

            writer.write("");
            writer.write("opPath, opQuery := httpbinding.SplitURI($S)", httpTrait.getUri());
            writer.write("request.URL.Path = smithyhttp.JoinPath(request.URL.Path, opPath)");
            writer.write("request.URL.RawQuery = smithyhttp.JoinRawQuery(request.URL.RawQuery, opQuery)");
            writer.write("request.Method = $S", httpTrait.getMethod());
            writer.write(
                """
                var restEncoder $P
                if request.URL.RawPath == "" {
                    restEncoder, err = $T(request.URL.Path, request.URL.RawQuery, request.Header)
                } else {
                    request.URL.RawPath = $T(request.URL.RawPath, opPath)
                    restEncoder, err = $T(request.URL.Path, request.URL.RawPath, request.URL.RawQuery, request.Header)
                }
                """,
                SymbolUtils.createPointableSymbolBuilder(
                    "Encoder", SmithyGoDependency.SMITHY_HTTP_BINDING).build(),
                SymbolUtils.createValueSymbolBuilder(
                    "NewEncoder", SmithyGoDependency.SMITHY_HTTP_BINDING).build(),
                SymbolUtils.createValueSymbolBuilder(
                    "JoinPath", SmithyGoDependency.SMITHY_HTTP_TRANSPORT).build(),
                SymbolUtils.createValueSymbolBuilder(
                    "NewEncoderWithRawPath", SmithyGoDependency.SMITHY_HTTP_BINDING).build()
            );

            writer.openBlock("if err != nil {", "}", () -> {
                writer.write("return out, metadata, &smithy.SerializationError{Err: err}");
            });
            writer.write("");

            // we only generate an operations http bindings function if there are bindings
            if (isOperationWithRestRequestBindings(model, operation)) {
                String serFunctionName = ProtocolGenerator.getOperationHttpBindingsSerFunctionName(
                        inputShape, service, getProtocolName());
                writer.openBlock("if err := $L(input, restEncoder); err != nil {", "}", serFunctionName, () -> {
                    writer.write("return out, metadata, &smithy.SerializationError{Err: err}");
                });
                writer.write("");
            }

            // Don't consider serializing the body if the input shape is a stubbed synthetic clone, without an
            // archetype.
            if (!CodegenUtils.isStubSynthetic(ProtocolUtils.expectInput(model, operation))) {
                Optional<EventStreamInfo> eventStreamInfo = EventStreamIndex.of(model).getInputInfo(operation);
                // document bindings vs payload bindings vs event streams
                HttpBindingIndex httpBindingIndex = HttpBindingIndex.of(model);
                boolean hasDocumentBindings = httpBindingIndex
                        .getRequestBindings(operation, HttpBinding.Location.DOCUMENT)
                        .stream().anyMatch(httpBinding -> eventStreamInfo.map(streamInfo ->
                                !streamInfo.getEventStreamMember().equals(httpBinding.getMember())).orElse(true));

                Optional<HttpBinding> payloadBinding = httpBindingIndex.getRequestBindings(operation,
                        HttpBinding.Location.PAYLOAD).stream()
                        .filter(httpBinding -> eventStreamInfo.map(streamInfo ->
                                !streamInfo.getEventStreamMember().equals(httpBinding.getMember())).orElse(true))
                        .findFirst();

                if (eventStreamInfo.isPresent() && (hasDocumentBindings || payloadBinding.isPresent())) {
                    throw new CodegenException("HTTP Binding Protocol unexpected document or payload bindings with "
                            + "input event stream");
                }

                if (eventStreamInfo.isPresent()) {
                    writeOperationSerializerMiddlewareEventStreamSetup(context, eventStreamInfo.get());
                } else if (hasDocumentBindings) {
                    // delegate the setup and usage of the document serializer function for the protocol
                    writeMiddlewareDocumentSerializerDelegator(context, operation, generator);

                } else if (payloadBinding.isPresent()) {
                    // delegate the setup and usage of the payload serializer function for the protocol
                    MemberShape memberShape = payloadBinding.get().getMember();
                    writeMiddlewarePayloadSerializerDelegator(context, memberShape);
                }
                writer.write("");
            }

            // Serialize HTTP request with payload, if set.
            writer.openBlock("if request.Request, err = restEncoder.Encode(request.Request); err != nil {", "}", () -> {
                writer.write("return out, metadata, &smithy.SerializationError{Err: err}");
            });
            writer.write("in.Request = request");
            writer.write("");

            writer.write("endTimer()");
            writer.write("span.End()");
            writer.write("return next.$L(ctx, in)", generator.getHandleMethodName());
        });
    }