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 2019/06/29 01:32:43 UTC

[servicecomb-java-chassis] 01/02: [SCB-1328][WIP][WEAK] restore old Converter code, and replace all dynamic class to Object.class

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

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

commit 875ae6e8349b52928b2209ffc17be8f704d5336c
Author: wujimin <wu...@huawei.com>
AuthorDate: Fri Jun 28 00:49:43 2019 +0800

    [SCB-1328][WIP][WEAK] restore old Converter code, and replace all dynamic class to Object.class
---
 .../swagger/converter/AbstractConverter.java       |  55 ++++++
 .../servicecomb/swagger/converter/Converter.java   |  33 ++++
 .../swagger/converter/ConverterMgr.java            | 171 ++++++++++++++++++
 .../converter/model/AbstractModelConverter.java    |  30 ++++
 .../converter/model/ArrayModelConverter.java       |  39 ++++
 .../converter/model/ModelImplConverter.java        |  48 +++++
 .../swagger/converter/model/RefModelConverter.java |  30 ++++
 .../property/AbstractPropertyConverter.java        |  30 ++++
 .../converter/property/ArrayPropertyConverter.java |  51 ++++++
 .../converter/property/MapPropertyConverter.java   |  43 +++++
 .../property/ObjectPropertyConverter.java          |  30 ++++
 .../converter/property/RefPropertyConverter.java   |  30 ++++
 .../property/StringPropertyConverter.java          |  50 ++++++
 .../property/SwaggerParamCollectionFormat.java     | 102 +++++++++++
 .../swagger/extend/ModelResolverExt.java           |   8 +-
 .../property/SwaggerParamCollectionFormatTest.java | 200 +++++++++++++++++++++
 16 files changed, 944 insertions(+), 6 deletions(-)

diff --git a/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/converter/AbstractConverter.java b/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/converter/AbstractConverter.java
new file mode 100644
index 0000000..90ad109
--- /dev/null
+++ b/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/converter/AbstractConverter.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.swagger.converter;
+
+import java.util.Map;
+
+import org.apache.commons.lang3.StringUtils;
+import org.apache.servicecomb.swagger.SwaggerUtils;
+
+import com.fasterxml.jackson.databind.JavaType;
+import com.fasterxml.jackson.databind.type.TypeFactory;
+
+import io.swagger.models.Swagger;
+
+public abstract class AbstractConverter implements Converter {
+  protected abstract Map<String, Object> findVendorExtensions(Object def);
+
+  protected abstract JavaType doConvert(Swagger swagger, Object def);
+
+  protected JavaType convertRef(Swagger swagger, String ref) {
+    Object def = swagger.getDefinitions().get(ref);
+    return ConverterMgr.findJavaType(swagger, def);
+  }
+
+  @Override
+  public JavaType convert(Swagger swagger, Object def) {
+    Map<String, Object> vendorExtensions = findVendorExtensions(def);
+    String canonical = SwaggerUtils.getClassName(vendorExtensions);
+    if (StringUtils.isEmpty(canonical)) {
+      return doConvert(swagger, def);
+    }
+
+    try {
+      return TypeFactory.defaultInstance().constructFromCanonical(canonical);
+    } catch (Throwable e) {
+      // type not exist
+      return OBJECT_JAVA_TYPE;
+    }
+  }
+}
diff --git a/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/converter/Converter.java b/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/converter/Converter.java
new file mode 100644
index 0000000..94d61d0
--- /dev/null
+++ b/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/converter/Converter.java
@@ -0,0 +1,33 @@
+/*
+ * 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.swagger.converter;
+
+import com.fasterxml.jackson.databind.JavaType;
+import com.fasterxml.jackson.databind.type.TypeFactory;
+
+import io.swagger.models.Swagger;
+
+public interface Converter {
+  static final JavaType OBJECT_JAVA_TYPE = TypeFactory.defaultInstance().constructType(Object.class);
+
+  static final JavaType STRING_JAVA_TYPE = TypeFactory.defaultInstance().constructType(String.class);
+
+  // def can be property or model
+  // def can not be null
+  JavaType convert(Swagger swagger, Object def);
+}
diff --git a/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/converter/ConverterMgr.java b/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/converter/ConverterMgr.java
new file mode 100644
index 0000000..0d96aed
--- /dev/null
+++ b/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/converter/ConverterMgr.java
@@ -0,0 +1,171 @@
+/*
+ * 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.swagger.converter;
+
+import java.math.BigDecimal;
+import java.time.LocalDate;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Map.Entry;
+
+import javax.servlet.http.Part;
+
+import org.apache.servicecomb.swagger.converter.model.ArrayModelConverter;
+import org.apache.servicecomb.swagger.converter.model.ModelImplConverter;
+import org.apache.servicecomb.swagger.converter.model.RefModelConverter;
+import org.apache.servicecomb.swagger.converter.property.ArrayPropertyConverter;
+import org.apache.servicecomb.swagger.converter.property.MapPropertyConverter;
+import org.apache.servicecomb.swagger.converter.property.ObjectPropertyConverter;
+import org.apache.servicecomb.swagger.converter.property.RefPropertyConverter;
+import org.apache.servicecomb.swagger.converter.property.StringPropertyConverter;
+import org.apache.servicecomb.swagger.extend.property.ByteProperty;
+import org.apache.servicecomb.swagger.extend.property.ShortProperty;
+
+import com.fasterxml.jackson.databind.JavaType;
+import com.fasterxml.jackson.databind.type.TypeFactory;
+
+import io.swagger.models.ArrayModel;
+import io.swagger.models.ModelImpl;
+import io.swagger.models.RefModel;
+import io.swagger.models.Swagger;
+import io.swagger.models.properties.ArrayProperty;
+import io.swagger.models.properties.BaseIntegerProperty;
+import io.swagger.models.properties.BooleanProperty;
+import io.swagger.models.properties.ByteArrayProperty;
+import io.swagger.models.properties.DateProperty;
+import io.swagger.models.properties.DateTimeProperty;
+import io.swagger.models.properties.DecimalProperty;
+import io.swagger.models.properties.DoubleProperty;
+import io.swagger.models.properties.FileProperty;
+import io.swagger.models.properties.FloatProperty;
+import io.swagger.models.properties.IntegerProperty;
+import io.swagger.models.properties.LongProperty;
+import io.swagger.models.properties.MapProperty;
+import io.swagger.models.properties.ObjectProperty;
+import io.swagger.models.properties.Property;
+import io.swagger.models.properties.RefProperty;
+import io.swagger.models.properties.StringProperty;
+
+public final class ConverterMgr {
+  private static final JavaType VOID_JAVA_TYPE = TypeFactory.defaultInstance().constructType(Void.class);
+
+  private static final Map<Class<? extends Property>, JavaType> PROPERTY_MAP = new HashMap<>();
+
+  // key is "type.format" of standard swagger data type
+  // value is related java class
+  private static final Map<String, JavaType> TYPE_FORMAT_MAP = new HashMap<>();
+
+  private static Map<Class<?>, Converter> converterMap = new HashMap<>();
+
+  static {
+    initPropertyMap();
+    initTypeFormatMap();
+    initConverters();
+  }
+
+  private static String genTypeFormatKey(String type, String format) {
+    return type + ":" + format;
+  }
+
+  private ConverterMgr() {
+
+  }
+
+  private static void initTypeFormatMap() {
+    try {
+      for (Entry<Class<? extends Property>, JavaType> entry : PROPERTY_MAP.entrySet()) {
+        Property property = entry.getKey().newInstance();
+        String key = genTypeFormatKey(property.getType(), property.getFormat());
+        TYPE_FORMAT_MAP.put(key, entry.getValue());
+      }
+    } catch (Throwable e) {
+      throw new Error(e);
+    }
+  }
+
+  private static void initPropertyMap() {
+    PROPERTY_MAP.put(BooleanProperty.class, TypeFactory.defaultInstance().constructType(Boolean.class));
+
+    PROPERTY_MAP.put(FloatProperty.class, TypeFactory.defaultInstance().constructType(Float.class));
+    PROPERTY_MAP.put(DoubleProperty.class, TypeFactory.defaultInstance().constructType(Double.class));
+    PROPERTY_MAP.put(DecimalProperty.class, TypeFactory.defaultInstance().constructType(BigDecimal.class));
+
+    PROPERTY_MAP.put(ByteProperty.class, TypeFactory.defaultInstance().constructType(Byte.class));
+    PROPERTY_MAP.put(ShortProperty.class, TypeFactory.defaultInstance().constructType(Short.class));
+    PROPERTY_MAP.put(IntegerProperty.class, TypeFactory.defaultInstance().constructType(Integer.class));
+    PROPERTY_MAP.put(BaseIntegerProperty.class, TypeFactory.defaultInstance().constructType(Integer.class));
+    PROPERTY_MAP.put(LongProperty.class, TypeFactory.defaultInstance().constructType(Long.class));
+
+    // stringProperty include enum scenes, not always be string type
+    // if convert by StringPropertyConverter, can support enum scenes
+    PROPERTY_MAP.put(StringProperty.class, TypeFactory.defaultInstance().constructType(String.class));
+
+    PROPERTY_MAP.put(DateProperty.class, TypeFactory.defaultInstance().constructType(LocalDate.class));
+    PROPERTY_MAP.put(DateTimeProperty.class, TypeFactory.defaultInstance().constructType(Date.class));
+
+    PROPERTY_MAP.put(ByteArrayProperty.class, TypeFactory.defaultInstance().constructType(byte[].class));
+
+    PROPERTY_MAP.put(FileProperty.class, TypeFactory.defaultInstance().constructType(Part.class));
+  }
+
+  private static void initConverters() {
+    // inner converters
+    for (Class<? extends Property> propertyCls : PROPERTY_MAP.keySet()) {
+      addInnerConverter(propertyCls);
+    }
+
+    converterMap.put(RefProperty.class, new RefPropertyConverter());
+    converterMap.put(ArrayProperty.class, new ArrayPropertyConverter());
+    converterMap.put(MapProperty.class, new MapPropertyConverter());
+    converterMap.put(StringProperty.class, new StringPropertyConverter());
+    converterMap.put(ObjectProperty.class, new ObjectPropertyConverter());
+
+    converterMap.put(ModelImpl.class, new ModelImplConverter());
+    converterMap.put(RefModel.class, new RefModelConverter());
+    converterMap.put(ArrayModel.class, new ArrayModelConverter());
+  }
+
+  private static void addInnerConverter(Class<? extends Property> propertyCls) {
+    JavaType javaType = PROPERTY_MAP.get(propertyCls);
+    if (javaType == null) {
+      throw new Error("not support inner property class: " + propertyCls.getName());
+    }
+
+    converterMap.put(propertyCls, (swagger, def) -> javaType);
+  }
+
+  public static JavaType findJavaType(String type, String format) {
+    String key = genTypeFormatKey(type, format);
+    return TYPE_FORMAT_MAP.get(key);
+  }
+
+  // def is null means void scene
+  // def can be model or property
+  public static JavaType findJavaType(Swagger swagger, Object def) {
+    if (def == null) {
+      return VOID_JAVA_TYPE;
+    }
+    Converter converter = converterMap.get(def.getClass());
+    if (converter == null) {
+      throw new Error("not support def type: " + def.getClass());
+    }
+
+    return converter.convert(swagger, def);
+  }
+}
diff --git a/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/converter/model/AbstractModelConverter.java b/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/converter/model/AbstractModelConverter.java
new file mode 100644
index 0000000..336f54f
--- /dev/null
+++ b/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/converter/model/AbstractModelConverter.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.swagger.converter.model;
+
+import java.util.Map;
+
+import org.apache.servicecomb.swagger.converter.AbstractConverter;
+
+import io.swagger.models.Model;
+
+public abstract class AbstractModelConverter extends AbstractConverter {
+  protected Map<String, Object> findVendorExtensions(Object def) {
+    return ((Model) def).getVendorExtensions();
+  }
+}
diff --git a/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/converter/model/ArrayModelConverter.java b/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/converter/model/ArrayModelConverter.java
new file mode 100644
index 0000000..0ef81bd
--- /dev/null
+++ b/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/converter/model/ArrayModelConverter.java
@@ -0,0 +1,39 @@
+/*
+ * 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.swagger.converter.model;
+
+import org.apache.servicecomb.swagger.converter.property.ArrayPropertyConverter;
+
+import com.fasterxml.jackson.databind.JavaType;
+
+import io.swagger.models.ArrayModel;
+import io.swagger.models.Swagger;
+
+public class ArrayModelConverter extends AbstractModelConverter {
+  @Override
+  public JavaType doConvert(Swagger swagger, Object model) {
+    ArrayModel arrayModel = (ArrayModel) model;
+
+    if (arrayModel.getItems() != null) {
+      return ArrayPropertyConverter.findJavaType(swagger, arrayModel.getItems(), false);
+    }
+
+    // don't know when will this happen.
+    throw new IllegalStateException("not support null array model items.");
+  }
+}
diff --git a/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/converter/model/ModelImplConverter.java b/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/converter/model/ModelImplConverter.java
new file mode 100644
index 0000000..9c0290b
--- /dev/null
+++ b/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/converter/model/ModelImplConverter.java
@@ -0,0 +1,48 @@
+/*
+ * 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.swagger.converter.model;
+
+import org.apache.servicecomb.swagger.converter.ConverterMgr;
+import org.apache.servicecomb.swagger.converter.property.MapPropertyConverter;
+
+import com.fasterxml.jackson.databind.JavaType;
+
+import io.swagger.models.ModelImpl;
+import io.swagger.models.Swagger;
+
+public class ModelImplConverter extends AbstractModelConverter {
+  @Override
+  public JavaType doConvert(Swagger swagger, Object model) {
+    ModelImpl modelImpl = (ModelImpl) model;
+
+    JavaType javaType = ConverterMgr.findJavaType(modelImpl.getType(), modelImpl.getFormat());
+    if (javaType != null) {
+      return javaType;
+    }
+
+    if (modelImpl.getReference() != null) {
+      return convertRef(swagger, modelImpl.getReference());
+    }
+
+    if (modelImpl.getAdditionalProperties() != null) {
+      return MapPropertyConverter.findJavaType(swagger, modelImpl.getAdditionalProperties());
+    }
+
+    return OBJECT_JAVA_TYPE;
+  }
+}
diff --git a/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/converter/model/RefModelConverter.java b/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/converter/model/RefModelConverter.java
new file mode 100644
index 0000000..d9e4169
--- /dev/null
+++ b/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/converter/model/RefModelConverter.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.swagger.converter.model;
+
+import com.fasterxml.jackson.databind.JavaType;
+
+import io.swagger.models.RefModel;
+import io.swagger.models.Swagger;
+
+public class RefModelConverter extends AbstractModelConverter {
+  @Override
+  public JavaType doConvert(Swagger swagger, Object refModel) {
+    return convertRef(swagger, ((RefModel) refModel).getSimpleRef());
+  }
+}
diff --git a/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/converter/property/AbstractPropertyConverter.java b/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/converter/property/AbstractPropertyConverter.java
new file mode 100644
index 0000000..0998fc3
--- /dev/null
+++ b/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/converter/property/AbstractPropertyConverter.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.swagger.converter.property;
+
+import java.util.Map;
+
+import org.apache.servicecomb.swagger.converter.AbstractConverter;
+
+import io.swagger.models.properties.Property;
+
+public abstract class AbstractPropertyConverter extends AbstractConverter {
+  protected Map<String, Object> findVendorExtensions(Object def) {
+    return ((Property) def).getVendorExtensions();
+  }
+}
diff --git a/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/converter/property/ArrayPropertyConverter.java b/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/converter/property/ArrayPropertyConverter.java
new file mode 100644
index 0000000..aab2ad5
--- /dev/null
+++ b/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/converter/property/ArrayPropertyConverter.java
@@ -0,0 +1,51 @@
+/*
+ * 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.swagger.converter.property;
+
+import java.util.Collection;
+import java.util.List;
+import java.util.Set;
+
+import org.apache.servicecomb.swagger.converter.ConverterMgr;
+
+import com.fasterxml.jackson.databind.JavaType;
+import com.fasterxml.jackson.databind.type.TypeFactory;
+
+import io.swagger.models.Swagger;
+import io.swagger.models.properties.ArrayProperty;
+import io.swagger.models.properties.Property;
+
+public class ArrayPropertyConverter extends AbstractPropertyConverter {
+  public static JavaType findJavaType(Swagger swagger, Property itemProperty, Boolean uniqueItems) {
+    JavaType itemJavaType = ConverterMgr.findJavaType(swagger, itemProperty);
+
+    @SuppressWarnings("rawtypes")
+    Class<? extends Collection> collectionClass = List.class;
+    if (Boolean.TRUE.equals(uniqueItems)) {
+      collectionClass = Set.class;
+    }
+    return TypeFactory.defaultInstance().constructCollectionType(collectionClass, itemJavaType);
+  }
+
+  @Override
+  public JavaType doConvert(Swagger swagger, Object property) {
+    ArrayProperty arrayProperty = (ArrayProperty) property;
+
+    return findJavaType(swagger, arrayProperty.getItems(), arrayProperty.getUniqueItems());
+  }
+}
diff --git a/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/converter/property/MapPropertyConverter.java b/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/converter/property/MapPropertyConverter.java
new file mode 100644
index 0000000..ee8baa0
--- /dev/null
+++ b/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/converter/property/MapPropertyConverter.java
@@ -0,0 +1,43 @@
+/*
+ * 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.swagger.converter.property;
+
+import java.util.Map;
+
+import org.apache.servicecomb.swagger.converter.ConverterMgr;
+
+import com.fasterxml.jackson.databind.JavaType;
+import com.fasterxml.jackson.databind.type.TypeFactory;
+
+import io.swagger.models.Swagger;
+import io.swagger.models.properties.MapProperty;
+import io.swagger.models.properties.Property;
+
+public class MapPropertyConverter extends AbstractPropertyConverter {
+  @Override
+  public JavaType doConvert(Swagger swagger, Object property) {
+    MapProperty mapProperty = (MapProperty) property;
+    Property valueProperty = mapProperty.getAdditionalProperties();
+    return findJavaType(swagger, valueProperty);
+  }
+
+  public static JavaType findJavaType(Swagger swagger, Property valueProperty) {
+    JavaType valueJavaType = ConverterMgr.findJavaType(swagger, valueProperty);
+    return TypeFactory.defaultInstance().constructMapType(Map.class, STRING_JAVA_TYPE, valueJavaType);
+  }
+}
diff --git a/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/converter/property/ObjectPropertyConverter.java b/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/converter/property/ObjectPropertyConverter.java
new file mode 100644
index 0000000..4a15b47
--- /dev/null
+++ b/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/converter/property/ObjectPropertyConverter.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.swagger.converter.property;
+
+import org.apache.servicecomb.swagger.converter.Converter;
+
+import com.fasterxml.jackson.databind.JavaType;
+
+import io.swagger.models.Swagger;
+
+public class ObjectPropertyConverter implements Converter {
+  @Override
+  public JavaType convert(Swagger swagger, Object def) {
+    return OBJECT_JAVA_TYPE;
+  }
+}
diff --git a/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/converter/property/RefPropertyConverter.java b/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/converter/property/RefPropertyConverter.java
new file mode 100644
index 0000000..0cb9287
--- /dev/null
+++ b/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/converter/property/RefPropertyConverter.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.swagger.converter.property;
+
+import com.fasterxml.jackson.databind.JavaType;
+
+import io.swagger.models.Swagger;
+import io.swagger.models.properties.RefProperty;
+
+public class RefPropertyConverter extends AbstractPropertyConverter {
+  @Override
+  public JavaType doConvert(Swagger swagger, Object refProperty) {
+    return convertRef(swagger, ((RefProperty) refProperty).getSimpleRef());
+  }
+}
diff --git a/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/converter/property/StringPropertyConverter.java b/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/converter/property/StringPropertyConverter.java
new file mode 100644
index 0000000..1f02155
--- /dev/null
+++ b/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/converter/property/StringPropertyConverter.java
@@ -0,0 +1,50 @@
+/*
+ * 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.swagger.converter.property;
+
+import java.util.List;
+
+import org.apache.servicecomb.swagger.converter.ConverterMgr;
+
+import com.fasterxml.jackson.databind.JavaType;
+
+import io.swagger.models.Swagger;
+import io.swagger.models.properties.StringProperty;
+
+public class StringPropertyConverter extends AbstractPropertyConverter {
+
+  public static boolean isEnum(StringProperty stringProperty) {
+    return isEnum(stringProperty.getEnum());
+  }
+
+  public static boolean isEnum(List<String> enums) {
+    return enums != null && !enums.isEmpty();
+  }
+
+  @Override
+  public JavaType doConvert(Swagger swagger, Object property) {
+    StringProperty stringProperty = (StringProperty) property;
+
+    List<String> enums = stringProperty.getEnum();
+    if (!isEnum(enums)) {
+      return ConverterMgr.findJavaType(stringProperty.getType(), stringProperty.getFormat());
+    }
+
+    return OBJECT_JAVA_TYPE;
+  }
+}
diff --git a/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/converter/property/SwaggerParamCollectionFormat.java b/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/converter/property/SwaggerParamCollectionFormat.java
new file mode 100644
index 0000000..3ae7aaa
--- /dev/null
+++ b/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/converter/property/SwaggerParamCollectionFormat.java
@@ -0,0 +1,102 @@
+/*
+ * 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.swagger.converter.property;
+
+import java.util.Collection;
+
+public enum SwaggerParamCollectionFormat {
+  CSV("csv", ","),
+  SSV("ssv", " "),
+  TSV("tsv", "\t"),
+  PIPES("pipes", "|") {
+    @Override
+    public String[] splitParam(String rawParam) {
+      if (null == rawParam) {
+        return new String[0];
+      }
+      return rawParam.split("\\|", -1);
+    }
+  },
+  MULTI("multi", null) {
+    /**
+     * In fact, {@link SwaggerParamCollectionFormat#MULTI#splitParam(String)} of {@link SwaggerParamCollectionFormat#MULTI}
+     * should never be invoked. We just override this method to ensure it does not throw exception.
+     */
+    @Override
+    public String[] splitParam(String rawParam) {
+      if (null == rawParam) {
+        return new String[0];
+      }
+      return new String[] {rawParam};
+    }
+  };
+
+  final private String collectionFormat;
+
+  final private String separator;
+
+  SwaggerParamCollectionFormat(String collectionFormat, String separator) {
+    this.collectionFormat = collectionFormat;
+    this.separator = separator;
+  }
+
+  public String getCollectionFormat() {
+    return collectionFormat;
+  }
+
+  public String getSeparator() {
+    return separator;
+  }
+
+  public String[] splitParam(String rawParam) {
+    if (null == rawParam) {
+      return new String[0];
+    }
+    return rawParam.split(separator, -1);
+  }
+
+  /**
+   * Join params with {@link #separator}.
+   * Null element will be ignored since {@code null} cannot be described in query array param.
+   *
+   * @return joined params, or return {@code null} if {@code params} is null or all elements of {@code params} are null.
+   */
+  public String joinParam(Collection<?> params) {
+    if (null == params || params.isEmpty()) {
+      return null;
+    }
+
+    StringBuilder paramBuilder = new StringBuilder();
+    int nullCount = 0;
+    for (Object param : params) {
+      if (param == null) {
+        nullCount++;
+        continue;
+      }
+
+      paramBuilder.append(param).append(separator);
+    }
+    if (nullCount == params.size()) {
+      return null;
+    }
+
+    paramBuilder.setLength(paramBuilder.length() - 1);
+
+    return paramBuilder.toString();
+  }
+}
diff --git a/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/extend/ModelResolverExt.java b/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/extend/ModelResolverExt.java
index 95bc749..aa89b8c 100644
--- a/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/extend/ModelResolverExt.java
+++ b/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/extend/ModelResolverExt.java
@@ -23,13 +23,13 @@ import java.lang.reflect.Type;
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.Iterator;
-import java.util.List;
 import java.util.Map;
 import java.util.Set;
 
 import org.apache.commons.lang3.StringUtils;
 import org.apache.servicecomb.foundation.common.exceptions.ServiceCombException;
 import org.apache.servicecomb.foundation.common.utils.SPIServiceUtils;
+import org.apache.servicecomb.swagger.converter.property.StringPropertyConverter;
 import org.apache.servicecomb.swagger.extend.module.EnumModuleExt;
 import org.apache.servicecomb.swagger.extend.property.creator.ByteArrayPropertyCreator;
 import org.apache.servicecomb.swagger.extend.property.creator.BytePropertyCreator;
@@ -157,14 +157,10 @@ public class ModelResolverExt extends ModelResolver {
 
     Property property = super.resolveProperty(propType, context, annotations, next);
     if (StringProperty.class.isInstance(property)) {
-      if (isEnum(((StringProperty) property).getEnum())) {
+      if (StringPropertyConverter.isEnum((StringProperty) property)) {
         setType(propType, property.getVendorExtensions());
       }
     }
     return property;
   }
-
-  private boolean isEnum(List<String> enums) {
-    return enums != null && !enums.isEmpty();
-  }
 }
diff --git a/swagger/swagger-generator/generator-core/src/test/java/org/apache/servicecomb/swagger/converter/property/SwaggerParamCollectionFormatTest.java b/swagger/swagger-generator/generator-core/src/test/java/org/apache/servicecomb/swagger/converter/property/SwaggerParamCollectionFormatTest.java
new file mode 100644
index 0000000..5b42cd5
--- /dev/null
+++ b/swagger/swagger-generator/generator-core/src/test/java/org/apache/servicecomb/swagger/converter/property/SwaggerParamCollectionFormatTest.java
@@ -0,0 +1,200 @@
+/*
+ * 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.swagger.converter.property;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+
+import org.hamcrest.Matchers;
+import org.junit.Assert;
+import org.junit.Test;
+
+public class SwaggerParamCollectionFormatTest {
+  @Test
+  public void splitParamNormal() {
+    Assert.assertThat(SwaggerParamCollectionFormat.CSV.splitParam("a,b,c"),
+        Matchers.arrayContaining("a", "b", "c"));
+    Assert.assertThat(SwaggerParamCollectionFormat.SSV.splitParam("10 11 12"),
+        Matchers.arrayContaining("10", "11", "12"));
+    Assert.assertThat(SwaggerParamCollectionFormat.TSV.splitParam("a\tb\tc"),
+        Matchers.arrayContaining("a", "b", "c"));
+    Assert.assertThat(SwaggerParamCollectionFormat.PIPES.splitParam("a|b|c"),
+        Matchers.arrayContaining("a", "b", "c"));
+  }
+
+  @Test
+  public void splitParamMulti() {
+    Assert.assertThat(SwaggerParamCollectionFormat.MULTI.splitParam("a,b,c"),
+        Matchers.arrayContaining("a,b,c"));
+  }
+
+  @Test
+  public void splitParam_SingleElement() {
+    Assert.assertThat(SwaggerParamCollectionFormat.CSV.splitParam("a"),
+        Matchers.arrayContaining("a"));
+    Assert.assertThat(SwaggerParamCollectionFormat.SSV.splitParam("a"),
+        Matchers.arrayContaining("a"));
+    Assert.assertThat(SwaggerParamCollectionFormat.TSV.splitParam("a"),
+        Matchers.arrayContaining("a"));
+    Assert.assertThat(SwaggerParamCollectionFormat.PIPES.splitParam("a"),
+        Matchers.arrayContaining("a"));
+    Assert.assertThat(SwaggerParamCollectionFormat.MULTI.splitParam("a"),
+        Matchers.arrayContaining("a"));
+  }
+
+  @Test
+  public void splitParam_NullElement() {
+    Assert.assertThat(SwaggerParamCollectionFormat.CSV.splitParam(null),
+        Matchers.emptyArray());
+    Assert.assertThat(SwaggerParamCollectionFormat.SSV.splitParam(null),
+        Matchers.emptyArray());
+    Assert.assertThat(SwaggerParamCollectionFormat.TSV.splitParam(null),
+        Matchers.emptyArray());
+    Assert.assertThat(SwaggerParamCollectionFormat.PIPES.splitParam(null),
+        Matchers.emptyArray());
+    Assert.assertThat(SwaggerParamCollectionFormat.MULTI.splitParam(null),
+        Matchers.emptyArray());
+  }
+
+  @Test
+  public void splitParam_BlankElement() {
+    Assert.assertThat(SwaggerParamCollectionFormat.CSV.splitParam(""),
+        Matchers.arrayContaining(""));
+    Assert.assertThat(SwaggerParamCollectionFormat.SSV.splitParam(""),
+        Matchers.arrayContaining(""));
+    Assert.assertThat(SwaggerParamCollectionFormat.TSV.splitParam(""),
+        Matchers.arrayContaining(""));
+    Assert.assertThat(SwaggerParamCollectionFormat.PIPES.splitParam(""),
+        Matchers.arrayContaining(""));
+    Assert.assertThat(SwaggerParamCollectionFormat.MULTI.splitParam(""),
+        Matchers.arrayContaining(""));
+
+    Assert.assertThat(SwaggerParamCollectionFormat.CSV.splitParam("a,,b"),
+        Matchers.arrayContaining("a", "", "b"));
+    Assert.assertThat(SwaggerParamCollectionFormat.SSV.splitParam("a  b"),
+        Matchers.arrayContaining("a", "", "b"));
+    Assert.assertThat(SwaggerParamCollectionFormat.TSV.splitParam("a\t\tb"),
+        Matchers.arrayContaining("a", "", "b"));
+    Assert.assertThat(SwaggerParamCollectionFormat.PIPES.splitParam("a||b"),
+        Matchers.arrayContaining("a", "", "b"));
+
+    Assert.assertThat(SwaggerParamCollectionFormat.CSV.splitParam("a,,"),
+        Matchers.arrayContaining("a", "", ""));
+    Assert.assertThat(SwaggerParamCollectionFormat.SSV.splitParam("a  "),
+        Matchers.arrayContaining("a", "", ""));
+    Assert.assertThat(SwaggerParamCollectionFormat.TSV.splitParam("a\t\t"),
+        Matchers.arrayContaining("a", "", ""));
+    String[] actual = SwaggerParamCollectionFormat.PIPES.splitParam("a||");
+    Assert.assertThat(Arrays.toString(actual), actual,
+        Matchers.arrayContaining("a", "", ""));
+
+    Assert.assertThat(SwaggerParamCollectionFormat.CSV.splitParam(",,b"),
+        Matchers.arrayContaining("", "", "b"));
+    Assert.assertThat(SwaggerParamCollectionFormat.SSV.splitParam("  b"),
+        Matchers.arrayContaining("", "", "b"));
+    Assert.assertThat(SwaggerParamCollectionFormat.TSV.splitParam("\t\tb"),
+        Matchers.arrayContaining("", "", "b"));
+    Assert.assertThat(SwaggerParamCollectionFormat.PIPES.splitParam("||b"),
+        Matchers.arrayContaining("", "", "b"));
+  }
+
+  @Test
+  public void joinNormal() {
+    List<String> params = Arrays.asList("a", "b", "c");
+    assertEquals("a,b,c", SwaggerParamCollectionFormat.CSV.joinParam(params));
+    assertEquals("a b c", SwaggerParamCollectionFormat.SSV.joinParam(params));
+    assertEquals("a\tb\tc", SwaggerParamCollectionFormat.TSV.joinParam(params));
+    assertEquals("a|b|c", SwaggerParamCollectionFormat.PIPES.joinParam(params));
+  }
+
+  @Test
+  public void join_SingleElement() {
+    List<String> params = Collections.singletonList("a");
+    assertEquals("a", SwaggerParamCollectionFormat.CSV.joinParam(params));
+    assertEquals("a", SwaggerParamCollectionFormat.SSV.joinParam(params));
+    assertEquals("a", SwaggerParamCollectionFormat.TSV.joinParam(params));
+    assertEquals("a", SwaggerParamCollectionFormat.PIPES.joinParam(params));
+  }
+
+  @Test
+  public void join_EmptyArray() {
+    Assert.assertNull(SwaggerParamCollectionFormat.CSV.joinParam(Collections.EMPTY_LIST));
+  }
+
+  @Test
+  public void join_NullAndBlankElement() {
+    Assert.assertNull(SwaggerParamCollectionFormat.CSV.joinParam(Collections.singletonList(null)));
+
+    assertEquals("", SwaggerParamCollectionFormat.CSV.joinParam(Collections.singleton("")));
+    assertEquals("a,,b,c", SwaggerParamCollectionFormat.CSV.joinParam(Arrays.asList("a", "", "b", "c")));
+    assertEquals("a  b c", SwaggerParamCollectionFormat.SSV.joinParam(Arrays.asList("a", "", "b", "c")));
+    assertEquals("a\t\tb\tc", SwaggerParamCollectionFormat.TSV.joinParam(Arrays.asList("a", "", "b", "c")));
+    assertEquals("a||b|c", SwaggerParamCollectionFormat.PIPES.joinParam(Arrays.asList("a", "", "b", "c")));
+
+    assertEquals("a,b,,c",
+        SwaggerParamCollectionFormat.CSV
+            .joinParam(Arrays.asList(null, "a", null, "b", null, "", null, null, "c", null)));
+    assertEquals("a b  c",
+        SwaggerParamCollectionFormat.SSV
+            .joinParam(Arrays.asList(null, "a", null, "b", null, "", null, null, "c", null)));
+    assertEquals("a\tb\t\tc",
+        SwaggerParamCollectionFormat.TSV
+            .joinParam(Arrays.asList(null, "a", null, "b", null, "", null, null, "c", null)));
+    assertEquals("a|b||c",
+        SwaggerParamCollectionFormat.PIPES
+            .joinParam(Arrays.asList(null, "a", null, "b", null, "", null, null, "c", null)));
+
+    assertEquals("a,b,,c",
+        SwaggerParamCollectionFormat.CSV
+            .joinParam(Arrays.asList(null, null, "a", null, "b", null, "", null, null, "c", null, null)));
+    assertEquals("a b  c",
+        SwaggerParamCollectionFormat.SSV
+            .joinParam(Arrays.asList(null, null, "a", null, "b", null, "", null, null, "c", null, null)));
+    assertEquals("a\tb\t\tc",
+        SwaggerParamCollectionFormat.TSV
+            .joinParam(Arrays.asList(null, null, "a", null, "b", null, "", null, null, "c", null, null)));
+    assertEquals("a|b||c",
+        SwaggerParamCollectionFormat.PIPES
+            .joinParam(Arrays.asList(null, null, "a", null, "b", null, "", null, null, "c", null, null)));
+  }
+
+  @Test
+  public void join_NullArray() {
+    assertNull(SwaggerParamCollectionFormat.CSV.joinParam(null));
+  }
+
+  /**
+   * In fact, the {@link SwaggerParamCollectionFormat#joinParam(Collection)} of {@link SwaggerParamCollectionFormat#MULTI}
+   * should never be invoked.
+   * This test is just for ensuring the method does not throw exception.
+   */
+  @Test
+  public void joinMulti() {
+    SwaggerParamCollectionFormat.MULTI.joinParam(Arrays.asList("a", "b", "c"));
+    SwaggerParamCollectionFormat.MULTI.joinParam(Collections.singletonList("a"));
+    assertNull(SwaggerParamCollectionFormat.MULTI.joinParam(new ArrayList<String>()));
+    assertNull(SwaggerParamCollectionFormat.MULTI.joinParam(Collections.singleton(null)));
+    assertNull(SwaggerParamCollectionFormat.MULTI.joinParam(null));
+  }
+}
\ No newline at end of file