protected void handleResponseIssues(ResponseMessage responseMessage, List<MessageIssue> issues) { PendingRequestInfo requestInfo; synchronized (sentRequestMap) { requestInfo = sentRequestMap.remove(responseMessage.getId()); } if (requestInfo == null) { // We have no pending request information that matches the id given in the response LOG.log(Level.WARNING, "Unmatched response message: " + responseMessage); logIssues(responseMessage, issues); } else { requestInfo.future.completeExceptionally(new MessageIssueException(responseMessage, issues)); } }
issueHandler.handle(exception.getRpcMessage(), exception.getIssues()); else fireError(exception);
private void assertIssues(Message message, CharSequence expectedIssues) { try { validator.consume(message); Assert.fail("Expected InvalidMessageException: " + expectedIssues + "."); } catch (MessageIssueException e) { String expected = expectedIssues.toString(); String actual = LineEndings.toSystemLineEndings(e.getMessage()); // The expectation may be a prefix of the actual exception message if (!actual.startsWith(expected)) Assert.assertEquals(expected, actual); } } }
@Test public void testRequestValidation() { ReflectiveMessageValidator validator = new ReflectiveMessageValidator(); RequestMessage message = new RequestMessage(); message.setId("1"); message.setParams(new Object()); try { validator.consume(message); Assert.fail(); } catch (MessageIssueException e) { Assert.assertEquals("The accessor 'RequestMessage.getMethod()' must return a non-null value. Path: $.method", e.getMessage()); } }
issueHandler.handle(exception.getRpcMessage(), exception.getIssues()); else fireError(exception);
protected void handleResponseIssues(ResponseMessage responseMessage, List<MessageIssue> issues) { PendingRequestInfo requestInfo; synchronized (sentRequestMap) { requestInfo = sentRequestMap.remove(responseMessage.getId()); } if (requestInfo == null) { // We have no pending request information that matches the id given in the response LOG.log(Level.WARNING, "Unmatched response message: " + responseMessage); logIssues(responseMessage, issues); } else { requestInfo.future.completeExceptionally(new MessageIssueException(responseMessage, issues)); } }
@Test public void testReflectionOnPropertiesOnly() { ReflectiveMessageValidator validator = new ReflectiveMessageValidator(); NotificationMessage message = new NotificationMessage(); message.setMethod("foo"); Foo foo = new Foo(); foo.nonNullString = "test"; foo.nested = new Foo() {{ nonNullString = "something"; }}; foo.foos = new ArrayList<>(); foo.foos.add(new Foo()); message.setParams(foo); try { validator.consume(message); Assert.fail(); } catch (MessageIssueException e) { Assert.assertEquals("The accessor 'Foo.getNonNullString()' must return a non-null value. Path: $.params.foos[0].nonNullString", e.getMessage()); } }
@Test public void testParseErrorRequest() { Map<String, JsonRpcMethod> supportedMethods = new LinkedHashMap<>(); supportedMethods.put("foo", JsonRpcMethod.request("foo", new TypeToken<Void>() {}.getType(), new TypeToken<Location>() {}.getType())); DebugMessageJsonHandler handler = new DebugMessageJsonHandler(supportedMethods); handler.setMethodProvider((id) -> "foo"); String input = "{" + "\"seq\":2,\n" + "\"type\":\"request\",\n" + "\"command\":\"foo\"\n" + "\"arguments\": \"ERROR HERE - a string where an object is expected\",\n" + "}"; try { handler.parseMessage(input); fail("Should have had a parse error"); } catch (MessageIssueException e) { // Make sure the message parsed ok up until the parse error DebugRequestMessage rpcMessage = (DebugRequestMessage)e.getRpcMessage(); Assert.assertEquals("2", rpcMessage.getId()); Assert.assertEquals("foo", rpcMessage.getMethod()); // check there is an underlying error MessageIssue messageIssue = e.getIssues().get(0); Assert.assertNotNull(messageIssue.getCause()); } }
@Override public void consume(Message message) throws MessageIssueException, JsonRpcException { List<MessageIssue> result = new ArrayList<>(); try { validate(message, result, new LinkedList<>(), new LinkedList<>()); } catch (Exception e) { LOG.log(Level.SEVERE, "Error during message validation: " + e.getMessage(), e); result.add(new MessageIssue("Message validation failed, please check the logs of the remote endpoint.", ResponseErrorCode.InvalidParams.getValue())); } if (!result.isEmpty()) { // Sort the messages in order to get a stable order (otherwise it depends on the JVM's reflection implementation) Collections.sort(result, (issue1, issue2) -> issue1.getText().compareTo(issue2.getText())); throw new MessageIssueException(message, result); } else if (delegate != null) { delegate.consume(message); } }
@Test public void testNonNullViolated() { ReflectiveMessageValidator validator = new ReflectiveMessageValidator(); NotificationMessage message = new NotificationMessage(); message.setMethod("foo"); message.setParams(new Foo()); try { validator.consume(message); Assert.fail(); } catch (MessageIssueException e) { Assert.assertEquals("The accessor 'Foo.getNonNullString()' must return a non-null value. Path: $.params.nonNullString", e.getMessage()); } }
@Test public void testParseSyntaxErrorRequest() { Map<String, JsonRpcMethod> supportedMethods = new LinkedHashMap<>(); supportedMethods.put("foo", JsonRpcMethod.request("foo", new TypeToken<Void>() {}.getType(), new TypeToken<Location>() {}.getType())); DebugMessageJsonHandler handler = new DebugMessageJsonHandler(supportedMethods); handler.setMethodProvider((id) -> "foo"); String input = "{" + "\"seq\":2,\n" + "\"type\":\"request\",\n" + "\"command\":\"foo\"\n" + "\"arguments\": \"ERROR HERE - an unterminated string,\n" + "}"; try { handler.parseMessage(input); fail("Should have had a parse error"); } catch (MessageIssueException e) { // Make sure the message parsed ok up until the parse error DebugRequestMessage rpcMessage = (DebugRequestMessage)e.getRpcMessage(); Assert.assertEquals("2", rpcMessage.getId()); Assert.assertEquals("foo", rpcMessage.getMethod()); // check there is an underlying error MessageIssue messageIssue = e.getIssues().get(0); Assert.assertNotNull(messageIssue.getCause()); } } }
public Message parseMessage(Reader input) throws JsonParseException { JsonReader jsonReader = new JsonReader(input); Message message = gson.fromJson(jsonReader, Message.class); if (message != null) { // Check whether the input has been fully consumed try { if (jsonReader.peek() != JsonToken.END_DOCUMENT) { MessageIssue issue = new MessageIssue("JSON document was not fully consumed.", ResponseErrorCode.ParseError.getValue()); throw new MessageIssueException(message, issue); } } catch (MalformedJsonException e) { MessageIssue issue = new MessageIssue("Message could not be parsed.", ResponseErrorCode.ParseError.getValue(), e); throw new MessageIssueException(message, issue); } catch (IOException e) { throw new JsonIOException(e); } } return message; }
@Test public void testRecursionViolation() { ReflectiveMessageValidator validator = new ReflectiveMessageValidator(); NotificationMessage message = new NotificationMessage(); message.setMethod("foo"); Foo foo = new Foo(); foo.nonNullString = "test"; foo.nested = foo; message.setParams(foo); try { validator.consume(message); Assert.fail(); } catch (MessageIssueException e) { Assert.assertEquals("An element of the message has a direct or indirect reference to itself. Path: $.params.nested", e.getMessage()); } }
@Override public void consume(Message message) throws MessageIssueException, JsonRpcException { List<MessageIssue> result = new ArrayList<>(); try { validate(message, result, new LinkedList<>(), new LinkedList<>()); } catch (Exception e) { LOG.log(Level.SEVERE, "Error during message validation: " + e.getMessage(), e); result.add(new MessageIssue("Message validation failed, please check the logs of the remote endpoint.", ResponseErrorCode.InvalidParams.getValue())); } if (!result.isEmpty()) { // Sort the messages in order to get a stable order (otherwise it depends on the JVM's reflection implementation) Collections.sort(result, (issue1, issue2) -> issue1.getText().compareTo(issue2.getText())); throw new MessageIssueException(message, result); } else if (delegate != null) { delegate.consume(message); } }
@Test public void testNonNullViolated_nested() { ReflectiveMessageValidator validator = new ReflectiveMessageValidator(); NotificationMessage message = new NotificationMessage(); message.setMethod("foo"); Foo foo = new Foo(); foo.nonNullString = "test"; foo.nested = new Foo(); message.setParams(foo); try { validator.consume(message); Assert.fail(); } catch (MessageIssueException e) { Assert.assertEquals("The accessor 'Foo.getNonNullString()' must return a non-null value. Path: $.params.nested.nonNullString", e.getMessage()); } }
public Message parseMessage(Reader input) throws JsonParseException { JsonReader jsonReader = new JsonReader(input); Message message = gson.fromJson(jsonReader, Message.class); if (message != null) { // Check whether the input has been fully consumed try { if (jsonReader.peek() != JsonToken.END_DOCUMENT) { MessageIssue issue = new MessageIssue("JSON document was not fully consumed.", ResponseErrorCode.ParseError.getValue()); throw new MessageIssueException(message, issue); } } catch (MalformedJsonException e) { MessageIssue issue = new MessageIssue("Message could not be parsed.", ResponseErrorCode.ParseError.getValue(), e); throw new MessageIssueException(message, issue); } catch (IOException e) { throw new JsonIOException(e); } } return message; }
throw new MessageIssueException(message, issue); } else { throw exception;
Message resultMessage = createMessage(messageType, seq, request_seq, method, success, message, rawParams, rawBody); MessageIssue issue = new MessageIssue("Message could not be parsed.", ResponseErrorCode.ParseError.getValue(), exception); throw new MessageIssueException(resultMessage, issue); } else { throw exception;
throw new MessageIssueException(message, issue); } else { throw exception;