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 2018/08/01 09:53:40 UTC

[incubator-servicecomb-java-chassis] 04/06: [SCB-777] set custom deserializer for Part

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

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

commit 5c2aa29dd3125611e0f7a1914ac94b902050113a
Author: yaohaishi <ya...@huawei.com>
AuthorDate: Sat Jul 28 15:49:01 2018 +0800

    [SCB-777] set custom deserializer for Part
---
 .../foundation/common/utils/JsonUtils.java         |  29 ++--
 .../utils/json/JavaxServletPartDeserializer.java   |  34 +++++
 .../utils/json/JavaxServletPartSerializer.java     |  50 +++++++
 .../producer/ProducerBeanParamMapperTest.java      | 146 +++++++++++++++++++++
 4 files changed, 248 insertions(+), 11 deletions(-)

diff --git a/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/common/utils/JsonUtils.java b/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/common/utils/JsonUtils.java
index 75c7b36..52f9aa5 100644
--- a/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/common/utils/JsonUtils.java
+++ b/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/common/utils/JsonUtils.java
@@ -21,14 +21,18 @@ import java.io.IOException;
 import java.io.InputStream;
 import java.io.OutputStream;
 
-import com.fasterxml.jackson.core.JsonGenerationException;
-import com.fasterxml.jackson.core.JsonParseException;
+import javax.servlet.http.Part;
+
+import org.apache.servicecomb.foundation.common.utils.json.JavaxServletPartDeserializer;
+import org.apache.servicecomb.foundation.common.utils.json.JavaxServletPartSerializer;
+
 import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.core.Version;
 import com.fasterxml.jackson.databind.DeserializationFeature;
 import com.fasterxml.jackson.databind.JavaType;
-import com.fasterxml.jackson.databind.JsonMappingException;
 import com.fasterxml.jackson.databind.ObjectMapper;
 import com.fasterxml.jackson.databind.SerializationFeature;
+import com.fasterxml.jackson.databind.module.SimpleModule;
 
 public final class JsonUtils {
   public static final ObjectMapper OBJ_MAPPER;
@@ -37,23 +41,27 @@ public final class JsonUtils {
     OBJ_MAPPER = new ObjectMapper();
     OBJ_MAPPER.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);
     OBJ_MAPPER.disable(SerializationFeature.FAIL_ON_EMPTY_BEANS);
+
+    SimpleModule partDeserializeModule = new SimpleModule("partDeserializeModule",
+        new Version(0, 0, 1, null, "javax.servlet", "javax.servlet-api")
+    );
+    partDeserializeModule.addSerializer(Part.class, new JavaxServletPartSerializer());
+    partDeserializeModule.addDeserializer(Part.class, new JavaxServletPartDeserializer());
+    OBJ_MAPPER.registerModule(partDeserializeModule);
   }
 
   private JsonUtils() {
   }
 
-  public static <T> T readValue(byte[] src,
-      Class<T> valueType) throws JsonParseException, JsonMappingException, IOException {
+  public static <T> T readValue(byte[] src, Class<T> valueType) throws IOException {
     return OBJ_MAPPER.readValue(src, valueType);
   }
 
-  public static <T> T readValue(InputStream is,
-      Class<T> valueType) throws JsonParseException, JsonMappingException, IOException {
+  public static <T> T readValue(InputStream is, Class<T> valueType) throws IOException {
     return OBJ_MAPPER.readValue(is, valueType);
   }
 
-  public static <T> T readValue(InputStream is,
-      JavaType valueType) throws JsonParseException, JsonMappingException, IOException {
+  public static <T> T readValue(InputStream is, JavaType valueType) throws IOException {
     return OBJ_MAPPER.readValue(is, valueType);
   }
 
@@ -69,8 +77,7 @@ public final class JsonUtils {
     return OBJ_MAPPER.convertValue(fromValue, toValueType);
   }
 
-  public static void writeValue(OutputStream out,
-      Object value) throws JsonGenerationException, JsonMappingException, IOException {
+  public static void writeValue(OutputStream out, Object value) throws IOException {
     OBJ_MAPPER.writeValue(out, value);
   }
 }
diff --git a/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/common/utils/json/JavaxServletPartDeserializer.java b/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/common/utils/json/JavaxServletPartDeserializer.java
new file mode 100644
index 0000000..98b489f
--- /dev/null
+++ b/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/common/utils/json/JavaxServletPartDeserializer.java
@@ -0,0 +1,34 @@
+/*
+ * 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.foundation.common.utils.json;
+
+import java.io.IOException;
+
+import javax.servlet.http.Part;
+
+import com.fasterxml.jackson.core.JsonParser;
+import com.fasterxml.jackson.databind.DeserializationContext;
+import com.fasterxml.jackson.databind.JsonDeserializer;
+
+public class JavaxServletPartDeserializer extends JsonDeserializer<Part> {
+  @Override
+  public Part deserialize(JsonParser p, DeserializationContext ctxt) throws IOException {
+    final Object currentValue = p.getEmbeddedObject();
+    return (Part) currentValue;
+  }
+}
diff --git a/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/common/utils/json/JavaxServletPartSerializer.java b/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/common/utils/json/JavaxServletPartSerializer.java
new file mode 100644
index 0000000..34d247e
--- /dev/null
+++ b/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/common/utils/json/JavaxServletPartSerializer.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.foundation.common.utils.json;
+
+import java.io.IOException;
+
+import javax.servlet.http.Part;
+
+import com.fasterxml.jackson.core.JsonGenerator;
+import com.fasterxml.jackson.core.ObjectCodec;
+import com.fasterxml.jackson.databind.SerializerProvider;
+import com.fasterxml.jackson.databind.ser.std.StdSerializer;
+import com.fasterxml.jackson.databind.util.TokenBuffer;
+
+public class JavaxServletPartSerializer extends StdSerializer<Part> {
+  private static final long serialVersionUID = 348443113789878443L;
+
+  public JavaxServletPartSerializer() {
+    this(null);
+  }
+
+  protected JavaxServletPartSerializer(Class<Part> t) {
+    super(t);
+  }
+
+  @Override
+  public void serialize(Part value, JsonGenerator gen, SerializerProvider provider) throws IOException {
+    final ObjectCodec preservedCodec = ((TokenBuffer) gen).asParser().getCodec();
+    // set codec as null to avoid recursive dead loop
+    // JsonGenerator is instantiated for each serialization, so there should be no thread safe issue
+    gen.setCodec(null);
+    gen.writeObject(value);
+    gen.setCodec(preservedCodec);
+  }
+}
diff --git a/swagger/swagger-invocation/invocation-core/src/test/java/org/apache/servicecomb/swagger/invocation/arguments/producer/ProducerBeanParamMapperTest.java b/swagger/swagger-invocation/invocation-core/src/test/java/org/apache/servicecomb/swagger/invocation/arguments/producer/ProducerBeanParamMapperTest.java
new file mode 100644
index 0000000..81c8d35
--- /dev/null
+++ b/swagger/swagger-invocation/invocation-core/src/test/java/org/apache/servicecomb/swagger/invocation/arguments/producer/ProducerBeanParamMapperTest.java
@@ -0,0 +1,146 @@
+/*
+ * 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.invocation.arguments.producer;
+
+import java.util.Date;
+import java.util.HashMap;
+import java.util.Objects;
+
+import javax.servlet.http.Part;
+
+import org.apache.servicecomb.foundation.common.part.AbstractPart;
+import org.apache.servicecomb.swagger.invocation.SwaggerInvocation;
+import org.apache.servicecomb.swagger.invocation.arguments.ArgumentMapper;
+import org.apache.servicecomb.swagger.invocation.arguments.producer.ProducerSpringMVCQueryObjectMapperTest.RecursiveParam;
+import org.apache.servicecomb.swagger.invocation.arguments.producer.ProducerSpringMVCQueryObjectMapperTest.TestParam;
+import org.junit.Assert;
+import org.junit.Test;
+
+public class ProducerBeanParamMapperTest {
+
+  @Test
+  public void mapArgument() {
+    final HashMap<String, Integer> producerNameToSwaggerIndexMap = new HashMap<>();
+    producerNameToSwaggerIndexMap.put("name", 2);
+    producerNameToSwaggerIndexMap.put("age", 0);
+    ArgumentMapper argumentMapper = new ProducerBeanParamMapper(producerNameToSwaggerIndexMap, 0, TestParam.class);
+    SwaggerInvocation swaggerInvocation = new SwaggerInvocation();
+    swaggerInvocation.setSwaggerArguments(new Object[] {22, "abc", "nameTest"});
+
+    final Object[] producerArguments = new Object[1];
+    argumentMapper.mapArgument(swaggerInvocation, producerArguments);
+    Assert.assertEquals(producerArguments[0], new TestParam().setName("nameTest").setAge(22));
+  }
+
+  @Test
+  public void mapArgumentOnRecursiveParam() {
+    final HashMap<String, Integer> producerNameToSwaggerIndexMap = new HashMap<>();
+    producerNameToSwaggerIndexMap.put("num", 0);
+    producerNameToSwaggerIndexMap.put("str", 1);
+    producerNameToSwaggerIndexMap.put("date", 2);
+    ArgumentMapper argumentMapper = new ProducerBeanParamMapper(producerNameToSwaggerIndexMap, 1,
+        RecursiveParam.class);
+    SwaggerInvocation swaggerInvocation = new SwaggerInvocation();
+    final Date testDate = new Date();
+    swaggerInvocation.setSwaggerArguments(new Object[] {2, "str0_0", testDate});
+
+    final Object[] producerArguments = new Object[2];
+    argumentMapper.mapArgument(swaggerInvocation, producerArguments);
+    Assert.assertNull(producerArguments[0]);
+    Assert.assertEquals(producerArguments[1], new RecursiveParam().setNum(2).setStr("str0_0").setDate(testDate));
+  }
+
+  @Test
+  public void mapArgumentWithPart() {
+    final HashMap<String, Integer> producerNameToSwaggerIndexMap = new HashMap<>();
+    producerNameToSwaggerIndexMap.put("up", 0);
+    producerNameToSwaggerIndexMap.put("str", 2);
+    producerNameToSwaggerIndexMap.put("longValue", 3);
+    ArgumentMapper argumentMapper = new ProducerBeanParamMapper(producerNameToSwaggerIndexMap, 0,
+        TestParamWithPart.class);
+    SwaggerInvocation swaggerInvocation = new SwaggerInvocation();
+    final AbstractPart uploadedFile = new AbstractPart();
+    swaggerInvocation.setSwaggerArguments(new Object[] {uploadedFile, 123L, "testString", 12L});
+
+    final Object[] producerArguments = new Object[2];
+    argumentMapper.mapArgument(swaggerInvocation, producerArguments);
+    Assert.assertEquals(producerArguments[0], new TestParamWithPart("testString", 12L, uploadedFile));
+    Assert.assertSame(((TestParamWithPart) producerArguments[0]).getUp(), uploadedFile);
+    Assert.assertNull(producerArguments[1]);
+  }
+
+  static class TestParamWithPart {
+    private String str;
+
+    private long longValue;
+
+    private Part uploaded;
+
+    public TestParamWithPart() {
+    }
+
+    public TestParamWithPart(String str, long longValue, Part uploaded) {
+      this.str = str;
+      this.longValue = longValue;
+      this.uploaded = uploaded;
+    }
+
+    public String getStr() {
+      return str;
+    }
+
+    public void setStr(String str) {
+      this.str = str;
+    }
+
+    public long getLongValue() {
+      return longValue;
+    }
+
+    public void setLongValue(long longValue) {
+      this.longValue = longValue;
+    }
+
+    public Part getUp() {
+      return uploaded;
+    }
+
+    public void setUp(Part uploaded) {
+      this.uploaded = uploaded;
+    }
+
+    @Override
+    public boolean equals(Object o) {
+      if (this == o) {
+        return true;
+      }
+      if (o == null || getClass() != o.getClass()) {
+        return false;
+      }
+      TestParamWithPart that = (TestParamWithPart) o;
+      return longValue == that.longValue &&
+          Objects.equals(str, that.str) &&
+          Objects.equals(uploaded, that.uploaded);
+    }
+
+    @Override
+    public int hashCode() {
+      return Objects.hash(str, longValue, uploaded);
+    }
+  }
+}