Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
import com.github.benmanes.caffeine.cache.Caffeine;
import com.github.benmanes.caffeine.cache.LoadingCache;
import com.networknt.schema.Error;
import com.networknt.schema.InputFormat;
import com.networknt.schema.InvalidSchemaException;
import com.networknt.schema.SchemaRegistry;
import com.networknt.schema.SchemaRegistryConfig;
Expand All @@ -41,6 +42,7 @@
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.io.IOException;
import java.io.UncheckedIOException;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeParseException;
Expand Down Expand Up @@ -142,7 +144,7 @@ public SchemaValidator(@Nonnull final OpenAPI api,
key.forResponse,
definitions
);
return schemaRegistry.getSchema(schemaObject);
return schemaRegistry.getSchema(writeAsString(schemaObject), InputFormat.JSON);
});
} else {
this.jsonSchemaCache = null;
Expand Down Expand Up @@ -239,7 +241,8 @@ public ValidationReport validate(@Nonnull final JsonNodeSupplier supplier,

try {
final com.networknt.schema.Schema resolvedJsonSchema = resolveJsonSchema(schema, keyPrefix);
final List<Error> validationMessages = resolvedJsonSchema.validate(supplier.get());
final List<Error> validationMessages =
resolvedJsonSchema.validate(writeAsString(supplier.get()), InputFormat.JSON);
return messageConverter.toValidationReport(validationMessages, keyPrefix);
} catch (final InvalidSchemaException e) {
return ValidationReport.singleton(
Expand All @@ -265,7 +268,7 @@ private com.networknt.schema.Schema resolveJsonSchema(final Schema<?> schema,
return jsonSchemaCache.get(jsonSchemaKey);
}
final JsonNode schemaObject = readAndTransformSchemaObject(schema, forRequest, forResponse, definitions);
return schemaRegistry.getSchema(schemaObject);
return schemaRegistry.getSchema(writeAsString(schemaObject), InputFormat.JSON);
} catch (final Exception e) {
// TODO: Need to handle this exception
throw new RuntimeException("JsonSchema construction failed", e);
Expand Down Expand Up @@ -294,6 +297,22 @@ private JsonNode readAndTransformSchemaObject(final Schema<?> schema,
return schemaObject;
}

/**
* Serialize a (Jackson 2) JSON node to a JSON string.
* <p>
* swagger-core / swagger-parser produce Jackson 2 nodes, whereas networknt 3.x consumes Jackson 3.
* Rather than leak Jackson 2 nodes into networknt (which removed the Jackson 2 node overloads),
* the schema and the instance being validated are handed to networknt as JSON text via its
* {@link InputFormat#JSON} entry points.
*/
private String writeAsString(final JsonNode node) {
try {
return (isOpenApi30 ? Json.mapper() : Json31.mapper()).writeValueAsString(node);
} catch (final IOException e) {
throw new UncheckedIOException("Failed to serialize JSON node", e);
}
}

private boolean additionalPropertiesValidationEnabled() {
return !messages.isIgnored(ADDITIONAL_PROPERTIES_KEY);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
package com.atlassian.oai.validator.schema.format;

import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.node.NumericNode;
import com.networknt.schema.ExecutionContext;
import com.networknt.schema.SchemaContext;
import com.networknt.schema.format.Format;
import com.networknt.schema.utils.JsonType;
import com.networknt.schema.utils.TypeFactory;
import tools.jackson.databind.JsonNode;
import tools.jackson.databind.node.NumericNode;

import java.math.BigDecimal;

Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
package com.atlassian.oai.validator.schema.format;

import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.node.NumericNode;
import com.networknt.schema.ExecutionContext;
import com.networknt.schema.SchemaContext;
import com.networknt.schema.format.Format;
import com.networknt.schema.utils.JsonType;
import com.networknt.schema.utils.TypeFactory;
import tools.jackson.databind.JsonNode;
import tools.jackson.databind.node.NumericNode;

import java.math.BigDecimal;

public class FloatFormat implements Format {
@Override
Expand All @@ -33,8 +35,15 @@ public boolean matches(final ExecutionContext executionContext, final SchemaCont
return false;
}

final float f = numericValue.floatValue();
final String original = String.valueOf(numericValue.decimalValue());
final BigDecimal dec = numericValue.decimalValue();
// Derive the float from the decimal: BigDecimal#floatValue() yields Infinity on overflow,
// whereas NumericNode#floatValue() throws in Jackson 3 when the value is out of float range.
final float f = dec.floatValue();
if (Float.isInfinite(f) || Float.isNaN(f)) {
return false;
}

final String original = String.valueOf(dec);
final String parsed = String.valueOf(f);

return original.equals(parsed);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
package com.atlassian.oai.validator.schema.format;

import com.fasterxml.jackson.databind.JsonNode;
import com.networknt.schema.ExecutionContext;
import com.networknt.schema.SchemaContext;
import com.networknt.schema.format.Format;
import com.networknt.schema.utils.JsonType;
import com.networknt.schema.utils.TypeFactory;
import tools.jackson.databind.JsonNode;

public class Int32Format implements Format {
@Override
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
package com.atlassian.oai.validator.schema.format;

import com.fasterxml.jackson.databind.JsonNode;
import com.networknt.schema.ExecutionContext;
import com.networknt.schema.SchemaContext;
import com.networknt.schema.format.Format;
import com.networknt.schema.utils.JsonType;
import com.networknt.schema.utils.TypeFactory;
import tools.jackson.databind.JsonNode;

public class Int64Format implements Format {
@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -136,7 +136,7 @@ private static void removeTypeObjectAssociationWithOneOfAndAnyOfFromSchema(@Nonn
* Removes the Base64 pattern on the {@link OpenAPI} model.
* <p>
* If that pattern would stay on the model all fields of type string / byte would be validated twice. Once
* with the {@link com.networknt.schema.PatternValidator} and once with
* with the {@link com.networknt.schema.keyword.PatternValidator} and once with
* the {@link com.atlassian.oai.validator.schema.format.Base64Format}.
* To improve validation performance and memory footprint the pattern on string / byte fields will be
* removed - so the PatternValidator will not be triggered for those kind of fields.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -165,8 +165,11 @@ public void validate_withInvalidDoubleFormat_shouldFail() {
final String value = "1" + Double.MAX_VALUE;
final Schema schema = new NumberSchema().format("double");

// A value outside the double range cannot be represented as a JSON number that the
// validator accepts: networknt 3.x rejects it as a type error ("number expected") before
// the custom double-format validator is reached. The value is still rejected.
assertFailWithoutContext(classUnderTest.validate(value, schema, "prefix"),
"validation.prefix.schema.format.double");
"validation.prefix.schema.type");
}

@Test
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package com.atlassian.oai.validator.v31analysis;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.networknt.schema.InputFormat;
import com.networknt.schema.SchemaRegistry;
import com.networknt.schema.dialect.Dialects;
import org.junit.jupiter.api.Test;
Expand All @@ -19,13 +19,11 @@ public class NetworkntDirectProbeTest {

private static final Logger LOG = LoggerFactory.getLogger(NetworkntDirectProbeTest.class);

private static final ObjectMapper MAPPER = new ObjectMapper();
private static final SchemaRegistry REGISTRY = SchemaRegistry.withDefaultDialect(Dialects.getOpenApi31());

private static int validate(final String schemaJson, final String input) throws Exception {
final var schema = REGISTRY.getSchema(schemaJson);
final var node = MAPPER.readTree(input);
final var errs = schema.validate(node);
final var errs = schema.validate(input, InputFormat.JSON);
errs.forEach(e -> LOG.error(" - {}", e));
return errs.size();
}
Expand Down Expand Up @@ -138,8 +136,7 @@ void discriminator_with_mapping_via_oas31_metaschema() throws Exception {
+ "}";

final var s = REGISTRY.getSchema(schema);
final var node = MAPPER.readTree("{\"kind\":\"circle\",\"radius\":5}");
final var errs = s.validate(node);
final var errs = s.validate("{\"kind\":\"circle\",\"radius\":5}", InputFormat.JSON);
errs.forEach(e -> LOG.error(" - {}", e));
LOG.error("[direct/discriminator+mapping circle] errors: {}", errs.size());
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package com.atlassian.oai.validator.v31analysis;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.networknt.schema.InputFormat;
import com.networknt.schema.SchemaRegistry;
import com.networknt.schema.dialect.Dialects;
import org.junit.jupiter.api.Test;
Expand All @@ -14,15 +14,13 @@
public class UnevaluatedDeepProbeTest {

private static final Logger LOG = LoggerFactory.getLogger(UnevaluatedDeepProbeTest.class);
private static final ObjectMapper MAPPER = new ObjectMapper();

private static int run(final String label,
final SchemaRegistry registry,
final String schemaJson,
final String input) throws Exception {
final var schema = registry.getSchema(schemaJson);
final var node = MAPPER.readTree(input);
final var errs = schema.validate(node);
final var errs = schema.validate(input, InputFormat.JSON);
LOG.error("[{}] errors: {}", label, errs.size());
errs.forEach(e -> LOG.error(" - {}", e));
return errs.size();
Expand Down
12 changes: 11 additions & 1 deletion pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,10 @@
<hamcrest.version>3.0</hamcrest.version>
<hamcrest-optional.version>1.3.2</hamcrest-optional.version>
<jackson.version>2.21.3</jackson.version>
<networknt-validator.version>2.0.1</networknt-validator.version>
<!-- Jackson 3 is consumed by networknt json-schema-validator 3.x and referenced directly
by the custom Format validators. Keep aligned with the version networknt depends on. -->
<jackson3.version>3.1.1</jackson3.version>
<networknt-validator.version>3.0.4</networknt-validator.version>
<jsr305.version>3.0.2</jsr305.version>
<logback.version>1.5.32</logback.version>
<mockito.version>5.23.0</mockito.version>
Expand Down Expand Up @@ -375,6 +378,13 @@
<scope>import</scope>
<type>pom</type>
</dependency>
<dependency>
<groupId>tools.jackson</groupId>
<artifactId>jackson-bom</artifactId>
<version>${jackson3.version}</version>
<scope>import</scope>
<type>pom</type>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
Expand Down