This is an automated email from the ASF dual-hosted git repository.
liubao pushed a commit to branch 2.8.x
in repository https://gitbox.apache.org/repos/asf/servicecomb-java-chassis.git
The following commit(s) were added to refs/heads/2.8.x by this push:
new 221fb379b [#4405]header parameter support array type (#4408)
221fb379b is described below
commit 221fb379b2582d82308fa9fc4e85a03545efac5b
Author: liubao68 <[email protected]>
AuthorDate: Tue Jul 9 09:37:12 2024 +0800
[#4405]header parameter support array type (#4408)
---
.../common/rest/codec/header/HeaderCodec.java | 45 +++++++++
.../common/rest/codec/header/HeaderCodecCsv.java | 28 ++++++
.../common/rest/codec/header/HeaderCodecMulti.java | 66 +++++++++++++
.../common/rest/codec/header/HeaderCodecPipes.java | 30 ++++++
.../rest/codec/header/HeaderCodecSimple.java | 52 ++++++++++
.../common/rest/codec/header/HeaderCodecSsv.java | 28 ++++++
.../common/rest/codec/header/HeaderCodecTsv.java | 27 ++++++
.../codec/header/HeaderCodecWithDelimiter.java | 84 ++++++++++++++++
.../rest/codec/header/HeaderCodecsUtils.java | 49 ++++++++++
.../rest/codec/param/HeaderProcessorCreator.java | 44 +++------
.../rest/codec/param/TestHeaderProcessor.java | 1 +
.../codec/param/TestRestClientRequestImpl.java | 63 +++++-------
.../demo/api/IHeaderParamWithListSchema.java | 64 ++++++++++++
.../client/ConsumerHeaderParamWithListSchema.java | 61 ++++++++++++
.../src/main/resources/application.yml | 10 ++
.../server/HeaderParamWithListSchema.java | 55 +++++++++++
.../tests/HeaderParamWithListSchemaIT.java | 108 +++++++++++++++++++++
.../demo/zeroconfig/tests/ServerTest.java | 3 +
18 files changed, 746 insertions(+), 72 deletions(-)
diff --git
a/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/codec/header/HeaderCodec.java
b/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/codec/header/HeaderCodec.java
new file mode 100644
index 000000000..546605d6b
--- /dev/null
+++
b/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/codec/header/HeaderCodec.java
@@ -0,0 +1,45 @@
+/*
+ * 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.common.rest.codec.header;
+
+import java.io.UnsupportedEncodingException;
+import java.net.URLEncoder;
+import java.nio.charset.StandardCharsets;
+
+import org.apache.servicecomb.common.rest.codec.RestClientRequest;
+import org.apache.servicecomb.common.rest.codec.RestObjectMapperFactory;
+import
org.apache.servicecomb.common.rest.codec.param.HeaderProcessorCreator.HeaderProcessor;
+
+import javax.servlet.http.HttpServletRequest;
+
+public interface HeaderCodec {
+ static String encodeValue(Object value) throws UnsupportedEncodingException {
+ return URLEncoder.encode(value.toString(), StandardCharsets.UTF_8.name());
+ }
+
+ // can not be replaced by value.toString() because of date serialize
+ static String convertToString(Object value) throws Exception {
+ return
RestObjectMapperFactory.getRestObjectMapper().convertToString(value);
+ }
+
+ String getCodecName();
+
+ void encode(RestClientRequest clientRequest, String name, Object value)
throws Exception;
+
+ Object decode(HeaderProcessor processor, HttpServletRequest request);
+}
diff --git
a/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/codec/header/HeaderCodecCsv.java
b/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/codec/header/HeaderCodecCsv.java
new file mode 100644
index 000000000..c2db1f12f
--- /dev/null
+++
b/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/codec/header/HeaderCodecCsv.java
@@ -0,0 +1,28 @@
+/*
+ * 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.common.rest.codec.header;
+
+public class HeaderCodecCsv extends HeaderCodecWithDelimiter {
+ public static final String CODEC_NAME = "csv";
+
+ public static final String DELIMITER = ",";
+
+ public HeaderCodecCsv() {
+ super(CODEC_NAME, DELIMITER, DELIMITER);
+ }
+}
diff --git
a/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/codec/header/HeaderCodecMulti.java
b/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/codec/header/HeaderCodecMulti.java
new file mode 100644
index 000000000..e53e09ca0
--- /dev/null
+++
b/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/codec/header/HeaderCodecMulti.java
@@ -0,0 +1,66 @@
+/*
+ * 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.common.rest.codec.header;
+
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Enumeration;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.ws.rs.core.Response.Status;
+
+import org.apache.servicecomb.common.rest.codec.RestClientRequest;
+import org.apache.servicecomb.common.rest.codec.RestObjectMapperFactory;
+import
org.apache.servicecomb.common.rest.codec.param.HeaderProcessorCreator.HeaderProcessor;
+import org.apache.servicecomb.swagger.invocation.exception.CommonExceptionData;
+import org.apache.servicecomb.swagger.invocation.exception.InvocationException;
+
+public class HeaderCodecMulti implements HeaderCodec {
+ public static final String NAME = "multi";
+
+ @Override
+ public String getCodecName() {
+ return NAME;
+ }
+
+ @Override
+ public void encode(RestClientRequest clientRequest, String name, Object
value) throws Exception {
+ if (null == value) {
+ // if value is empty, header should not be set to clientRequest to avoid
NullPointerException in Netty.
+ return;
+ }
+ if (!(value instanceof Collection<?>)) {
+ throw new InvocationException(Status.BAD_REQUEST,
+ new CommonExceptionData("Array type of header should be
Collection"));
+ }
+ for (Object item : ((Collection<?>) value)) {
+ clientRequest.getHeaders().add(name,
+
RestObjectMapperFactory.getConsumerWriterMapper().convertToString(item));
+ }
+ }
+
+ @Override
+ public Object decode(HeaderProcessor processor, HttpServletRequest request) {
+ Enumeration<String> headerValues =
request.getHeaders(processor.getParameterPath());
+ if (headerValues == null) {
+ //Even if the paramPath does not exist, headerValues won't be null at now
+ return null;
+ }
+ return processor.convertValue(Collections.list(headerValues),
processor.getTargetType());
+ }
+}
diff --git
a/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/codec/header/HeaderCodecPipes.java
b/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/codec/header/HeaderCodecPipes.java
new file mode 100644
index 000000000..4a96aaebe
--- /dev/null
+++
b/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/codec/header/HeaderCodecPipes.java
@@ -0,0 +1,30 @@
+/*
+ * 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.common.rest.codec.header;
+
+public class HeaderCodecPipes extends HeaderCodecWithDelimiter {
+ public static final String CODEC_NAME = "pipes";
+
+ public static final String JOIN_DELIMITER = "|";
+
+ public static final String SPLIT_DELIMITER = "\\|";
+
+ public HeaderCodecPipes() {
+ super(CODEC_NAME, JOIN_DELIMITER, SPLIT_DELIMITER);
+ }
+}
diff --git
a/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/codec/header/HeaderCodecSimple.java
b/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/codec/header/HeaderCodecSimple.java
new file mode 100644
index 000000000..3c37e56e2
--- /dev/null
+++
b/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/codec/header/HeaderCodecSimple.java
@@ -0,0 +1,52 @@
+/*
+ * 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.common.rest.codec.header;
+
+import javax.servlet.http.HttpServletRequest;
+
+import org.apache.servicecomb.common.rest.codec.RestClientRequest;
+import org.apache.servicecomb.common.rest.codec.RestObjectMapperFactory;
+import
org.apache.servicecomb.common.rest.codec.param.HeaderProcessorCreator.HeaderProcessor;
+
+public class HeaderCodecSimple implements HeaderCodec {
+ public static final String NAME = "simple";
+
+ @Override
+ public String getCodecName() {
+ return NAME;
+ }
+
+ @Override
+ public void encode(RestClientRequest clientRequest, String name, Object
value) throws Exception {
+ if (null == value) {
+ // if value is empty, header should not be set to clientRequest to avoid
NullPointerException in Netty.
+ return;
+ }
+ clientRequest.putHeader(name,
+
RestObjectMapperFactory.getConsumerWriterMapper().convertToString(value));
+ }
+
+ @Override
+ public Object decode(HeaderProcessor processor, HttpServletRequest request) {
+ Object value = request.getHeader(processor.getParameterPath());
+ if (value == null) {
+ value = processor.checkRequiredAndDefaultValue();
+ }
+ return processor.convertValue(value, processor.getTargetType());
+ }
+}
diff --git
a/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/codec/header/HeaderCodecSsv.java
b/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/codec/header/HeaderCodecSsv.java
new file mode 100644
index 000000000..9de25de2e
--- /dev/null
+++
b/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/codec/header/HeaderCodecSsv.java
@@ -0,0 +1,28 @@
+/*
+ * 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.common.rest.codec.header;
+
+public class HeaderCodecSsv extends HeaderCodecWithDelimiter {
+ public static final String CODEC_NAME = "ssv";
+
+ public static final String DELIMITER = " ";
+
+ public HeaderCodecSsv() {
+ super(CODEC_NAME, DELIMITER, DELIMITER);
+ }
+}
diff --git
a/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/codec/header/HeaderCodecTsv.java
b/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/codec/header/HeaderCodecTsv.java
new file mode 100644
index 000000000..51dda805c
--- /dev/null
+++
b/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/codec/header/HeaderCodecTsv.java
@@ -0,0 +1,27 @@
+/*
+ * 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.common.rest.codec.header;
+
+public class HeaderCodecTsv extends HeaderCodecWithDelimiter {
+ public static final String CODEC_NAME = "tsv";
+
+ public static final String DELIMITER = "\t";
+
+ public HeaderCodecTsv() {
+ super(CODEC_NAME, DELIMITER, DELIMITER);
+ }
+}
diff --git
a/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/codec/header/HeaderCodecWithDelimiter.java
b/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/codec/header/HeaderCodecWithDelimiter.java
new file mode 100644
index 000000000..75481c8ce
--- /dev/null
+++
b/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/codec/header/HeaderCodecWithDelimiter.java
@@ -0,0 +1,84 @@
+/*
+ * 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.common.rest.codec.header;
+
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.StringJoiner;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.ws.rs.core.Response.Status;
+
+import org.apache.servicecomb.common.rest.codec.RestClientRequest;
+import org.apache.servicecomb.common.rest.codec.RestObjectMapperFactory;
+import
org.apache.servicecomb.common.rest.codec.param.HeaderProcessorCreator.HeaderProcessor;
+import org.apache.servicecomb.swagger.invocation.exception.CommonExceptionData;
+import org.apache.servicecomb.swagger.invocation.exception.InvocationException;
+
+public abstract class HeaderCodecWithDelimiter implements HeaderCodec {
+ private final String name;
+
+ private final String joinDelimiter;
+
+ private final String splitDelimiter;
+
+ public HeaderCodecWithDelimiter(String name, String joinDelimiter, String
splitDelimiter) {
+ this.name = name;
+ this.joinDelimiter = joinDelimiter;
+ this.splitDelimiter = splitDelimiter;
+ }
+
+
+ @Override
+ public String getCodecName() {
+ return name;
+ }
+
+ @Override
+ public void encode(RestClientRequest clientRequest, String name, Object
value) throws Exception {
+ if (null == value) {
+ // if value is empty, header should not be set to clientRequest to avoid
NullPointerException in Netty.
+ return;
+ }
+ if (!(value instanceof Collection<?>)) {
+ throw new InvocationException(Status.BAD_REQUEST,
+ new CommonExceptionData("Array type of header should be
Collection"));
+ }
+ clientRequest.putHeader(name, join((Collection<?>) value));
+ }
+
+ protected String join(Collection<?> values) throws Exception {
+ StringJoiner joiner = new StringJoiner(joinDelimiter);
+ for (Object value : values) {
+ String strValue =
RestObjectMapperFactory.getConsumerWriterMapper().convertToString(value);
+ joiner.add(strValue);
+ }
+
+ return joiner.toString();
+ }
+
+ @Override
+ public Object decode(HeaderProcessor processor, HttpServletRequest request) {
+ String headerValues = request.getHeader(processor.getParameterPath());
+ if (headerValues == null) {
+ headerValues = (String) processor.checkRequiredAndDefaultValue();
+ }
+
+ return
processor.convertValue(Arrays.asList(headerValues.split(splitDelimiter)),
processor.getTargetType());
+ }
+}
diff --git
a/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/codec/header/HeaderCodecsUtils.java
b/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/codec/header/HeaderCodecsUtils.java
new file mode 100644
index 000000000..cbb968a31
--- /dev/null
+++
b/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/codec/header/HeaderCodecsUtils.java
@@ -0,0 +1,49 @@
+/*
+ * 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.common.rest.codec.header;
+
+import java.util.HashMap;
+import java.util.Map;
+
+public class HeaderCodecsUtils {
+ private static final Map<String, HeaderCodec> CODECS;
+
+ static {
+ CODECS = new HashMap<>();
+ CODECS.put(HeaderCodecSimple.NAME, new HeaderCodecSimple());
+ CODECS.put(HeaderCodecMulti.NAME, new HeaderCodecMulti());
+ CODECS.put(HeaderCodecCsv.CODEC_NAME, new HeaderCodecCsv());
+ CODECS.put(HeaderCodecTsv.CODEC_NAME, new HeaderCodecTsv());
+ CODECS.put(HeaderCodecPipes.CODEC_NAME, new HeaderCodecPipes());
+ CODECS.put(HeaderCodecSsv.CODEC_NAME, new HeaderCodecSsv());
+ }
+
+ private HeaderCodecsUtils() {
+ }
+
+ public static HeaderCodec find(String collectionFormat) {
+ return CODECS.get(formatName(collectionFormat));
+ }
+
+ private static String formatName(String collectionFormat) {
+ if (collectionFormat == null) {
+ return HeaderCodecSimple.NAME;
+ }
+ return collectionFormat;
+ }
+}
diff --git
a/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/codec/param/HeaderProcessorCreator.java
b/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/codec/param/HeaderProcessorCreator.java
index cb40fdf64..30846a27c 100644
---
a/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/codec/param/HeaderProcessorCreator.java
+++
b/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/codec/param/HeaderProcessorCreator.java
@@ -18,17 +18,15 @@
package org.apache.servicecomb.common.rest.codec.param;
import java.lang.reflect.Type;
-import java.util.Collections;
-import java.util.Enumeration;
import javax.servlet.http.HttpServletRequest;
import javax.ws.rs.core.Response.Status;
import org.apache.servicecomb.common.rest.codec.RestClientRequest;
-import org.apache.servicecomb.common.rest.codec.RestObjectMapperFactory;
+import org.apache.servicecomb.common.rest.codec.header.HeaderCodec;
+import org.apache.servicecomb.common.rest.codec.header.HeaderCodecMulti;
+import org.apache.servicecomb.common.rest.codec.header.HeaderCodecsUtils;
import org.apache.servicecomb.swagger.invocation.exception.InvocationException;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
import com.fasterxml.jackson.databind.JavaType;
import com.fasterxml.jackson.databind.type.TypeFactory;
@@ -39,8 +37,6 @@ import io.swagger.models.parameters.Parameter;
import io.swagger.models.properties.ArrayProperty;
public class HeaderProcessorCreator implements ParamValueProcessorCreator {
- private static final Logger LOGGER =
LoggerFactory.getLogger(HeaderProcessorCreator.class);
-
public static final String PARAMTYPE = "header";
public static class HeaderProcessor extends AbstractParamProcessor {
@@ -48,33 +44,25 @@ public class HeaderProcessorCreator implements
ParamValueProcessorCreator {
private final boolean ignoreRequiredCheck =
DynamicPropertyFactory.getInstance()
.getBooleanProperty("servicecomb.rest.parameter.header.ignoreRequiredCheck",
false).get();
- private final boolean repeatedType;
+ private final HeaderCodec headerCodec;
public HeaderProcessor(HeaderParameter headerParameter, JavaType
targetType) {
super(headerParameter.getName(), targetType,
headerParameter.getDefaultValue(), headerParameter.getRequired());
- this.repeatedType = ArrayProperty.isType(headerParameter.getType());
+ if ((ArrayProperty.isType(headerParameter.getType())) &&
headerParameter.getCollectionFormat() == null) {
+ // compatible to default settings
+ this.headerCodec = HeaderCodecsUtils.find(HeaderCodecMulti.NAME);
+ } else {
+ this.headerCodec =
HeaderCodecsUtils.find(headerParameter.getCollectionFormat());
+ }
}
@Override
public Object getValue(HttpServletRequest request) {
- if (repeatedType) {
- Enumeration<String> headerValues = request.getHeaders(paramPath);
- if (headerValues == null) {
- //Even if the paramPath does not exist, headerValues won't be null
at now
- return null;
- }
- return convertValue(Collections.list(headerValues), targetType);
- }
-
- Object value = request.getHeader(paramPath);
- if (value == null) {
- value = checkRequiredAndDefaultValue();
- }
- return convertValue(value, targetType);
+ return headerCodec.decode(this, request);
}
- private Object checkRequiredAndDefaultValue() {
+ public Object checkRequiredAndDefaultValue() {
if (!ignoreRequiredCheck && isRequired()) {
throw new InvocationException(Status.BAD_REQUEST, "Parameter is
required.");
}
@@ -83,13 +71,7 @@ public class HeaderProcessorCreator implements
ParamValueProcessorCreator {
@Override
public void setValue(RestClientRequest clientRequest, Object arg) throws
Exception {
- if (null == arg) {
- // null header should not be set to clientRequest to avoid
NullPointerException in Netty.
- LOGGER.debug("Header arg is null, will not be set into clientRequest.
paramPath = [{}]", paramPath);
- return;
- }
- clientRequest.putHeader(paramPath,
-
RestObjectMapperFactory.getConsumerWriterMapper().convertToString(arg));
+ headerCodec.encode(clientRequest, paramPath, arg);
}
@Override
diff --git
a/common/common-rest/src/test/java/org/apache/servicecomb/common/rest/codec/param/TestHeaderProcessor.java
b/common/common-rest/src/test/java/org/apache/servicecomb/common/rest/codec/param/TestHeaderProcessor.java
index c3f07c582..4058f045e 100644
---
a/common/common-rest/src/test/java/org/apache/servicecomb/common/rest/codec/param/TestHeaderProcessor.java
+++
b/common/common-rest/src/test/java/org/apache/servicecomb/common/rest/codec/param/TestHeaderProcessor.java
@@ -65,6 +65,7 @@ public class TestHeaderProcessor {
if (javaType.isContainerType()) {
headerParameter.type(ArrayProperty.TYPE);
+ headerParameter.setCollectionFormat("multi");
}
return new HeaderProcessor(headerParameter, javaType);
}
diff --git
a/common/common-rest/src/test/java/org/apache/servicecomb/common/rest/codec/param/TestRestClientRequestImpl.java
b/common/common-rest/src/test/java/org/apache/servicecomb/common/rest/codec/param/TestRestClientRequestImpl.java
index be86969fd..70e3f4bdd 100644
---
a/common/common-rest/src/test/java/org/apache/servicecomb/common/rest/codec/param/TestRestClientRequestImpl.java
+++
b/common/common-rest/src/test/java/org/apache/servicecomb/common/rest/codec/param/TestRestClientRequestImpl.java
@@ -16,9 +16,9 @@
*/
package org.apache.servicecomb.common.rest.codec.param;
+import static org.assertj.core.api.Assertions.assertThat;
+
import java.util.Arrays;
-import java.util.HashMap;
-import java.util.Map;
import java.util.UUID;
import javax.servlet.http.Part;
@@ -31,9 +31,6 @@ import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
-import org.junit.jupiter.api.condition.EnabledForJreRange;
-import org.junit.jupiter.api.condition.EnabledOnJre;
-import org.junit.jupiter.api.condition.JRE;
import org.mockito.MockedStatic;
import org.mockito.Mockito;
@@ -43,7 +40,7 @@ import io.vertx.core.Context;
import io.vertx.core.MultiMap;
import io.vertx.core.buffer.Buffer;
import io.vertx.core.http.HttpClientRequest;
-import static org.assertj.core.api.Assertions.assertThat;
+import io.vertx.core.http.impl.headers.HeadersMultiMap;
public class TestRestClientRequestImpl {
private HttpClientRequest request;
@@ -74,13 +71,15 @@ public class TestRestClientRequestImpl {
public void testCookie() throws Exception {
final MultiMap map = MultiMap.caseInsensitiveMultiMap();
Mockito.doAnswer(invocation -> {
- map.add(io.vertx.core.http.HttpHeaders.COOKIE,
"sessionid=abcdefghijklmnopqrstuvwxyz; region=china-north; ");
- return null;
- }).when(request).putHeader(io.vertx.core.http.HttpHeaders.COOKIE,
"sessionid=abcdefghijklmnopqrstuvwxyz; region=china-north; ");
+ map.add(io.vertx.core.http.HttpHeaders.COOKIE,
"sessionid=abcdefghijklmnopqrstuvwxyz; region=china-north; ");
+ return null;
+ }).when(request)
+ .putHeader(io.vertx.core.http.HttpHeaders.COOKIE,
"sessionid=abcdefghijklmnopqrstuvwxyz; region=china-north; ");
Mockito.doAnswer(invocation -> {
- map.add(io.vertx.core.http.HttpHeaders.COOKIE,
"sessionid=abcdefghijklmnopqrstuvwxyz; region=china-north; ");
- return null;
- }).when(request).putHeader(io.vertx.core.http.HttpHeaders.COOKIE,
"region=china-north; sessionid=abcdefghijklmnopqrstuvwxyz; ");
+ map.add(io.vertx.core.http.HttpHeaders.COOKIE,
"sessionid=abcdefghijklmnopqrstuvwxyz; region=china-north; ");
+ return null;
+ }).when(request)
+ .putHeader(io.vertx.core.http.HttpHeaders.COOKIE, "region=china-north;
sessionid=abcdefghijklmnopqrstuvwxyz; ");
Mockito.when(request.headers()).thenReturn(map);
RestClientRequestImpl restClientRequest = new
RestClientRequestImpl(request, null, null);
@@ -149,44 +148,26 @@ public class TestRestClientRequestImpl {
}
@Test
- @EnabledOnJre(JRE.JAVA_8)
- public void doEndWithUploadForJre8() {
- Map<String, String> headers = new HashMap<>();
- Mockito.doAnswer(invocation -> {
- headers.put(HttpHeaders.CONTENT_TYPE, "multipart/form-data;
charset=UTF-8; boundary=boundarynull-null-null-null-null");
- return null;
- }).when(request).putHeader(HttpHeaders.CONTENT_TYPE, "multipart/form-data;
charset=UTF-8; boundary=boundarynull-null-null-null-null");
-
- UUID uuid = new UUID(0, 0);
- try (MockedStatic<UUID> mockedStatic = Mockito.mockStatic(UUID.class)) {
- mockedStatic.when(UUID::randomUUID).thenReturn(uuid);
- RestClientRequestImpl restClientRequest = new
RestClientRequestImpl(request, context, null);
- restClientRequest.attach("file", null);
- restClientRequest.doEndWithUpload();
-
- Assertions.assertEquals("multipart/form-data; charset=UTF-8;
boundary=boundarynull-null-null-null-null",
- headers.get(HttpHeaders.CONTENT_TYPE));
- }
- }
-
- @Test
- @EnabledForJreRange(min = JRE.JAVA_9)
- public void doEndWithUploadAfterJre8() {
- Map<String, String> headers = new HashMap<>();
+ public void testDoEndWithUpload() {
+ MultiMap headers = HeadersMultiMap.headers();
Mockito.doAnswer(invocation -> {
- headers.put(HttpHeaders.CONTENT_TYPE, "multipart/form-data;
charset=UTF-8; boundary=boundary00000000-0000-0000-0000-000000000000");
+ headers.add(HttpHeaders.CONTENT_TYPE,
+ "multipart/form-data; charset=UTF-8;
boundary=boundary00000000-0000-0000-0000-000000000000");
return null;
- }).when(request).putHeader(HttpHeaders.CONTENT_TYPE, "multipart/form-data;
charset=UTF-8; boundary=boundary00000000-0000-0000-0000-000000000000");
+ }).when(request).putHeader(HttpHeaders.CONTENT_TYPE,
+ "multipart/form-data; charset=UTF-8;
boundary=boundary00000000-0000-0000-0000-000000000000");
- UUID uuid = new UUID(0, 0);
+ UUID uuid = Mockito.mock(UUID.class);
+
Mockito.when(uuid.toString()).thenReturn("00000000-0000-0000-0000-000000000000");
try (MockedStatic<UUID> mockedStatic = Mockito.mockStatic(UUID.class)) {
mockedStatic.when(UUID::randomUUID).thenReturn(uuid);
RestClientRequestImpl restClientRequest = new
RestClientRequestImpl(request, context, null);
restClientRequest.attach("file", null);
restClientRequest.doEndWithUpload();
- Assertions.assertEquals("multipart/form-data; charset=UTF-8;
boundary=boundary00000000-0000-0000-0000-000000000000",
- headers.get(HttpHeaders.CONTENT_TYPE));
+ Assertions.assertEquals(
+ "multipart/form-data; charset=UTF-8;
boundary=boundary00000000-0000-0000-0000-000000000000",
+ headers.get(HttpHeaders.CONTENT_TYPE));
}
}
}
diff --git
a/demo/demo-schema/src/main/java/org/apache/servicecomb/demo/api/IHeaderParamWithListSchema.java
b/demo/demo-schema/src/main/java/org/apache/servicecomb/demo/api/IHeaderParamWithListSchema.java
new file mode 100644
index 000000000..0f0b5b5a9
--- /dev/null
+++
b/demo/demo-schema/src/main/java/org/apache/servicecomb/demo/api/IHeaderParamWithListSchema.java
@@ -0,0 +1,64 @@
+/*
+ * 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.demo.api;
+
+import java.util.List;
+
+import javax.ws.rs.GET;
+import javax.ws.rs.HeaderParam;
+import javax.ws.rs.Path;
+
+import io.swagger.annotations.ApiParam;
+
+@Path("/headerList")
+public interface IHeaderParamWithListSchema {
+ @Path("headerListDefault")
+ @GET
+ String headerListDefault(
+ @HeaderParam("headerList") List<String> headerList);
+
+ @Path("headerListCSV")
+ @GET
+ String headerListCSV(
+ @ApiParam(collectionFormat = "csv") @HeaderParam("headerList")
+ List<String> headerList);
+
+ @Path("headerListMULTI")
+ @GET
+ String headerListMULTI(
+ @ApiParam(collectionFormat = "multi") @HeaderParam("headerList")
+ List<String> headerList);
+
+ @Path("headerListSSV")
+ @GET
+ String headerListSSV(
+ @ApiParam(collectionFormat = "ssv") @HeaderParam("headerList")
+ List<String> headerList);
+
+ @Path("headerListPIPES")
+ @GET
+ String headerListPIPES(
+ @ApiParam(collectionFormat = "pipes") @HeaderParam("headerList")
+ List<String> headerList);
+
+ @Path("headerListTSV")
+ @GET
+ String headerListTSV(
+ @ApiParam(collectionFormat = "tsv") @HeaderParam("headerList")
+ List<String> headerList);
+}
diff --git
a/demo/demo-zeroconfig-schemadiscovery-registry/demo-zeroconfig-schemadiscovery-registry-client/src/main/java/org/apache/servicecomb/demo/zeroconfig/client/ConsumerHeaderParamWithListSchema.java
b/demo/demo-zeroconfig-schemadiscovery-registry/demo-zeroconfig-schemadiscovery-registry-client/src/main/java/org/apache/servicecomb/demo/zeroconfig/client/ConsumerHeaderParamWithListSchema.java
new file mode 100644
index 000000000..4b759246e
--- /dev/null
+++
b/demo/demo-zeroconfig-schemadiscovery-registry/demo-zeroconfig-schemadiscovery-registry-client/src/main/java/org/apache/servicecomb/demo/zeroconfig/client/ConsumerHeaderParamWithListSchema.java
@@ -0,0 +1,61 @@
+/*
+ * 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.demo.zeroconfig.client;
+
+import java.util.List;
+
+import org.apache.servicecomb.demo.api.IHeaderParamWithListSchema;
+import org.apache.servicecomb.provider.pojo.RpcReference;
+import org.apache.servicecomb.provider.rest.common.RestSchema;
+
+@RestSchema(schemaId = "ConsumerHeaderParamWithListSchema", schemaInterface =
IHeaderParamWithListSchema.class)
+public class ConsumerHeaderParamWithListSchema implements
IHeaderParamWithListSchema {
+ @RpcReference(microserviceName =
"demo-zeroconfig-schemadiscovery-registry-server",
+ schemaId = "HeaderParamWithListSchema")
+ private IHeaderParamWithListSchema provider;
+
+ @Override
+ public String headerListDefault(List<String> headerList) {
+ return provider.headerListDefault(headerList);
+ }
+
+ @Override
+ public String headerListCSV(List<String> headerList) {
+ return provider.headerListCSV(headerList);
+ }
+
+ @Override
+ public String headerListMULTI(List<String> headerList) {
+ return provider.headerListMULTI(headerList);
+ }
+
+ @Override
+ public String headerListSSV(List<String> headerList) {
+ return provider.headerListSSV(headerList);
+ }
+
+ @Override
+ public String headerListPIPES(List<String> headerList) {
+ return provider.headerListPIPES(headerList);
+ }
+
+ @Override
+ public String headerListTSV(List<String> headerList) {
+ return provider.headerListTSV(headerList);
+ }
+}
diff --git
a/demo/demo-zeroconfig-schemadiscovery-registry/demo-zeroconfig-schemadiscovery-registry-edge/src/main/resources/application.yml
b/demo/demo-zeroconfig-schemadiscovery-registry/demo-zeroconfig-schemadiscovery-registry-edge/src/main/resources/application.yml
index 685fd5937..8f327cbef 100644
---
a/demo/demo-zeroconfig-schemadiscovery-registry/demo-zeroconfig-schemadiscovery-registry-edge/src/main/resources/application.yml
+++
b/demo/demo-zeroconfig-schemadiscovery-registry/demo-zeroconfig-schemadiscovery-registry-edge/src/main/resources/application.yml
@@ -45,6 +45,16 @@ servicecomb:
path: "/register/url/prefix/.*"
microserviceName: demo-zeroconfig-schemadiscovery-registry-client
versionRule: 0+
+ client-2:
+ prefixSegmentCount: 0
+ path: "/headerList/.*"
+ microserviceName: demo-zeroconfig-schemadiscovery-registry-client
+ versionRule: 0+
+
+ references:
+ transport:
+
demo-zeroconfig-schemadiscovery-registry-client.ClientServerEndpoint.contextMapper:
rest
+
context:
headerContextMapper: |
gatewayHeader: context-gateway-header
diff --git
a/demo/demo-zeroconfig-schemadiscovery-registry/demo-zeroconfig-schemadiscovery-registry-server/src/main/java/org/apache/servicecomb/demo/zeroconfig/server/HeaderParamWithListSchema.java
b/demo/demo-zeroconfig-schemadiscovery-registry/demo-zeroconfig-schemadiscovery-registry-server/src/main/java/org/apache/servicecomb/demo/zeroconfig/server/HeaderParamWithListSchema.java
new file mode 100644
index 000000000..f51852fb8
--- /dev/null
+++
b/demo/demo-zeroconfig-schemadiscovery-registry/demo-zeroconfig-schemadiscovery-registry-server/src/main/java/org/apache/servicecomb/demo/zeroconfig/server/HeaderParamWithListSchema.java
@@ -0,0 +1,55 @@
+/*
+ * 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.demo.zeroconfig.server;
+
+import java.util.List;
+
+import org.apache.servicecomb.demo.api.IHeaderParamWithListSchema;
+import org.apache.servicecomb.provider.rest.common.RestSchema;
+
+@RestSchema(schemaId = "HeaderParamWithListSchema", schemaInterface =
IHeaderParamWithListSchema.class)
+public class HeaderParamWithListSchema implements IHeaderParamWithListSchema {
+ @Override
+ public String headerListDefault(List<String> headerList) {
+ return headerList == null ? "null" : headerList.size() + ":" + headerList;
+ }
+
+ @Override
+ public String headerListCSV(List<String> headerList) {
+ return headerList == null ? "null" : headerList.size() + ":" + headerList;
+ }
+
+ @Override
+ public String headerListMULTI(List<String> headerList) {
+ return headerList == null ? "null" : headerList.size() + ":" + headerList;
+ }
+
+ @Override
+ public String headerListSSV(List<String> headerList) {
+ return headerList == null ? "null" : headerList.size() + ":" + headerList;
+ }
+
+ @Override
+ public String headerListPIPES(List<String> headerList) {
+ return headerList == null ? "null" : headerList.size() + ":" + headerList;
+ }
+
+ @Override
+ public String headerListTSV(List<String> headerList) {
+ return headerList == null ? "null" : headerList.size() + ":" + headerList;
+ }
+}
diff --git
a/demo/demo-zeroconfig-schemadiscovery-registry/demo-zeroconfig-schemadiscovery-registry-tests/src/main/java/org/apache/servicecomb/demo/zeroconfig/tests/HeaderParamWithListSchemaIT.java
b/demo/demo-zeroconfig-schemadiscovery-registry/demo-zeroconfig-schemadiscovery-registry-tests/src/main/java/org/apache/servicecomb/demo/zeroconfig/tests/HeaderParamWithListSchemaIT.java
new file mode 100644
index 000000000..37bab8df0
--- /dev/null
+++
b/demo/demo-zeroconfig-schemadiscovery-registry/demo-zeroconfig-schemadiscovery-registry-tests/src/main/java/org/apache/servicecomb/demo/zeroconfig/tests/HeaderParamWithListSchemaIT.java
@@ -0,0 +1,108 @@
+/*
+ * 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.demo.zeroconfig.tests;
+
+import org.apache.servicecomb.demo.CategorizedTestCase;
+import org.apache.servicecomb.demo.TestMgr;
+import org.springframework.http.HttpEntity;
+import org.springframework.http.HttpHeaders;
+import org.springframework.http.HttpMethod;
+import org.springframework.stereotype.Component;
+import org.springframework.util.MultiValueMap;
+import org.springframework.web.client.RestOperations;
+import org.springframework.web.client.RestTemplate;
+
+@Component
+public class HeaderParamWithListSchemaIT implements CategorizedTestCase {
+ private static final String GATEWAY_URL = "http://localhost:8888";
+
+ RestOperations template = new RestTemplate();
+
+ @Override
+ public void testRestTransport() throws Exception {
+ testHeaderListDefault();
+ testHeaderListMulti();
+ testHeaderListCSV();
+ testHeaderListSSV();
+ testHeaderListTSV();
+ testHeaderListPipes();
+ }
+
+ // default to csv, this is different from Open API 3.0 which default to none.
+ private void testHeaderListDefault() {
+ MultiValueMap<String, String> headers = new HttpHeaders();
+ headers.add("headerList", "a,b,c");
+ HttpEntity<Void> entity = new HttpEntity<>(headers);
+ String result = template
+ .exchange(GATEWAY_URL + "/headerList/headerListDefault",
HttpMethod.GET, entity, String.class).getBody();
+ TestMgr.check("\"3:[a, b, c]\"", result);
+ }
+
+ private void testHeaderListPipes() {
+ MultiValueMap<String, String> headers = new HttpHeaders();
+ headers.add("headerList", "a|b|c");
+ HttpEntity<Void> entity = new HttpEntity<>(headers);
+ String result = template
+ .exchange(GATEWAY_URL + "/headerList/headerListPIPES", HttpMethod.GET,
entity, String.class).getBody();
+ TestMgr.check("\"3:[a, b, c]\"", result);
+ }
+
+ private void testHeaderListTSV() {
+ MultiValueMap<String, String> headers = new HttpHeaders();
+ headers.add("headerList", "a\tb\tc");
+ HttpEntity<Void> entity = new HttpEntity<>(headers);
+ String result = template
+ .exchange(GATEWAY_URL + "/headerList/headerListTSV", HttpMethod.GET,
entity, String.class).getBody();
+ TestMgr.check("\"3:[a, b, c]\"", result);
+ }
+
+ private void testHeaderListSSV() {
+ MultiValueMap<String, String> headers = new HttpHeaders();
+ headers.add("headerList", "a b c");
+ HttpEntity<Void> entity = new HttpEntity<>(headers);
+ String result = template
+ .exchange(GATEWAY_URL + "/headerList/headerListSSV", HttpMethod.GET,
entity, String.class).getBody();
+ TestMgr.check("\"3:[a, b, c]\"", result);
+ }
+
+ private void testHeaderListCSV() {
+ MultiValueMap<String, String> headers = new HttpHeaders();
+ headers.add("headerList", "a,b,c");
+ HttpEntity<Void> entity = new HttpEntity<>(headers);
+ String result = template
+ .exchange(GATEWAY_URL + "/headerList/headerListCSV", HttpMethod.GET,
entity, String.class).getBody();
+ TestMgr.check("\"3:[a, b, c]\"", result);
+
+ headers.add("headerList", "a, b, c");
+ entity = new HttpEntity<>(headers);
+ result = template
+ .exchange(GATEWAY_URL + "/headerList/headerListCSV", HttpMethod.GET,
entity, String.class).getBody();
+ TestMgr.check("\"3:[a, b, c]\"", result);
+ }
+
+ private void testHeaderListMulti() {
+ MultiValueMap<String, String> headers = new HttpHeaders();
+ headers.add("headerList", "a");
+ headers.add("headerList", "b");
+ headers.add("headerList", "c");
+ HttpEntity<Void> entity = new HttpEntity<>(headers);
+ String result = template
+ .exchange(GATEWAY_URL + "/headerList/headerListMULTI", HttpMethod.GET,
entity, String.class).getBody();
+ TestMgr.check("\"3:[a, b, c]\"", result);
+ }
+}
diff --git
a/demo/demo-zeroconfig-schemadiscovery-registry/demo-zeroconfig-schemadiscovery-registry-tests/src/main/java/org/apache/servicecomb/demo/zeroconfig/tests/ServerTest.java
b/demo/demo-zeroconfig-schemadiscovery-registry/demo-zeroconfig-schemadiscovery-registry-tests/src/main/java/org/apache/servicecomb/demo/zeroconfig/tests/ServerTest.java
index aaf8233df..363496a05 100644
---
a/demo/demo-zeroconfig-schemadiscovery-registry/demo-zeroconfig-schemadiscovery-registry-tests/src/main/java/org/apache/servicecomb/demo/zeroconfig/tests/ServerTest.java
+++
b/demo/demo-zeroconfig-schemadiscovery-registry/demo-zeroconfig-schemadiscovery-registry-tests/src/main/java/org/apache/servicecomb/demo/zeroconfig/tests/ServerTest.java
@@ -59,8 +59,11 @@ public class ServerTest implements CategorizedTestCase {
RequestEntity<Void> requestEntity = new RequestEntity<>(headers,
HttpMethod.GET,
new
URI("cse://demo-zeroconfig-schemadiscovery-registry-edge/register/url/prefix/contextMapper?clientQuery=v3&"
+ "gatewayQuery=v4"));
+ // test two times to check different transport(only use rest)
ResponseEntity<String> response = template.exchange(requestEntity,
String.class);
TestMgr.check(response.getBody(), "success");
+ response = template.exchange(requestEntity, String.class);
+ TestMgr.check(response.getBody(), "success");
}
@SuppressWarnings("unchecked")