From 4255b31f7ac0e3969059fb9d830109535fdf11d6 Mon Sep 17 00:00:00 2001 From: Timon Borter Date: Thu, 25 Apr 2024 16:19:52 +0200 Subject: [PATCH] fix: better access into json validator for subclasses --- .../json/JsonTextMessageValidator.java | 67 ++++--------------- .../json/schema/JsonSchemaValidation.java | 41 +++++------- .../json/JsonTextMessageValidatorTest.java | 9 +-- 3 files changed, 35 insertions(+), 82 deletions(-) diff --git a/validation/citrus-validation-json/src/main/java/org/citrusframework/validation/json/JsonTextMessageValidator.java b/validation/citrus-validation-json/src/main/java/org/citrusframework/validation/json/JsonTextMessageValidator.java index 1c59bacaa6..3762e5150f 100644 --- a/validation/citrus-validation-json/src/main/java/org/citrusframework/validation/json/JsonTextMessageValidator.java +++ b/validation/citrus-validation-json/src/main/java/org/citrusframework/validation/json/JsonTextMessageValidator.java @@ -34,7 +34,7 @@ *

* JSONArray as well as nested JSONObjects are supported, too. *

- * Validator offers two different modes to operate. By default strict mode is set and the validator will also check the exact amount of + * Validator offers two different modes to operate. By default, strict mode is set and the validator will also check the exact amount of * control object fields to match. No additional fields in received JSON data structure will be accepted. In soft mode validator * allows additional fields in received JSON data structure so the control JSON object can be a partial subset. * @@ -42,37 +42,27 @@ */ public class JsonTextMessageValidator extends AbstractMessageValidator { - /** - * Should also check exact amount of object fields - */ private boolean strict = JsonSettings.isStrict(); - /** - * Permissive mode to use on the Json parser - */ private int permissiveMode = JsonSettings.getPermissiveMoe(); - /** - * Schema validator - */ private JsonSchemaValidation jsonSchemaValidation = new JsonSchemaValidation(); private JsonElementValidator.Provider elementValidatorProvider = JsonElementValidator.Provider.DEFAULT; @Override - public void validateMessage( - Message receivedMessage, - Message controlMessage, - TestContext context, - JsonMessageValidationContext validationContext - ) { + public void validateMessage(Message receivedMessage, + Message controlMessage, + TestContext context, + JsonMessageValidationContext validationContext) { logger.debug("Start JSON message validation ..."); + if (validationContext.isSchemaValidationEnabled()) { jsonSchemaValidation.validate(receivedMessage, context, validationContext); } - String receivedJsonText = receivedMessage.getPayload(String.class); - String controlJsonText = context.replaceDynamicContentInString(controlMessage.getPayload(String.class)); + var receivedJsonText = receivedMessage.getPayload(String.class); + var controlJsonText = context.replaceDynamicContentInString(controlMessage.getPayload(String.class)); if (!hasText(controlJsonText)) { logger.debug("Skip message payload validation as no control message was defined"); @@ -81,9 +71,9 @@ public void validateMessage( throw new ValidationException("Validation failed - expected message contents, but received empty message!"); } - elementValidatorProvider.getValidator(strict, context, validationContext).validate( - parseJson(permissiveMode, receivedJsonText, controlJsonText) - ); + elementValidatorProvider.getValidator(strict, context, validationContext) + .validate(parseJson(permissiveMode, receivedJsonText, controlJsonText)); + logger.debug("JSON message validation successful: All values OK"); } @@ -97,41 +87,19 @@ public boolean supportsMessageType(String messageType, Message message) { return messageType.equalsIgnoreCase(JSON.name()) && hasJsonPayload(message); } - /** - * Set the validator strict mode. - * - * @param strict - */ public void setStrict(boolean strict) { this.strict = strict; } - /** - * Set the validator strict mode. - * - * @param strict - * @return this object for chaining - */ public JsonTextMessageValidator strict(boolean strict) { setStrict(strict); return this; } - /** - * Sets the json schema validation. - * - * @param jsonSchemaValidation - */ - void setJsonSchemaValidation(JsonSchemaValidation jsonSchemaValidation) { + public void setJsonSchemaValidation(JsonSchemaValidation jsonSchemaValidation) { this.jsonSchemaValidation = jsonSchemaValidation; } - /** - * Sets the json schema validation. - * - * @param jsonSchemaValidation - * @return this object for chaining - */ public JsonTextMessageValidator jsonSchemaValidation(JsonSchemaValidation jsonSchemaValidation) { setJsonSchemaValidation(jsonSchemaValidation); return this; @@ -146,21 +114,10 @@ public JsonTextMessageValidator elementValidatorProvider(JsonElementValidator.Pr return this; } - /** - * Sets the permissive mode. - * - * @param permissiveMode - */ public void setPermissiveMode(int permissiveMode) { this.permissiveMode = permissiveMode; } - /** - * Sets the permissive mode - * - * @param permissiveMode - * @return this object for chaining - */ public JsonTextMessageValidator permissiveMode(int permissiveMode) { setPermissiveMode(permissiveMode); return this; diff --git a/validation/citrus-validation-json/src/main/java/org/citrusframework/validation/json/schema/JsonSchemaValidation.java b/validation/citrus-validation-json/src/main/java/org/citrusframework/validation/json/schema/JsonSchemaValidation.java index d85a2d0f65..75cf64af1b 100644 --- a/validation/citrus-validation-json/src/main/java/org/citrusframework/validation/json/schema/JsonSchemaValidation.java +++ b/validation/citrus-validation-json/src/main/java/org/citrusframework/validation/json/schema/JsonSchemaValidation.java @@ -16,6 +16,8 @@ package org.citrusframework.validation.json.schema; +import static java.util.Collections.emptySet; + import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; import com.networknt.schema.ValidationMessage; @@ -41,27 +43,21 @@ /** * This class is responsible for the validation of json messages against json schemas / json schema repositories. + * * @since 2.7.3 */ public class JsonSchemaValidation implements SchemaValidator { private static final Logger logger = LoggerFactory.getLogger(JsonSchemaValidation.class); - private final JsonSchemaFilter jsonSchemaFilter; + private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper(); - /** Object Mapper to convert the message for validation*/ - private ObjectMapper objectMapper = new ObjectMapper(); + private final JsonSchemaFilter jsonSchemaFilter; - /** - * Default constructor using default filter. - */ public JsonSchemaValidation() { this(new JsonSchemaFilter()); } - /** - * Constructor using filter implementation. - */ public JsonSchemaValidation(JsonSchemaFilter jsonSchemaFilter) { this.jsonSchemaFilter = jsonSchemaFilter; } @@ -71,9 +67,9 @@ public void validate(Message message, TestContext context, JsonMessageValidation logger.debug("Starting Json schema validation ..."); GraciousProcessingReport report = validate(message, - findSchemaRepositories(context), - validationContext, - context.getReferenceResolver()); + findSchemaRepositories(context), + validationContext, + context.getReferenceResolver()); if (!report.isSuccess()) { logger.error("Failed to validate Json schema for message:\n{}", message.getPayload(String.class)); @@ -90,7 +86,7 @@ public void validate(Message message, TestContext context, JsonMessageValidation * @param report The report containing the error message * @return A string representation of all messages contained in the report */ - private String constructErrorMessage(GraciousProcessingReport report) { + protected String constructErrorMessage(GraciousProcessingReport report) { StringBuilder stringBuilder = new StringBuilder(); stringBuilder.append("Json validation failed: "); report.getValidationMessages().forEach(processingMessage -> stringBuilder.append("\n\t").append(processingMessage.getMessage())); @@ -114,9 +110,9 @@ private List findSchemaRepositories(TestContext context) { * @return A report holding the results of the validation */ public GraciousProcessingReport validate(Message message, - List schemaRepositories, - JsonMessageValidationContext validationContext, - ReferenceResolver referenceResolver) { + List schemaRepositories, + JsonMessageValidationContext validationContext, + ReferenceResolver referenceResolver) { return validate(message, jsonSchemaFilter.filter(schemaRepositories, validationContext, referenceResolver)); } @@ -147,15 +143,13 @@ private GraciousProcessingReport validate(Message message, List validate(Message message, SimpleJsonSchema simpleJsonSchema) { try { - JsonNode receivedJson = objectMapper.readTree(message.getPayload(String.class)); + JsonNode receivedJson = OBJECT_MAPPER.readTree(message.getPayload(String.class)); if (receivedJson.isEmpty()) { - return Collections.emptySet(); + return emptySet(); } else { return simpleJsonSchema.getSchema().validate( - objectMapper.readTree( - message.getPayload(String.class) - ) - ); + OBJECT_MAPPER.readTree( + message.getPayload(String.class))); } } catch (IOException e) { throw new CitrusRuntimeException("Failed to validate Json schema", e); @@ -172,6 +166,7 @@ private Set validate(Message message, SimpleJsonSchema simple */ @Override public boolean supportsMessageType(String messageType, Message message) { - return "JSON".equals(messageType) || (message != null && IsJsonPredicate.getInstance().test(message.getPayload(String.class))); + return "JSON".equals(messageType) + || (message != null && IsJsonPredicate.getInstance().test(message.getPayload(String.class))); } } diff --git a/validation/citrus-validation-json/src/test/java/org/citrusframework/validation/json/JsonTextMessageValidatorTest.java b/validation/citrus-validation-json/src/test/java/org/citrusframework/validation/json/JsonTextMessageValidatorTest.java index bfa61d66c8..df6aa948d0 100644 --- a/validation/citrus-validation-json/src/test/java/org/citrusframework/validation/json/JsonTextMessageValidatorTest.java +++ b/validation/citrus-validation-json/src/test/java/org/citrusframework/validation/json/JsonTextMessageValidatorTest.java @@ -16,7 +16,6 @@ package org.citrusframework.validation.json; -import net.minidev.json.parser.JSONParser; import net.minidev.json.parser.ParseException; import org.citrusframework.UnitTestSupport; import org.citrusframework.exceptions.CitrusRuntimeException; @@ -36,6 +35,8 @@ import java.util.List; import java.util.Set; +import static net.minidev.json.parser.JSONParser.MODE_JSON_SIMPLE; +import static net.minidev.json.parser.JSONParser.MODE_RFC4627; import static org.assertj.core.api.Assertions.*; import static org.mockito.Mockito.*; @@ -92,7 +93,7 @@ public void testUseSchemaRepositoryValidatorIfSchemaValidationIsEnabled() { JsonSchemaValidation jsonSchemaValidation = mock(JsonSchemaValidation.class); when(jsonSchemaValidation.validate(any(), anyList(), any(), any())).thenReturn(new GraciousProcessingReport((true))); - fixture.setJsonSchemaValidation(jsonSchemaValidation); + fixture.jsonSchemaValidation(jsonSchemaValidation); JsonSchemaRepository jsonSchemaRepository = mock(JsonSchemaRepository.class); context.getReferenceResolver().bind("jsonSchemaRepository", jsonSchemaRepository); @@ -124,7 +125,7 @@ public void shouldFindProperValidationContext() { @Test public void testPermissiveModeSimple() { - fixture.setPermissiveMode(JSONParser.MODE_JSON_SIMPLE); + fixture.permissiveMode(MODE_JSON_SIMPLE); var actualMessage = new DefaultMessage("{\"text\":\"Hello World!\",, \"index\":5, \"id\":\"x123456789x\",}"); var expectedMessage = new DefaultMessage("{\"text\":\"Hello World!\", \"index\":5, \"id\":\"x123456789x\"}"); @@ -152,7 +153,7 @@ public void shouldUseCustomElementValidator() { @Test public void testPermissiveModeStrict() { - fixture.setPermissiveMode(JSONParser.MODE_RFC4627); + fixture.permissiveMode(MODE_RFC4627); var actualMessage = new DefaultMessage("{\"text\":\"Hello World!\",, \"index\":5, \"id\":\"x123456789x\",}"); var expectedMessage = new DefaultMessage("{\"text\":\"Hello World!\", \"index\":5, \"id\":\"x123456789x\"}");