diff --git a/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/engine/SwaggerProducerOperation.java b/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/engine/SwaggerProducerOperation.java index f174415b0b2..7f5b75e92c1 100644 --- a/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/engine/SwaggerProducerOperation.java +++ b/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/engine/SwaggerProducerOperation.java @@ -18,6 +18,7 @@ import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; +import java.lang.reflect.Type; import java.util.List; import java.util.concurrent.CompletableFuture; @@ -46,6 +47,11 @@ public class SwaggerProducerOperation { private SwaggerOperation swaggerOperation; + // swagger parameter types relate to producer + // because features of @BeanParam/query wrapper/rpc mode parameter wrapper + // types is not direct equals to producerMethod parameter types + private Type[] swaggerParameterTypes; + private ProducerArgumentsMapper argumentsMapper; private ProducerResponseMapper responseMapper; @@ -81,10 +87,22 @@ public void setProducerMethod(Method producerMethod) { this.producerMethod = producerMethod; } + public SwaggerOperation getSwaggerOperation() { + return swaggerOperation; + } + public void setSwaggerOperation(SwaggerOperation swaggerOperation) { this.swaggerOperation = swaggerOperation; } + public Type[] getSwaggerParameterTypes() { + return swaggerParameterTypes; + } + + public void setSwaggerParameterTypes(Type[] swaggerParameterTypes) { + this.swaggerParameterTypes = swaggerParameterTypes; + } + public ProducerArgumentsMapper getArgumentsMapper() { return argumentsMapper; } diff --git a/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/invocation/arguments/AbstractArgumentsMapperCreator.java b/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/invocation/arguments/AbstractArgumentsMapperCreator.java index ba5c04fb53a..f8b24f01ee0 100644 --- a/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/invocation/arguments/AbstractArgumentsMapperCreator.java +++ b/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/invocation/arguments/AbstractArgumentsMapperCreator.java @@ -106,6 +106,8 @@ public abstract class AbstractArgumentsMapperCreator { // body index in swagger parameters protected int swaggerBodyIdx; + protected BodyParameter bodyParameter; + protected Map swaggerBodyProperties; public AbstractArgumentsMapperCreator(SerializationConfig serializationConfig, @@ -118,7 +120,7 @@ public AbstractArgumentsMapperCreator(SerializationConfig serializationConfig, this.swaggerParameters = new ArrayList<>(this.swaggerOperation.getOperation().getParameters()); - BodyParameter bodyParameter = findSwaggerBodyParameter(); + bodyParameter = findSwaggerBodyParameter(); swaggerBodyProperties = SwaggerUtils.getBodyProperties(swaggerOperation.getSwagger(), bodyParameter); } @@ -203,6 +205,17 @@ protected boolean processKnownParameter(int providerParamIdx, java.lang.reflect. return false; } + // complex scenes + // swagger: int add(Body x) + // producer: int add(int x, int y) + if (bodyParameter != null && + !SwaggerUtils.isBean(providerParameter.getType()) && + swaggerIdx == swaggerBodyIdx && + SwaggerUtils.isBean(bodyParameter.getSchema())) { + swaggerParameters.set(swaggerIdx, bodyParameter); + return false; + } + ArgumentMapper mapper = createKnownParameterMapper(providerParamIdx, swaggerIdx); mappers.add(mapper); return true; diff --git a/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/invocation/arguments/producer/ProducerArgumentsMapperCreator.java b/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/invocation/arguments/producer/ProducerArgumentsMapperCreator.java index b964a3914cf..56c91e12b95 100644 --- a/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/invocation/arguments/producer/ProducerArgumentsMapperCreator.java +++ b/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/invocation/arguments/producer/ProducerArgumentsMapperCreator.java @@ -21,6 +21,7 @@ import java.lang.reflect.Method; import java.lang.reflect.Parameter; +import java.lang.reflect.Type; import java.util.Map; import org.apache.servicecomb.foundation.common.utils.LambdaMetafactoryUtils; @@ -36,15 +37,25 @@ import com.fasterxml.jackson.databind.type.TypeFactory; public class ProducerArgumentsMapperCreator extends AbstractArgumentsMapperCreator { + // swagger parameter types relate to producer + // because features of @BeanParam/query, and rpc mode parameter wrapper + // types is not always equals to producerMethod parameter types directly + private Type[] swaggerParameterTypes; + public ProducerArgumentsMapperCreator(SerializationConfig serializationConfig, Map, ContextArgumentMapperFactory> contextFactorys, Method producerMethod, SwaggerOperation swaggerOperation) { super(serializationConfig, contextFactorys, producerMethod, swaggerOperation); + + swaggerParameterTypes = new Type[swaggerOperation.getOperation().getParameters().size()]; + } + + public Type[] getSwaggerParameterTypes() { + return swaggerParameterTypes; } public ProducerArgumentsMapper createArgumentsMapper() { doCreateArgumentsMapper(); - return new ProducerArgumentsMapper(mappers, providerMethod.getParameterCount()); } @@ -57,13 +68,16 @@ protected void processUnknownParameter(String parameterName) { @Override protected ArgumentMapper createKnownParameterMapper(int producerParamIdx, Integer swaggerIdx) { - return new ProducerArgumentSame(producerParamIdx, swaggerIdx); + swaggerParameterTypes[swaggerIdx] = providerMethod.getGenericParameterTypes()[producerParamIdx]; + return new ProducerArgumentSame(swaggerIdx, producerParamIdx); } @Override protected ArgumentMapper createSwaggerBodyFieldMapper(int producerParamIdx, String parameterName, int swaggerBodyIdx) { - return new SwaggerBodyFieldToProducerArgument(producerParamIdx, parameterName, swaggerBodyIdx); + swaggerParameterTypes[swaggerBodyIdx] = Object.class; + return new SwaggerBodyFieldToProducerArgument(producerParamIdx, parameterName, + providerMethod.getGenericParameterTypes()[producerParamIdx], swaggerBodyIdx); } @Override @@ -87,6 +101,7 @@ protected void processBeanParameter(int producerParamIdx, Parameter producerPara setter = LambdaMetafactoryUtils.createSetter(propertyDefinition.getField().getAnnotated()); } + swaggerParameterTypes[swaggerIdx] = propertyDefinition.getPrimaryType(); mapper.addField(swaggerIdx, setter); } mappers.add(mapper); diff --git a/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/invocation/arguments/producer/SwaggerBodyFieldToProducerArgument.java b/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/invocation/arguments/producer/SwaggerBodyFieldToProducerArgument.java index 474de654fbb..bf6f4b58a79 100644 --- a/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/invocation/arguments/producer/SwaggerBodyFieldToProducerArgument.java +++ b/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/invocation/arguments/producer/SwaggerBodyFieldToProducerArgument.java @@ -17,27 +17,39 @@ package org.apache.servicecomb.swagger.invocation.arguments.producer; +import java.lang.reflect.Type; import java.util.Map; +import org.apache.servicecomb.foundation.common.utils.JsonUtils; import org.apache.servicecomb.swagger.invocation.SwaggerInvocation; import org.apache.servicecomb.swagger.invocation.arguments.ArgumentMapper; +import com.fasterxml.jackson.databind.JavaType; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.type.TypeFactory; + public class SwaggerBodyFieldToProducerArgument implements ArgumentMapper { + public static ObjectMapper mapper = JsonUtils.OBJ_MAPPER; + private final int producerParamIdx; private final String parameterName; + private final JavaType producerParamType; + private final int swaggerBodyIdx; - public SwaggerBodyFieldToProducerArgument(int producerParamIdx, String parameterName, int swaggerBodyIdx) { + public SwaggerBodyFieldToProducerArgument(int producerParamIdx, String parameterName, Type producerParamType, + int swaggerBodyIdx) { this.producerParamIdx = producerParamIdx; this.parameterName = parameterName; + this.producerParamType = TypeFactory.defaultInstance().constructType(producerParamType); this.swaggerBodyIdx = swaggerBodyIdx; } @Override public void mapArgument(SwaggerInvocation invocation, Object[] producerArguments) { Map body = invocation.getSwaggerArgument(swaggerBodyIdx); - producerArguments[producerParamIdx] = body.get(parameterName); + producerArguments[producerParamIdx] = mapper.convertValue(body.get(parameterName), producerParamType); } } diff --git a/swagger/swagger-invocation/invocation-core/src/test/java/org/apache/servicecomb/swagger/invocation/arguments/producer/TestPojoOneArg.java b/swagger/swagger-invocation/invocation-core/src/test/java/org/apache/servicecomb/swagger/invocation/arguments/producer/TestPojoOneArg.java new file mode 100644 index 00000000000..df8573dddae --- /dev/null +++ b/swagger/swagger-invocation/invocation-core/src/test/java/org/apache/servicecomb/swagger/invocation/arguments/producer/TestPojoOneArg.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.invocation.arguments.producer; + +import java.util.Collections; + +import org.apache.servicecomb.foundation.test.scaffolding.model.Color; +import org.apache.servicecomb.swagger.engine.SwaggerEnvironment; +import org.apache.servicecomb.swagger.engine.SwaggerProducer; +import org.apache.servicecomb.swagger.engine.SwaggerProducerOperation; +import org.apache.servicecomb.swagger.invocation.SwaggerInvocation; +import org.apache.servicecomb.swagger.invocation.schemas.PojoOneArg; +import org.junit.Assert; +import org.junit.Test; + +public class TestPojoOneArg { + @Test + public void should_mapper_swagger_wrapped_body_field_to_producer_enum() { + SwaggerProducer swaggerProducer = new SwaggerEnvironment().createProducer(new PojoOneArg(), null); + SwaggerProducerOperation swaggerProducerOperation = swaggerProducer.findOperation("enumBody"); + Assert.assertEquals("color", + swaggerProducerOperation.getSwaggerOperation().getOperation().getParameters().get(0).getName()); + + ProducerArgumentsMapper mapper = swaggerProducerOperation.getArgumentsMapper(); + + SwaggerInvocation invocation = new SwaggerInvocation(); + invocation.setSwaggerArguments(new Object[] {Collections.singletonMap("color", "BLUE")}); + + Object[] arguments = mapper.toProducerArgs(invocation); + + Assert.assertEquals(1, arguments.length); + Assert.assertSame(Color.BLUE, arguments[0]); + } +} diff --git a/swagger/swagger-invocation/invocation-core/src/test/java/org/apache/servicecomb/swagger/invocation/schemas/ConsumerOneArg.java b/swagger/swagger-invocation/invocation-core/src/test/java/org/apache/servicecomb/swagger/invocation/schemas/ConsumerOneArg.java new file mode 100644 index 00000000000..876b952d481 --- /dev/null +++ b/swagger/swagger-invocation/invocation-core/src/test/java/org/apache/servicecomb/swagger/invocation/schemas/ConsumerOneArg.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.swagger.invocation.schemas; + +import org.apache.servicecomb.foundation.test.scaffolding.model.Color; +import org.apache.servicecomb.foundation.test.scaffolding.model.User; + +public interface ConsumerOneArg { + void simple(String name); + + void bean(User user); + + void enumBody(Color color); +} diff --git a/swagger/swagger-invocation/invocation-core/src/test/java/org/apache/servicecomb/swagger/invocation/schemas/PojoOneArg.java b/swagger/swagger-invocation/invocation-core/src/test/java/org/apache/servicecomb/swagger/invocation/schemas/PojoOneArg.java new file mode 100644 index 00000000000..6172f47083b --- /dev/null +++ b/swagger/swagger-invocation/invocation-core/src/test/java/org/apache/servicecomb/swagger/invocation/schemas/PojoOneArg.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.swagger.invocation.schemas; + +import org.apache.servicecomb.foundation.test.scaffolding.model.Color; +import org.apache.servicecomb.foundation.test.scaffolding.model.User; + +public class PojoOneArg { + public void simple(String name) { + + } + + public void bean(User user) { + + } + + public void enumBody(Color color) { + + } +}