Skip to content

Commit

Permalink
Support exception mapper extension
Browse files Browse the repository at this point in the history
  • Loading branch information
mytang0 committed Feb 20, 2023
1 parent a131257 commit 05776e2
Show file tree
Hide file tree
Showing 4 changed files with 37 additions and 10 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
import java.util.concurrent.ConcurrentHashMap;

import static org.apache.dubbo.common.constants.CommonConstants.COMMA_SPLIT_PATTERN;
import static org.apache.dubbo.rpc.protocol.rest.Constants.EXCEPTION_MAPPER_KEY;
import static org.apache.dubbo.rpc.protocol.rest.Constants.EXTENSION_KEY;

public abstract class BaseRestProtocolServer implements RestProtocolServer {
Expand All @@ -38,8 +39,8 @@ public void start(URL url) {
getDeployment().getMediaTypeMappings().put("json", "application/json");
getDeployment().getMediaTypeMappings().put("xml", "text/xml");
getDeployment().getProviderClasses().add(RpcContextFilter.class.getName());
// TODO users can override this mapper, but we just rely on the current priority strategy of resteasy
getDeployment().getProviderClasses().add(RpcExceptionMapper.class.getName());

loadProviders(url.getParameter(EXCEPTION_MAPPER_KEY, RpcExceptionMapper.class.getName()));

loadProviders(url.getParameter(EXTENSION_KEY, ""));

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,4 +35,7 @@ public interface Constants {
String TOMCAT = "tomcat";

String NETTY = "netty";

// exception mapper
String EXCEPTION_MAPPER_KEY = "exception.mapper";
}
Original file line number Diff line number Diff line change
Expand Up @@ -28,24 +28,21 @@ public class RpcExceptionMapper implements ExceptionMapper<RpcException> {

@Override
public Response toResponse(RpcException e) {
// TODO do more sophisticated exception handling and output
if (e.getCause() instanceof ConstraintViolationException) {
return handleConstraintViolationException((ConstraintViolationException) e.getCause());
}
// we may want to avoid exposing the dubbo exception details to certain clients
// TODO for now just do plain text output
return Response.status(Response.Status.INTERNAL_SERVER_ERROR).entity("Internal server error: " + e.getMessage()).type(ContentType.TEXT_PLAIN_UTF_8).build();
}

protected Response handleConstraintViolationException(ConstraintViolationException cve) {
ViolationReport report = new ViolationReport();
for (ConstraintViolation<?> cv : cve.getConstraintViolations()) {
report.addConstraintViolation(new RestConstraintViolation(
cv.getPropertyPath().toString(),
cv.getMessage(),
cv.getInvalidValue() == null ? "null" : cv.getInvalidValue().toString()));
cv.getPropertyPath().toString(),
cv.getMessage(),
cv.getInvalidValue() == null ? "null" : cv.getInvalidValue().toString()));
}
// TODO for now just do xml output
return Response.status(Response.Status.INTERNAL_SERVER_ERROR).entity(report).type(ContentType.TEXT_XML_UTF_8).build();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -38,18 +38,21 @@
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;

import javax.ws.rs.core.Response;
import javax.ws.rs.ext.ExceptionMapper;
import java.util.Map;

import static org.apache.dubbo.remoting.Constants.SERVER_KEY;
import static org.apache.dubbo.rpc.protocol.rest.Constants.EXCEPTION_MAPPER_KEY;
import static org.apache.dubbo.rpc.protocol.rest.Constants.EXTENSION_KEY;
import static org.hamcrest.CoreMatchers.equalTo;
import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.CoreMatchers.nullValue;
import static org.hamcrest.MatcherAssert.assertThat;

class RestProtocolTest {
private Protocol protocol = ExtensionLoader.getExtensionLoader(Protocol.class).getExtension("rest");
private ProxyFactory proxy = ExtensionLoader.getExtensionLoader(ProxyFactory.class).getAdaptiveExtension();
private final Protocol protocol = ExtensionLoader.getExtensionLoader(Protocol.class).getExtension("rest");
private final 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.DemoService");
private final ModuleServiceRepository repository = ApplicationModel.defaultModel().getDefaultModule().getServiceRepository();
Expand Down Expand Up @@ -246,6 +249,29 @@ void testDefaultPort() {
assertThat(protocol.getDefaultPort(), is(80));
}

@Test
void testExceptionMapper() {
DemoService server = new DemoServiceImpl();

URL url = this.registerProvider(exportUrl, server, DemoService.class);

URL exceptionUrl = url.addParameter(EXCEPTION_MAPPER_KEY, TestExceptionMapper.class.getName());

protocol.export(proxy.getInvoker(server, DemoService.class, exceptionUrl));

DemoService referDemoService = this.proxy.getProxy(protocol.refer(DemoService.class, exceptionUrl));

Assertions.assertEquals("test-exception", referDemoService.error());
}

public static class TestExceptionMapper implements ExceptionMapper<RuntimeException> {

@Override
public Response toResponse(RuntimeException e) {
return Response.ok("test-exception").build();
}
}

private URL registerProvider(URL url, Object impl, Class<?> interfaceClass) {
ServiceDescriptor serviceDescriptor = repository.registerService(interfaceClass);
ProviderModel providerModel = new ProviderModel(
Expand Down

0 comments on commit 05776e2

Please sign in to comment.