You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@servicecomb.apache.org by li...@apache.org on 2020/12/07 09:34:48 UTC

[servicecomb-java-chassis] branch master updated: [SCB-2147] add RestClientCodecFilter (#2105)

This is an automated email from the ASF dual-hosted git repository.

liubao pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/servicecomb-java-chassis.git


The following commit(s) were added to refs/heads/master by this push:
     new 90f4ef8  [SCB-2147] add RestClientCodecFilter (#2105)
90f4ef8 is described below

commit 90f4ef890099109892beec99e7c944b88b33f693
Author: wujimin <wu...@huawei.com>
AuthorDate: Mon Dec 7 17:34:38 2020 +0800

    [SCB-2147] add RestClientCodecFilter (#2105)
---
 .../apache/servicecomb/core/filter/FilterNode.java |   2 +-
 .../foundation/common/net/URIEndpointObject.java   |   2 +-
 .../rest/client/RestClientCodecFilter.java         |  80 ++++++++
 .../transport/rest/client/RestClientEncoder.java   | 206 +++++++++++----------
 .../rest/client/RestClientCodecFilterTest.java     |  73 ++++++++
 .../rest/client/RestClientEncoderTest.java         |  25 ++-
 6 files changed, 273 insertions(+), 115 deletions(-)

diff --git a/core/src/main/java/org/apache/servicecomb/core/filter/FilterNode.java b/core/src/main/java/org/apache/servicecomb/core/filter/FilterNode.java
index cbed2f8..a6f817c 100644
--- a/core/src/main/java/org/apache/servicecomb/core/filter/FilterNode.java
+++ b/core/src/main/java/org/apache/servicecomb/core/filter/FilterNode.java
@@ -29,7 +29,7 @@ import org.apache.servicecomb.swagger.invocation.Response;
 public class FilterNode {
   public static final FilterNode EMPTY = new FilterNode(null) {
     @Override
-    public CompletableFuture<Response> onFilter(Invocation invocation1) {
+    public CompletableFuture<Response> onFilter(Invocation invocation) {
       return CompletableFuture.completedFuture(Response.ok(null));
     }
   };
diff --git a/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/common/net/URIEndpointObject.java b/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/common/net/URIEndpointObject.java
index 8729034..517a25f 100644
--- a/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/common/net/URIEndpointObject.java
+++ b/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/common/net/URIEndpointObject.java
@@ -54,7 +54,7 @@ public class URIEndpointObject extends IpPort {
     querys = splitQuery(uri);
     sslEnabled = Boolean.parseBoolean(getFirst(SSL_ENABLED_KEY));
     String httpVersion = getFirst(PROTOCOL_KEY);
-    if (httpVersion != null && httpVersion.equals(HTTP2)) {
+    if (HTTP2.equals(httpVersion)) {
       http2Enabled = true;
     }
   }
diff --git a/transports/transport-rest/transport-rest-client/src/main/java/org/apache/servicecomb/transport/rest/client/RestClientCodecFilter.java b/transports/transport-rest/transport-rest-client/src/main/java/org/apache/servicecomb/transport/rest/client/RestClientCodecFilter.java
new file mode 100644
index 0000000..c9efd54
--- /dev/null
+++ b/transports/transport-rest/transport-rest-client/src/main/java/org/apache/servicecomb/transport/rest/client/RestClientCodecFilter.java
@@ -0,0 +1,80 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.servicecomb.transport.rest.client;
+
+import static org.apache.servicecomb.swagger.invocation.InvocationType.CONSUMER;
+
+import java.util.concurrent.CompletableFuture;
+
+import org.apache.servicecomb.core.Invocation;
+import org.apache.servicecomb.core.filter.Filter;
+import org.apache.servicecomb.core.filter.FilterMeta;
+import org.apache.servicecomb.core.filter.FilterNode;
+import org.apache.servicecomb.swagger.invocation.Response;
+import org.springframework.beans.factory.annotation.Autowired;
+
+@FilterMeta(name = "rest-client-codec", invocationType = CONSUMER)
+public class RestClientCodecFilter implements Filter {
+  protected RestClientTransportContextFactory transportContextFactory;
+
+  protected RestClientEncoder encoder;
+
+  protected RestClientDecoder decoder;
+
+  @Autowired
+  public RestClientCodecFilter setTransportContextFactory(RestClientTransportContextFactory transportContextFactory) {
+    this.transportContextFactory = transportContextFactory;
+    return this;
+  }
+
+  @Autowired
+  public RestClientCodecFilter setEncoder(RestClientEncoder encoder) {
+    this.encoder = encoder;
+    return this;
+  }
+
+  @Autowired
+  public RestClientCodecFilter setDecoder(RestClientDecoder decoder) {
+    this.decoder = decoder;
+    return this;
+  }
+
+  @Override
+  public CompletableFuture<Response> onFilter(Invocation invocation, FilterNode nextNode) {
+    publishClientFiltersStartEvent(invocation);
+
+    return CompletableFuture.completedFuture(null)
+        .thenAccept(v -> prepareTransportContext(invocation))
+        .thenAccept(v -> encoder.encode(invocation))
+        .thenCompose(v -> nextNode.onFilter(invocation))
+        .thenApply(response -> decoder.decode(invocation, response))
+        .whenComplete((response, throwable) -> publishClientFiltersFinishEvent(invocation));
+  }
+
+  protected void publishClientFiltersStartEvent(Invocation invocation) {
+    invocation.getInvocationStageTrace().startClientFiltersRequest();
+  }
+
+  protected void prepareTransportContext(Invocation invocation) {
+    RestClientTransportContext transportContext = transportContextFactory.create(invocation);
+    invocation.setTransportContext(transportContext);
+  }
+
+  protected void publishClientFiltersFinishEvent(Invocation invocation) {
+    invocation.getInvocationStageTrace().finishClientFiltersResponse();
+  }
+}
diff --git a/transports/transport-rest/transport-rest-client/src/main/java/org/apache/servicecomb/transport/rest/client/RestClientEncoder.java b/transports/transport-rest/transport-rest-client/src/main/java/org/apache/servicecomb/transport/rest/client/RestClientEncoder.java
index fa36b4f..f590bc9 100644
--- a/transports/transport-rest/transport-rest-client/src/main/java/org/apache/servicecomb/transport/rest/client/RestClientEncoder.java
+++ b/transports/transport-rest/transport-rest-client/src/main/java/org/apache/servicecomb/transport/rest/client/RestClientEncoder.java
@@ -42,6 +42,7 @@ import org.apache.servicecomb.foundation.common.utils.StringBuilderUtils;
 import org.apache.servicecomb.swagger.invocation.exception.InvocationException;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
+import org.springframework.stereotype.Component;
 import org.springframework.util.CollectionUtils;
 
 import com.fasterxml.jackson.core.JsonProcessingException;
@@ -54,145 +55,150 @@ import io.vertx.core.http.HttpClientRequest;
 /**
  * encode all send data except upload
  */
+@Component
 public class RestClientEncoder {
   private static final Logger LOGGER = LoggerFactory.getLogger(RestClientEncoder.class);
 
   public static final int FORM_BUFFER_SIZE = 1024;
 
-  protected final Invocation invocation;
-
-  protected final RestClientTransportContext transportContext;
-
-  protected final RestClientRequestParameters requestParameters;
-
-  protected final HttpClientRequest httpClientRequest;
-
-  public RestClientEncoder(Invocation invocation) {
-    this.invocation = invocation;
-    this.transportContext = invocation.getTransportContext();
-    this.requestParameters = transportContext.getRequestParameters();
-    this.httpClientRequest = transportContext.getHttpClientRequest();
-  }
-
-  public void encode() {
+  public void encode(Invocation invocation) {
     try {
-      doEncode();
+      EncoderSession encoderSession = new EncoderSession(invocation);
+      encoderSession.doEncode();
     } catch (Exception e) {
       throw new InvocationException(BAD_REQUEST, FAILED_TO_ENCODE_REST_CLIENT_REQUEST, e.getMessage(), e);
     }
   }
 
-  protected void doEncode() throws Exception {
-    LOGGER.debug("rest client request, method={}, operation={}, endpoint={}, path={}.",
-        httpClientRequest.method(),
-        invocation.getMicroserviceQualifiedName(),
-        invocation.getEndpoint().getEndpoint(),
-        httpClientRequest.uri());
+  public static class EncoderSession {
+    protected final Invocation invocation;
 
-    swaggerArgumentsToRequest();
+    protected final RestClientTransportContext transportContext;
 
-    writeCookies(requestParameters.getCookieMap());
-    writeScbHeaders();
-    writeForm(requestParameters.getFormMap());
-  }
+    protected final RestClientRequestParameters requestParameters;
 
-  protected void swaggerArgumentsToRequest() throws Exception {
-    RestCodec.argsToRest(invocation.getSwaggerArguments(), transportContext.getRestOperationMeta(), requestParameters);
-  }
+    protected final HttpClientRequest httpClientRequest;
 
-  protected void writeCookies(@Nullable Map<String, String> cookieMap) {
-    if (CollectionUtils.isEmpty(cookieMap)) {
-      return;
+    public EncoderSession(Invocation invocation) {
+      this.invocation = invocation;
+      this.transportContext = invocation.getTransportContext();
+      this.requestParameters = this.transportContext.getRequestParameters();
+      this.httpClientRequest = this.transportContext.getHttpClientRequest();
     }
 
-    StringBuilder builder = new StringBuilder();
-    for (Entry<String, String> entry : cookieMap.entrySet()) {
-      builder.append(entry.getKey())
-          .append('=')
-          .append(entry.getValue())
-          .append("; ");
-    }
-    StringBuilderUtils.deleteLast(builder, 2);
-    httpClientRequest.putHeader(HttpHeaders.COOKIE, builder.toString());
-  }
+    protected void doEncode() throws Exception {
+      RestClientEncoder.LOGGER.debug("rest client request, method={}, operation={}, endpoint={}, path={}.",
+          httpClientRequest.method(),
+          invocation.getMicroserviceQualifiedName(),
+          invocation.getEndpoint().getEndpoint(),
+          httpClientRequest.uri());
+
+      swaggerArgumentsToRequest();
 
-  protected void writeScbHeaders() throws JsonProcessingException {
-    OperationConfig operationConfig = invocation.getOperationMeta().getConfig();
-    if (invocation.isThirdPartyInvocation() && operationConfig.isClientRequestHeaderFilterEnabled()) {
-      return;
+      writeCookies(requestParameters.getCookieMap());
+      writeScbHeaders();
+      writeForm(requestParameters.getFormMap());
     }
 
-    httpClientRequest.putHeader(Const.TARGET_MICROSERVICE, invocation.getMicroserviceName());
-    httpClientRequest.putHeader(Const.CSE_CONTEXT,
-        RestObjectMapperFactory.getRestObjectMapper().writeValueAsString(invocation.getContext()));
-  }
+    protected void swaggerArgumentsToRequest() throws Exception {
+      RestCodec
+          .argsToRest(invocation.getSwaggerArguments(), transportContext.getRestOperationMeta(), requestParameters);
+    }
 
-  protected void writeForm(@Nullable Map<String, Object> formMap) throws Exception {
-    if (requestParameters.getUploads() == null) {
-      writeUrlEncodedForm(formMap);
-      return;
+    protected void writeCookies(@Nullable Map<String, String> cookieMap) {
+      if (CollectionUtils.isEmpty(cookieMap)) {
+        return;
+      }
+
+      StringBuilder builder = new StringBuilder();
+      for (Entry<String, String> entry : cookieMap.entrySet()) {
+        builder.append(entry.getKey())
+            .append('=')
+            .append(entry.getValue())
+            .append("; ");
+      }
+      StringBuilderUtils.deleteLast(builder, 2);
+      httpClientRequest.putHeader(HttpHeaders.COOKIE, builder.toString());
     }
 
-    writeChunkedForm(formMap);
-  }
+    protected void writeScbHeaders() throws JsonProcessingException {
+      OperationConfig operationConfig = invocation.getOperationMeta().getConfig();
+      if (invocation.isThirdPartyInvocation() && operationConfig.isClientRequestHeaderFilterEnabled()) {
+        return;
+      }
 
-  protected void writeUrlEncodedForm(@Nullable Map<String, Object> formMap) throws Exception {
-    if (formMap == null) {
-      return;
+      httpClientRequest.putHeader(Const.TARGET_MICROSERVICE, invocation.getMicroserviceName());
+      httpClientRequest.putHeader(Const.CSE_CONTEXT,
+          RestObjectMapperFactory.getRestObjectMapper().writeValueAsString(invocation.getContext()));
     }
 
-    httpClientRequest.putHeader(CONTENT_TYPE, MediaType.APPLICATION_FORM_URLENCODED);
+    protected void writeForm(@Nullable Map<String, Object> formMap) throws Exception {
+      if (requestParameters.getUploads() == null) {
+        writeUrlEncodedForm(formMap);
+        return;
+      }
 
-    Buffer bodyBuffer = genUrlEncodedFormBuffer(formMap);
-    requestParameters.setBodyBuffer(bodyBuffer);
-  }
+      writeChunkedForm(formMap);
+    }
 
-  protected Buffer genUrlEncodedFormBuffer(@Nonnull Map<String, Object> formMap) throws Exception {
-    // 2x faster than UriComponentsBuilder
-    ByteBuf byteBuf = Unpooled.buffer(FORM_BUFFER_SIZE);
-    for (Entry<String, Object> entry : formMap.entrySet()) {
-      writeCharSequence(byteBuf, entry.getKey());
-      byteBuf.writeByte('=');
+    protected void writeUrlEncodedForm(@Nullable Map<String, Object> formMap) throws Exception {
+      if (formMap == null) {
+        return;
+      }
 
-      String value = QueryCodec.convertToString(entry.getValue());
-      String encodedValue = URLEncoder.encode(value, StandardCharsets.UTF_8.name());
-      writeCharSequence(byteBuf, encodedValue);
+      httpClientRequest.putHeader(CONTENT_TYPE, MediaType.APPLICATION_FORM_URLENCODED);
 
-      byteBuf.markWriterIndex();
-      byteBuf.writeByte('&');
+      Buffer bodyBuffer = genUrlEncodedFormBuffer(formMap);
+      requestParameters.setBodyBuffer(bodyBuffer);
     }
 
-    byteBuf.resetWriterIndex();
-    return Buffer.buffer(byteBuf);
-  }
+    protected Buffer genUrlEncodedFormBuffer(@Nonnull Map<String, Object> formMap) throws Exception {
+      // 2x faster than UriComponentsBuilder
+      ByteBuf byteBuf = Unpooled.buffer(RestClientEncoder.FORM_BUFFER_SIZE);
+      for (Entry<String, Object> entry : formMap.entrySet()) {
+        writeCharSequence(byteBuf, entry.getKey());
+        byteBuf.writeByte('=');
 
-  protected void writeChunkedForm(@Nullable Map<String, Object> formMap) throws Exception {
-    String boundary = transportContext.getOrCreateBoundary();
+        String value = QueryCodec.convertToString(entry.getValue());
+        String encodedValue = URLEncoder.encode(value, StandardCharsets.UTF_8.name());
+        writeCharSequence(byteBuf, encodedValue);
 
-    httpClientRequest.setChunked(true);
-    httpClientRequest.putHeader(CONTENT_TYPE, MULTIPART_FORM_DATA + "; charset=UTF-8; boundary=" + boundary);
+        byteBuf.markWriterIndex();
+        byteBuf.writeByte('&');
+      }
 
-    if (formMap == null) {
-      return;
+      byteBuf.resetWriterIndex();
+      return Buffer.buffer(byteBuf);
     }
 
-    Buffer bodyBuffer = genChunkedFormBuffer(formMap, boundary);
-    requestParameters.setBodyBuffer(bodyBuffer);
-  }
+    protected void writeChunkedForm(@Nullable Map<String, Object> formMap) throws Exception {
+      String boundary = transportContext.getOrCreateBoundary();
+
+      httpClientRequest.setChunked(true);
+      httpClientRequest.putHeader(CONTENT_TYPE, MULTIPART_FORM_DATA + "; charset=UTF-8; boundary=" + boundary);
+
+      if (formMap == null) {
+        return;
+      }
 
-  protected Buffer genChunkedFormBuffer(@Nonnull Map<String, Object> formMap, String boundary) throws Exception {
-    ByteBuf byteBuf = Unpooled.buffer(FORM_BUFFER_SIZE);
-    for (Entry<String, Object> entry : formMap.entrySet()) {
-      writeCharSequence(byteBuf, "\r\n--");
-      writeCharSequence(byteBuf, boundary);
-      writeCharSequence(byteBuf, "\r\nContent-Disposition: form-data; name=\"");
-      writeCharSequence(byteBuf, entry.getKey());
-      writeCharSequence(byteBuf, "\"\r\n\r\n");
-
-      String value = QueryCodec.convertToString(entry.getValue());
-      writeCharSequence(byteBuf, value);
+      Buffer bodyBuffer = genChunkedFormBuffer(formMap, boundary);
+      requestParameters.setBodyBuffer(bodyBuffer);
+    }
+
+    protected Buffer genChunkedFormBuffer(@Nonnull Map<String, Object> formMap, String boundary) throws Exception {
+      ByteBuf byteBuf = Unpooled.buffer(RestClientEncoder.FORM_BUFFER_SIZE);
+      for (Entry<String, Object> entry : formMap.entrySet()) {
+        writeCharSequence(byteBuf, "\r\n--");
+        writeCharSequence(byteBuf, boundary);
+        writeCharSequence(byteBuf, "\r\nContent-Disposition: form-data; name=\"");
+        writeCharSequence(byteBuf, entry.getKey());
+        writeCharSequence(byteBuf, "\"\r\n\r\n");
+
+        String value = QueryCodec.convertToString(entry.getValue());
+        writeCharSequence(byteBuf, value);
+      }
+      return Buffer.buffer(byteBuf);
     }
-    return Buffer.buffer(byteBuf);
   }
 
   protected static void writeCharSequence(ByteBuf byteBuf, String value) {
diff --git a/transports/transport-rest/transport-rest-client/src/test/java/org/apache/servicecomb/transport/rest/client/RestClientCodecFilterTest.java b/transports/transport-rest/transport-rest-client/src/test/java/org/apache/servicecomb/transport/rest/client/RestClientCodecFilterTest.java
new file mode 100644
index 0000000..b240f69
--- /dev/null
+++ b/transports/transport-rest/transport-rest-client/src/test/java/org/apache/servicecomb/transport/rest/client/RestClientCodecFilterTest.java
@@ -0,0 +1,73 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.servicecomb.transport.rest.client;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.catchThrowable;
+
+import java.util.concurrent.CompletableFuture;
+
+import javax.ws.rs.core.Response.Status;
+
+import org.apache.servicecomb.core.Invocation;
+import org.apache.servicecomb.core.filter.FilterNode;
+import org.apache.servicecomb.foundation.common.utils.AsyncUtils;
+import org.apache.servicecomb.foundation.test.scaffolding.exception.RuntimeExceptionWithoutStackTrace;
+import org.apache.servicecomb.swagger.invocation.Response;
+import org.junit.jupiter.api.Test;
+
+class RestClientCodecFilterTest extends RestClientTestBase {
+  RestClientEncoder encoder = new RestClientEncoder();
+
+  RestClientDecoder decoder = new RestClientDecoder();
+
+  RestClientCodecFilter codecFilter = new RestClientCodecFilter()
+      .setTransportContextFactory(factory)
+      .setEncoder(encoder)
+      .setDecoder(decoder);
+
+  @Test
+  void should_publish_start_and_finish_client_filters_event_when_succeed() {
+    init("query", null, false);
+
+    Response response = codecFilter.onFilter(invocation, FilterNode.EMPTY).join();
+
+    assertThat(response.getStatusCode()).isEqualTo(Status.OK.getStatusCode());
+    assertThat(invocation.getInvocationStageTrace().getStartClientFiltersRequest()).isNotEqualTo(0);
+    assertThat(invocation.getInvocationStageTrace().getFinishClientFiltersResponse()).isNotEqualTo(0);
+  }
+
+  @Test
+  void should_publish_start_and_finish_client_filters_event_when_failed() {
+    init("query", null, false);
+
+    RuntimeExceptionWithoutStackTrace mockThrowable = new RuntimeExceptionWithoutStackTrace("mock filter failed");
+    FilterNode filterNode = new FilterNode(null) {
+      @Override
+      public CompletableFuture<Response> onFilter(Invocation invocation) {
+        return AsyncUtils.completeExceptionally(mockThrowable);
+      }
+    };
+
+    Throwable throwable = catchThrowable(() -> codecFilter.onFilter(invocation, filterNode).join());
+
+    assertThat(throwable.getCause()).isSameAs(mockThrowable);
+    assertThat(invocation.getInvocationStageTrace().getStartClientFiltersRequest()).isNotEqualTo(0);
+    assertThat(invocation.getInvocationStageTrace().getFinishClientFiltersResponse()).isNotEqualTo(0);
+  }
+}
\ No newline at end of file
diff --git a/transports/transport-rest/transport-rest-client/src/test/java/org/apache/servicecomb/transport/rest/client/RestClientEncoderTest.java b/transports/transport-rest/transport-rest-client/src/test/java/org/apache/servicecomb/transport/rest/client/RestClientEncoderTest.java
index 753220f..539a38d 100644
--- a/transports/transport-rest/transport-rest-client/src/test/java/org/apache/servicecomb/transport/rest/client/RestClientEncoderTest.java
+++ b/transports/transport-rest/transport-rest-client/src/test/java/org/apache/servicecomb/transport/rest/client/RestClientEncoderTest.java
@@ -36,18 +36,17 @@ import com.google.common.collect.ImmutableMap;
 import com.google.common.collect.Lists;
 
 class RestClientEncoderTest extends RestClientTestBase {
-  RestClientEncoder encoder;
+  RestClientEncoder encoder = new RestClientEncoder();
 
   void init(String operationId, Map<String, Object> swaggerArgs) {
     init(operationId, swaggerArgs, false);
-    encoder = new RestClientEncoder(invocation);
   }
 
   @Test
   void should_encode_header_parameter() {
     init("header", ImmutableMap.of("header", "value"));
 
-    encoder.encode();
+    encoder.encode(invocation);
 
     assertThat(httpClientRequest.headers().get("header"))
         .isEqualTo("value");
@@ -57,7 +56,7 @@ class RestClientEncoderTest extends RestClientTestBase {
   void should_encode_servicecomb_headers() {
     init("header", ImmutableMap.of("header", "value"));
 
-    encoder.encode();
+    encoder.encode(invocation);
 
     assertThat(httpClientRequest.headers().toString())
         .isEqualTo("header: value\n"
@@ -71,7 +70,7 @@ class RestClientEncoderTest extends RestClientTestBase {
     referenceConfig.setThirdPartyService(true);
     operationMeta.getConfig().setClientRequestHeaderFilterEnabled(true);
 
-    encoder.encode();
+    encoder.encode(invocation);
 
     assertThat(httpClientRequest.headers().toString())
         .isEqualTo("header: value\n");
@@ -83,7 +82,7 @@ class RestClientEncoderTest extends RestClientTestBase {
     referenceConfig.setThirdPartyService(true);
     operationMeta.getConfig().setClientRequestHeaderFilterEnabled(false);
 
-    encoder.encode();
+    encoder.encode(invocation);
 
     assertThat(httpClientRequest.headers().toString())
         .isEqualTo("header: value\n"
@@ -95,7 +94,7 @@ class RestClientEncoderTest extends RestClientTestBase {
   void should_encode_cookie_parameter() {
     init("cookie", ImmutableMap.of("cookie1", "v1", "cookie2", "v2"));
 
-    encoder.encode();
+    encoder.encode(invocation);
 
     assertThat(httpClientRequest.headers().get(HttpHeaders.COOKIE))
         .isEqualTo("cookie1=v1; cookie2=v2");
@@ -105,7 +104,7 @@ class RestClientEncoderTest extends RestClientTestBase {
   void should_encode_body_parameter() {
     init("body", ImmutableMap.of("body", "value"));
 
-    encoder.encode();
+    encoder.encode(invocation);
 
     assertThat(transportContext.getRequestParameters().getBodyBuffer().toString())
         .isEqualTo("\"value\"");
@@ -115,7 +114,7 @@ class RestClientEncoderTest extends RestClientTestBase {
   void should_encode_form_attribute_parameter() {
     init("form", ImmutableMap.of("form1", "v1", "form2", "v2"));
 
-    encoder.encode();
+    encoder.encode(invocation);
 
     assertThat(httpClientRequest.headers().get(HttpHeaders.CONTENT_TYPE))
         .isEqualTo(MediaType.APPLICATION_FORM_URLENCODED);
@@ -130,7 +129,7 @@ class RestClientEncoderTest extends RestClientTestBase {
     swaggerArgs.put("form2", null);
     init("form", swaggerArgs);
 
-    encoder.encode();
+    encoder.encode(invocation);
 
     assertThat(httpClientRequest.headers().get(HttpHeaders.CONTENT_TYPE))
         .isEqualTo(MediaType.APPLICATION_FORM_URLENCODED);
@@ -142,7 +141,7 @@ class RestClientEncoderTest extends RestClientTestBase {
   void should_encode_form_with_upload_parameter() {
     init("formWithUpload", ImmutableMap.of("form1", "v1", "form2", new File("form2")));
 
-    encoder.encode();
+    encoder.encode(invocation);
 
     RestClientRequestParameters requestParameters = transportContext.getRequestParameters();
     assertThat(requestParameters.getBodyBuffer().toString())
@@ -160,7 +159,7 @@ class RestClientEncoderTest extends RestClientTestBase {
   void should_encode_form_with_upload_list() {
     init("formWithUploadList", ImmutableMap.of("files", Arrays.asList(new File("f1"), new File("f2"))));
 
-    encoder.encode();
+    encoder.encode(invocation);
 
     checkUploadList();
   }
@@ -169,7 +168,7 @@ class RestClientEncoderTest extends RestClientTestBase {
   void should_encode_form_with_upload_array() {
     init("formWithUploadList", ImmutableMap.of("files", new File[] {new File("f1"), new File("f2")}));
 
-    encoder.encode();
+    encoder.encode(invocation);
 
     checkUploadList();
   }