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 <yaohai...@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); + } + } +}