@Override public void handleRequest(InputStream input, OutputStream output, Context context) throws IOException { server.handleRequest(input, output); } }
public JsonRpcLambdaHandler(ObjectMapper mapper, Class<T> serviceClass, T service) { this.service = service; this.server = new JsonRpcBasicServer(mapper, this.service, serviceClass); this.server.setErrorResolver( new MultipleErrorResolver(new PojoErrorResolver(mapper), DefaultErrorResolver.INSTANCE)); }
public JsonRpcLambdaClient(ObjectMapper mapper, LambdaAsyncClient lambda, String functionName) { this.lambda = lambda; this.functionName = functionName; this.streamClient = new JsonRpcClient( mapper, new MultipleExceptionResolver( new PojoExceptionResolver(mapper), DefaultExceptionResolver.INSTANCE)); }
/** * {@inheritDoc} */ @Override public JsonError resolveError(Throwable thrownException, Method method, List<JsonNode> arguments) { JsonRpcError resolver = getResolverForException(thrownException, method); if (notFoundResolver(resolver)) { return null; } String message = hasErrorMessage(resolver) ? resolver.message() : thrownException.getMessage(); return new JsonError(resolver.code(), message, new ErrorData(resolver.exception().getName(), message)); }
@JsonRpcErrors({@JsonRpcError(exception = CustomTestException.class, code = 1234)}) Object testMethod(); }
/** * Create a new dynamic JSON-RPC proxy for an interface that dispatches calls as Lambda function * invocations using this client. * * @return a dynamic proxy that implements serviceInterface */ public <T> T newProxy(Class<T> serviceInterface) { IJsonRpcClient client = new JsonRpcLambdaProxyAdapter(this); return ProxyUtil.createClientProxy( Thread.currentThread().getContextClassLoader(), serviceInterface, client); }
private JsonRpcError getResolverForException(Throwable thrownException, Method method) { JsonRpcErrors errors = ReflectionUtil.getAnnotation(method, JsonRpcErrors.class); if (hasAnnotations(errors)) { for (JsonRpcError errorDefined : errors.value()) { if (isExceptionInstanceOfError(thrownException, errorDefined)) { return errorDefined; } } } return null; }
@JsonRpcMethod("mixedObjectPrimitiveVarargMethodWithJsonRpcParam") String mixedObjectPrimitiveVarargMethodWithJsonRpcParam(@JsonRpcParam("object") Object test, @JsonRpcParam("ints") int... ints); }
protected void handleErrorResponse(ObjectNode jsonObject) throws Throwable { if (hasError(jsonObject)) { // resolve and throw the exception if (exceptionResolver == null) { throw DefaultExceptionResolver.INSTANCE.resolveException(jsonObject); } else { throw exceptionResolver.resolveException(jsonObject); } } }
@Test public void clientSideResolverResolvesServerSideErrors() throws Exception { ErrorResolver server = new PojoErrorResolver(mapper); ExceptionResolver client = new PojoExceptionResolver(mapper); PojoTestException originalException = new PojoTestException("alpha", "beta"); JsonError originalError = server.resolveError( originalException, PojoService.class.getMethod("pojoCall", String.class), Collections.emptyList()); ObjectNode response = wrapErrorAsResponse(originalError); Throwable deserializedThrowable = client.resolveException(response); assertThat(deserializedThrowable) .isInstanceOf(PojoTestException.class) .isEqualToComparingFieldByField(originalException); }
@Override protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { jsonRpcServer.handle(request, response); } }
/** * Serialize a JSON-RPC request into a ByteBuffer for use as a Lambda request payload. * * @throws IOException if serializing the request payload fails */ private ByteBuffer writeRequest(String methodName, Object argument) throws IOException { ByteArrayOutputStream requestStream = new ByteArrayOutputStream(); streamClient.invoke(methodName, argument, requestStream); log.trace("Raw request payload: " + requestStream.toString()); return ByteBuffer.wrap(requestStream.toByteArray()); }
/** Deserialize a JSON-RPC response from a ByteBuffer from a Lambda response payload. */ private Object readResponse(Type returnType, InvokeResponse response) { try { log.trace( "Raw response payload: " + StandardCharsets.UTF_8.decode(response.payload()).toString()); return streamClient.readResponse( returnType, new ByteBufferBackedInputStream(response.payload())); } catch (Throwable t) { if (t instanceof IOException) { log.warn("Could not read JSON-RPC response: ", t); } else { // This exception is raised when deserialized from the remote call, and must be // handled/logged in calling code; so only log at DEBUG level log.debug("Read an exception value from JSON-RPC response: ", t); } // wrap the raw Throwable from the JSON RPC client so that this method can be used in // CompletableFuture::thenApply throw new CompletionException(t); } } }
@JsonRpcService( "api/temperature" // note the absence of a leading slash ) public interface Temperature { @SuppressWarnings("unused") Integer currentTemperature(); }
@Override public JsonError resolveError( final Throwable t, final Method method, final List<JsonNode> arguments) { final boolean isModeledException = Arrays.stream(method.getExceptionTypes()).anyMatch(aClass -> aClass.isInstance(t)); if (isModeledException) { // We have to explicitly serialize the exception type here using the mapper, rather than // relying on the mapper serializing the entire JsonError object. This is needed because // Jackson looks up the mixins based on the type of the *variable* not the object instance. // Since the type of the data field on JsonError is just Object, it then doesn't correctly // apply the annotations from ThrowableSerializationMixin. final JsonNode node = mapper.valueToTree(t); return new JsonError(ERROR_CODE, t.getMessage(), node); } log.warn( "Exception type {} is not modeled in signature of {}, returning generic error", t.getClass(), method.getName()); return new JsonError(JsonError.INTERNAL_ERROR.code, t.getMessage(), null); } }
private void raiseExceptionIfNotValidResponseObject(JsonNode response) { if (isInvalidResponse(response)) { throw new JsonRpcClientException(0, "Invalid JSON-RPC response", response); } }
/** * {@inheritDoc} */ public void didInvoke(Method method, List<JsonNode> arguments, Object result, Throwable t, long duration) { for (InvocationListener invocationListener : invocationListeners) { invocationListener.didInvoke(method, arguments, result, t, duration); } }
/** * {@inheritDoc} */ public Throwable resolveException(ObjectNode response) { for (ExceptionResolver resolver : resolvers) { Throwable resolvedException = resolver.resolveException(response); if (resolvedException != null) { return resolvedException; } } return null; }
@JsonRpcMethod("mixedObjectStringVarargMethodWithJsonRpcParam") String mixedObjectStringVarargMethodWithJsonRpcParam(@JsonRpcParam("object") Object test, @JsonRpcParam("strings") String... strings);
/** * <p>Unlike the {@link com.googlecode.jsonrpc4j.spring.service.Service} / * {@link com.googlecode.jsonrpc4j.spring.service.ServiceImpl} example, this case has no interface * so the bean has the @JsonRpcService directly into the implementation. This setup worked * in jsonrpc4j 1.1, but failed in 1.2.</p> */ @JsonRpcService("ServiceSansInterface") public class ServiceSansInterfaceImpl { }