protected MessageConsumer wrapMessageConsumer(MessageConsumer consumer) { MessageConsumer result = consumer; if (messageTracer != null) { final PrintWriter tracer = messageTracer; result = message -> { tracer.println(message); tracer.flush(); consumer.consume(message); }; } if (validateMessages) { result = new ReflectiveMessageValidator(result); } if (messageWrapper != null) { result = messageWrapper.apply(result); } return result; }
+ " Path: " + createPathString(accessorStack), ResponseErrorCode.InvalidParams.getValue())); return; if (element == null) { issues.add(new MessageIssue("Lists must not contain null references." + " Path: " + createPathString(accessorStack), ResponseErrorCode.InvalidParams.getValue())); validate(element, issues, objectStack, accessorStack); accessorStack.pop(); Either<?, ?> either = (Either<?, ?>) object; if (either.isLeft()) { validate(either.getLeft(), issues, objectStack, accessorStack); } else if (either.isRight()) { validate(either.getRight(), issues, objectStack, accessorStack); } else { issues.add(new MessageIssue("An Either instance must not be empty." + " Path: " + createPathString(accessorStack), ResponseErrorCode.InvalidParams.getValue())); if (isGetter(method)) { accessorStack.push(method); Object value = method.invoke(object); issues.add(new MessageIssue("The accessor '" + method.getDeclaringClass().getSimpleName() + "." + method.getName() + "()' must return a non-null value." + " Path: " + createPathString(accessorStack),
protected String createPathString(Deque<Object> accessorStack) { StringBuilder result = new StringBuilder("$"); Iterator<Object> resultIter = accessorStack.descendingIterator(); while(resultIter.hasNext()) { Object accessor = resultIter.next(); if (accessor instanceof Method) result.append('.').append(getPropertyName((Method) accessor)); else if (accessor instanceof Integer) result.append('[').append(accessor).append(']'); else result.append(accessor); } return result.toString(); }
@Test public void testSkipJsonElement() { final AtomicBoolean result = new AtomicBoolean(false); ReflectiveMessageValidator validator = new ReflectiveMessageValidator((message) -> { result.set(true); }); NotificationMessage message = new NotificationMessage(); message.setMethod("foo"); message.setParams(new JsonObject()); validator.consume(message); Assert.assertTrue(result.get()); }
@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); } }
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()); } }
@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 testNoViolation() { ReflectiveMessageValidator validator = new ReflectiveMessageValidator(); NotificationMessage message = new NotificationMessage(); message.setMethod("foo"); Foo foo = new Foo(); foo.nonNullString = "test"; foo.nested = new Foo() {{ nonNullString = "something"; }}; message.setParams(foo); validator.consume(message); }
+ " Path: " + createPathString(accessorStack), ResponseErrorCode.InvalidParams.getValue())); return; if (element == null) { issues.add(new MessageIssue("Lists must not contain null references." + " Path: " + createPathString(accessorStack), ResponseErrorCode.InvalidParams.getValue())); validate(element, issues, objectStack, accessorStack); accessorStack.pop(); Either<?, ?> either = (Either<?, ?>) object; if (either.isLeft()) { validate(either.getLeft(), issues, objectStack, accessorStack); } else if (either.isRight()) { validate(either.getRight(), issues, objectStack, accessorStack); } else { issues.add(new MessageIssue("An Either instance must not be empty." + " Path: " + createPathString(accessorStack), ResponseErrorCode.InvalidParams.getValue())); if (isGetter(method)) { accessorStack.push(method); Object value = method.invoke(object); issues.add(new MessageIssue("The accessor '" + method.getDeclaringClass().getSimpleName() + "." + method.getName() + "()' must return a non-null value." + " Path: " + createPathString(accessorStack),
protected MessageConsumer wrapMessageConsumer(MessageConsumer consumer) { MessageConsumer result = consumer; if (messageTracer != null) { final PrintWriter tracer = messageTracer; result = message -> { tracer.println(message); tracer.flush(); consumer.consume(message); }; } if (validateMessages) { result = new ReflectiveMessageValidator(result); } if (messageWrapper != null) { result = messageWrapper.apply(result); } return result; }
protected String createPathString(Deque<Object> accessorStack) { StringBuilder result = new StringBuilder("$"); Iterator<Object> resultIter = accessorStack.descendingIterator(); while(resultIter.hasNext()) { Object accessor = resultIter.next(); if (accessor instanceof Method) result.append('.').append(getPropertyName((Method) accessor)); else if (accessor instanceof Integer) result.append('[').append(accessor).append(']'); else result.append(accessor); } return result.toString(); }
@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()); } }
@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 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()); } }
@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()); } }