Spring Integration and returning schema validation errors

757 views Asked by At

We are using Spring Integration to process a JSON payload passed into a RESTful endpoint. As part of this flow we are using a filter to validate the JSON:

.filter(schemaValidationFilter, s -> s
    .discardFlow(f -> f
        .handle(message -> {
            throw new SchemaValidationException(message);
        }))
)

This works great. However, if the validation fails we want to capture the parsing error and return that to the user so they can act on the error. Here is the overridden accept method in the SchemaValidationFilter class:

@Override
public boolean accept(Message<?> message) {
  Assert.notNull(message);
  Assert.isTrue(message.getHeaders().containsKey(TYPE_NAME));

  String historyType = (String)message.getHeaders().get(TYPE_NAME);
  JSONObject payload = (JSONObject) message.getPayload();
  String jsonString = payload.toJSONString();

  try {
      ProcessingReport report = schemaValidator.validate(historyType, payload);
      return report.isSuccess();
  } catch (IOException | ProcessingException e) {
      throw new MessagingException(message, e);
  }

}

What we have done is in the catch block we throw a MessageException which seems to solve the problem. However this seems to break what a filter should do (simply return a true or false).

Is there a best practice for passing the error details from the filter to the client? Is the filter the right solution for this use case?

Thanks for your help! John

2

There are 2 answers

1
Artem Bilan On BEST ANSWER

I'd say you go correct way. Please, refer to the XmlValidatingMessageSelector, so your JsonValidatingMessageSelector should be similar and must follow the same design.

Since we have a throwExceptionOnRejection option we always can be sure that throwing Exception instead of just true/false is correct behavior.

What Gary says is good, too, but according to the existing logic in that MessageSelector impl we can go ahead with the same and continue to use .filter(), but, of course, already without .discardFlow(), because we won't send invalid message to the discardChannel.

When your JsonValidatingMessageSelector is ready, feel free to contribute it back to the Framework!

1
Gary Russell On

It's probably more correct to do the validation in a <service-activator/>...

public Message<?> validate(Message<?> message) {

    ...

    try {
        ProcessingReport report = schemaValidator.validate(historyType, payload);
        return message;
    } 
    catch (IOException | ProcessingException e) {
        throw new MessagingException(message, e);
    }
}

...since you're never really filtering.