diff --git a/dubbo-rpc/dubbo-rpc-rest/src/main/java/org/apache/dubbo/rpc/protocol/rest/message/codec/JsonCodec.java b/dubbo-rpc/dubbo-rpc-rest/src/main/java/org/apache/dubbo/rpc/protocol/rest/message/codec/JsonCodec.java index 7d494b53b2c..8ff5f2b60f3 100644 --- a/dubbo-rpc/dubbo-rpc-rest/src/main/java/org/apache/dubbo/rpc/protocol/rest/message/codec/JsonCodec.java +++ b/dubbo-rpc/dubbo-rpc-rest/src/main/java/org/apache/dubbo/rpc/protocol/rest/message/codec/JsonCodec.java @@ -23,7 +23,7 @@ import org.apache.dubbo.rpc.protocol.rest.message.HttpMessageCodec; import org.apache.dubbo.rpc.protocol.rest.message.MediaTypeMatcher; import org.apache.dubbo.rpc.protocol.rest.util.DataParseUtils; - +import javax.ws.rs.core.Response; import java.io.OutputStream; import java.nio.charset.StandardCharsets; import java.util.HashSet; @@ -37,10 +37,9 @@ public class JsonCodec implements HttpMessageCodec { private static final Set unSupportClasses = new HashSet<>(); static { - unSupportClasses.add(byte[].class); unSupportClasses.add(String.class); - + unSupportClasses.add(Response.class); } @Override diff --git a/dubbo-rpc/dubbo-rpc-rest/src/main/java/org/apache/dubbo/rpc/protocol/rest/message/codec/ResteasyResponseCodec.java b/dubbo-rpc/dubbo-rpc-rest/src/main/java/org/apache/dubbo/rpc/protocol/rest/message/codec/ResteasyResponseCodec.java new file mode 100644 index 00000000000..31fe9e2db9e --- /dev/null +++ b/dubbo-rpc/dubbo-rpc-rest/src/main/java/org/apache/dubbo/rpc/protocol/rest/message/codec/ResteasyResponseCodec.java @@ -0,0 +1,88 @@ +/* + * 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.dubbo.rpc.protocol.rest.message.codec; + +import org.apache.dubbo.common.URL; +import org.apache.dubbo.common.extension.Activate; +import org.apache.dubbo.common.utils.ClassUtils; +import org.apache.dubbo.common.utils.JsonUtils; +import org.apache.dubbo.metadata.rest.media.MediaType; +import org.apache.dubbo.rpc.protocol.rest.message.HttpMessageCodec; + +import java.io.OutputStream; +import java.lang.reflect.Method; +import java.nio.charset.StandardCharsets; + +@Activate(onClass="javax.ws.rs.core.Response") +public class ResteasyResponseCodec implements HttpMessageCodec { + + private Class responseClass; + public ResteasyResponseCodec(){ + try { + responseClass = ClassUtils.forName("javax.ws.rs.core.Response"); + } catch (Exception exception) { + responseClass = null; + } + } + + @Override + public boolean contentTypeSupport(MediaType mediaType, Class targetType) { + return isMatch(targetType); + } + + @Override + public boolean typeSupport(Class targetType) { + return isMatch(targetType); + } + + @Override + public MediaType contentType() { + return MediaType.APPLICATION_JSON_VALUE; + } + + @Override + public Object decode(byte[] body, Class targetType) throws Exception { + if (null == body || body.length == 0) { + return null; + } + + Class builtResponse = ClassUtils.forName("org.jboss.resteasy.specimpl.BuiltResponse"); + + Object o = builtResponse.newInstance(); + + Method method = builtResponse.getMethod("setEntity", Object.class); + + method.invoke(o, new String(body, StandardCharsets.UTF_8)); + + return o; + } + + @Override + public void encode(OutputStream os, Object target, URL url) throws Exception { + if (target != null) { + Method method = target.getClass().getMethod("getEntity"); + method.setAccessible(true); + Object result = method.invoke(target); + os.write(JsonUtils.toJson(result).getBytes(StandardCharsets.UTF_8)); + } + } + + private boolean isMatch(Class targetType) { + return responseClass != null && null != targetType && responseClass.isAssignableFrom(targetType); + } +} diff --git a/dubbo-rpc/dubbo-rpc-rest/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.rpc.protocol.rest.message.HttpMessageCodec b/dubbo-rpc/dubbo-rpc-rest/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.rpc.protocol.rest.message.HttpMessageCodec index 11a7b325399..5a4daf81349 100644 --- a/dubbo-rpc/dubbo-rpc-rest/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.rpc.protocol.rest.message.HttpMessageCodec +++ b/dubbo-rpc/dubbo-rpc-rest/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.rpc.protocol.rest.message.HttpMessageCodec @@ -4,3 +4,4 @@ json=org.apache.dubbo.rpc.protocol.rest.message.codec.JsonCodec string=org.apache.dubbo.rpc.protocol.rest.message.codec.StringCodec byteArray=org.apache.dubbo.rpc.protocol.rest.message.codec.ByteArrayCodec xml=org.apache.dubbo.rpc.protocol.rest.message.codec.XMLCodec +resteasyResponseCodec=org.apache.dubbo.rpc.protocol.rest.message.codec.ResteasyResponseCodec diff --git a/dubbo-rpc/dubbo-rpc-rest/src/test/java/org/apache/dubbo/rpc/protocol/rest/ResteasyResponseTest.java b/dubbo-rpc/dubbo-rpc-rest/src/test/java/org/apache/dubbo/rpc/protocol/rest/ResteasyResponseTest.java new file mode 100644 index 00000000000..8884ba780e3 --- /dev/null +++ b/dubbo-rpc/dubbo-rpc-rest/src/test/java/org/apache/dubbo/rpc/protocol/rest/ResteasyResponseTest.java @@ -0,0 +1,78 @@ +/* + * 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.dubbo.rpc.protocol.rest; + +import org.apache.dubbo.common.URL; +import org.apache.dubbo.common.extension.ExtensionLoader; +import org.apache.dubbo.common.utils.NetUtils; +import org.apache.dubbo.rpc.Protocol; +import org.apache.dubbo.rpc.ProxyFactory; +import org.apache.dubbo.rpc.model.*; +import org.apache.dubbo.rpc.protocol.rest.rest.RestDemoService; +import org.apache.dubbo.rpc.protocol.rest.rest.RestDemoServiceImpl; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +import javax.ws.rs.core.Response; + +import static org.apache.dubbo.remoting.Constants.SERVER_KEY; + +public class ResteasyResponseTest { + + private Protocol protocol = ExtensionLoader.getExtensionLoader(Protocol.class).getExtension("rest"); + private ProxyFactory proxy = ExtensionLoader.getExtensionLoader(ProxyFactory.class).getAdaptiveExtension(); + private final int availablePort = NetUtils.getAvailablePort(); + private final URL exportUrl = URL.valueOf("rest://127.0.0.1:" + availablePort + "/rest?interface=org.apache.dubbo.rpc.protocol.rest.rest.RestDemoService"); + private final ModuleServiceRepository repository = ApplicationModel.defaultModel().getDefaultModule().getServiceRepository(); + + @AfterEach + public void tearDown() { + protocol.destroy(); + FrameworkModel.destroyAll(); + } + @Test + void testResponse() { + RestDemoService server = new RestDemoServiceImpl(); + URL url = this.registerProvider(exportUrl, server, RestDemoService.class); + + URL nettyUrl = url.addParameter(SERVER_KEY, "netty").addParameter("timeout", 3000000); + + protocol.export(proxy.getInvoker(new RestDemoServiceImpl(), RestDemoService.class, nettyUrl)); + + RestDemoService demoService = this.proxy.getProxy(protocol.refer(RestDemoService.class, nettyUrl)); + + Response response = demoService.findUserById(10); + + Assertions.assertNotNull(response); + } + + private URL registerProvider(URL url, Object impl, Class interfaceClass) { + ServiceDescriptor serviceDescriptor = repository.registerService(interfaceClass); + ProviderModel providerModel = new ProviderModel( + url.getServiceKey(), + impl, + serviceDescriptor, + null, + null); + repository.registerProvider(providerModel); + return url.setServiceModel(providerModel); + } + + + +} diff --git a/dubbo-rpc/dubbo-rpc-rest/src/test/java/org/apache/dubbo/rpc/protocol/rest/rest/RestDemoService.java b/dubbo-rpc/dubbo-rpc-rest/src/test/java/org/apache/dubbo/rpc/protocol/rest/rest/RestDemoService.java index c423bbf3cfc..56b3fd1ee74 100644 --- a/dubbo-rpc/dubbo-rpc-rest/src/test/java/org/apache/dubbo/rpc/protocol/rest/rest/RestDemoService.java +++ b/dubbo-rpc/dubbo-rpc-rest/src/test/java/org/apache/dubbo/rpc/protocol/rest/rest/RestDemoService.java @@ -18,6 +18,7 @@ import javax.ws.rs.*; import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Response; @Path("/demoService") @@ -26,6 +27,10 @@ public interface RestDemoService { @Path("/hello") Integer hello(@QueryParam("a")Integer a,@QueryParam("b") Integer b); + @GET + @Path("/findUserById") + Response findUserById(@QueryParam("id")Integer id); + @GET @Path("/error") String error(); diff --git a/dubbo-rpc/dubbo-rpc-rest/src/test/java/org/apache/dubbo/rpc/protocol/rest/rest/RestDemoServiceImpl.java b/dubbo-rpc/dubbo-rpc-rest/src/test/java/org/apache/dubbo/rpc/protocol/rest/rest/RestDemoServiceImpl.java index 3ba0858b23e..b0b32ed9a82 100644 --- a/dubbo-rpc/dubbo-rpc-rest/src/test/java/org/apache/dubbo/rpc/protocol/rest/rest/RestDemoServiceImpl.java +++ b/dubbo-rpc/dubbo-rpc-rest/src/test/java/org/apache/dubbo/rpc/protocol/rest/rest/RestDemoServiceImpl.java @@ -17,10 +17,11 @@ package org.apache.dubbo.rpc.protocol.rest.rest; import org.apache.dubbo.rpc.RpcContext; - +import org.jboss.resteasy.specimpl.BuiltResponse; +import javax.ws.rs.core.Response; +import java.util.HashMap; import java.util.Map; - public class RestDemoServiceImpl implements RestDemoService { private static Map context; private boolean called; @@ -53,6 +54,14 @@ public Integer hello(Integer a, Integer b) { return a + b; } + @Override + public Response findUserById(Integer id) { + Map content = new HashMap<>(); + content.put("username","jack"); + content.put("id",id); + + return BuiltResponse.ok(content).build(); + } @Override public String error() {