Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix/#160 max value float #164

Merged
merged 8 commits into from
Jun 14, 2019
2 changes: 1 addition & 1 deletion pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@
</distributionManagement>
<properties>
<java.version>1.8</java.version>
<java.testversion>1.7</java.testversion>
<java.testversion>1.8</java.testversion>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<version.jackson>2.9.9</version.jackson>
<version.slf4j>1.7.25</version.slf4j>
Expand Down
41 changes: 13 additions & 28 deletions src/main/java/com/networknt/schema/MaximumValidator.java
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.Collections;
import java.util.Set;
Expand All @@ -33,7 +34,7 @@ public class MaximumValidator extends BaseJsonValidator implements JsonValidator
private final ThresholdMixin typedMaximum;


public MaximumValidator(String schemaPath, JsonNode schemaNode, JsonSchema parentSchema, ValidationContext validationContext) {
public MaximumValidator(String schemaPath, final JsonNode schemaNode, JsonSchema parentSchema, ValidationContext validationContext) {
super(schemaPath, schemaNode, parentSchema, ValidatorTypeCode.MAXIMUM, validationContext);

if (!schemaNode.isNumber()) {
Expand All @@ -47,33 +48,16 @@ public MaximumValidator(String schemaPath, JsonNode schemaNode, JsonSchema paren

parseErrorCode(getValidatorType().getErrorCodeKey());

if (!JsonType.INTEGER.toString().equals(getNodeFieldType())) {
// "number" or no type
// by default treat value as double: compatible with previous behavior
final double dm = schemaNode.doubleValue();
typedMaximum = new ThresholdMixin() {
@Override
public boolean crossesThreshold(JsonNode node) {
double value = node.asDouble();
return greaterThan(value, dm) || (excludeEqual && MaximumValidator.this.equals(value, dm));
}

@Override
public String thresholdValue() {
return String.valueOf(dm);
}
};

} else if ( schemaNode.isLong() || schemaNode.isInt() ) {
if (( schemaNode.isLong() || schemaNode.isInt() ) && (JsonType.INTEGER.toString().equals(getNodeFieldType()))) {
// "integer", and within long range
final long lm = schemaNode.asLong();
typedMaximum = new ThresholdMixin() {
@Override
public boolean crossesThreshold(JsonNode node) {
long val = node.asLong();
if(node.isBigInteger()) {
if (node.isBigInteger()) {
//node.isBigInteger is not trustable, the type BigInteger doesn't mean it is a big number.
if(node.bigIntegerValue().compareTo(new BigInteger(String.valueOf(Long.MAX_VALUE))) > 0) {
if (node.bigIntegerValue().compareTo(new BigInteger(String.valueOf(Long.MAX_VALUE))) > 0) {
return true;
}
}
Expand All @@ -85,20 +69,22 @@ public String thresholdValue() {
return String.valueOf(lm);
}
};

} else {
// "integer" outside long range
final BigInteger bim = new BigInteger(schemaNode.asText());
typedMaximum = new ThresholdMixin() {
@Override
public boolean crossesThreshold(JsonNode node) {
int cmp = bim.compareTo(node.bigIntegerValue());
return cmp < 0 || (excludeEqual && cmp <= 0);
if(schemaNode.doubleValue() == Double.POSITIVE_INFINITY) {
return false;
}
final BigDecimal max = new BigDecimal(schemaNode.asText());
if(node.doubleValue() == Double.POSITIVE_INFINITY) {return true;}
BigDecimal value = new BigDecimal(node.asText());
return value.compareTo(max) > 0 || (excludeEqual && value.compareTo(max) == 0);
}

@Override
public String thresholdValue() {
return String.valueOf(bim);
return schemaNode.asText();
}
};
}
Expand All @@ -117,5 +103,4 @@ public Set<ValidationMessage> validate(JsonNode node, JsonNode rootNode, String
}
return Collections.emptySet();
}

}
33 changes: 10 additions & 23 deletions src/main/java/com/networknt/schema/MinimumValidator.java
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.Collections;
import java.util.Set;
Expand Down Expand Up @@ -50,24 +51,7 @@ public MinimumValidator(String schemaPath, JsonNode schemaNode, JsonSchema paren

parseErrorCode(getValidatorType().getErrorCodeKey());

if (!JsonType.INTEGER.toString().equals(getNodeFieldType())) {
// "number" or no type
// by default treat value as double: compatible with previous behavior
final double dmin = schemaNode.doubleValue();
typedMinimum = new ThresholdMixin() {
@Override
public boolean crossesThreshold(JsonNode node) {
double value = node.asDouble();
return lessThan(value, dmin) || (excluded && MinimumValidator.this.equals(value, dmin));
}

@Override
public String thresholdValue() {
return String.valueOf(dmin);
}
};

} else if ( schemaNode.isLong() || schemaNode.isInt() ) {
if ( schemaNode.isLong() || schemaNode.isInt() && JsonType.INTEGER.toString().equals(getNodeFieldType())) {
// "integer", and within long range
final long lmin = schemaNode.asLong();
typedMinimum = new ThresholdMixin() {
Expand All @@ -90,18 +74,21 @@ public String thresholdValue() {
};

} else {
// "integer" outside long range
final BigInteger bimin = new BigInteger(schemaNode.asText());
typedMinimum = new ThresholdMixin() {
@Override
public boolean crossesThreshold(JsonNode node) {
int cmp = bimin.compareTo(node.bigIntegerValue());
return cmp > 0 || (excluded && cmp >= 0);
if(schemaNode.doubleValue() == Double.NEGATIVE_INFINITY) {
return false;
}
final BigDecimal min = new BigDecimal(schemaNode.asText());
if(node.doubleValue() == Double.NEGATIVE_INFINITY) {return true;}
BigDecimal value = new BigDecimal(node.asText());
return value.compareTo(min) < 0 || (excluded && value.compareTo(min) == 0);
}

@Override
public String thresholdValue() {
return String.valueOf(bimin);
return schemaNode.asText();
}
};
}
Expand Down
63 changes: 63 additions & 0 deletions src/test/java/com/networknt/schema/MaximumValidatorPerfTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
package com.networknt.schema;

import org.junit.Ignore;
import org.junit.Test;

import java.lang.annotation.Annotation;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
@Ignore
public class MaximumValidatorPerfTest {
MaximumValidatorTest test = new MaximumValidatorTest();

@Test
public void testTime() throws InvocationTargetException, IllegalAccessException {
test.setUp();
String[] testMethodsToBeExecuted = {"testMaximumDoubleValue"};
List<Method> testMethods = getTestMethods(testMethodsToBeExecuted);
long start = System.currentTimeMillis();
executeTests(testMethods, 200000);
BalloonWen marked this conversation as resolved.
Show resolved Hide resolved
long end = System.currentTimeMillis();
System.out.println("time to execute all tests using:" + (end - start) +"ms");
}

public void executeTests(List<Method> methods, int executeTimes) throws InvocationTargetException, IllegalAccessException {

for(int i = 0; i < executeTimes; i++) {
for(Method testMethod : methods) {
testMethod.invoke(test);
}
}

}

public List<Method> getTestMethods(String[] methodNames) {
Method[] methods = test.getClass().getMethods();
List<Method> testMethods = new ArrayList<Method>();
if(methodNames.length > 0) {
for(String name : methodNames) {
testMethods.addAll(Arrays.stream(methods).filter(m -> m.getName().equals(name)).collect(Collectors.toList()));
}
return testMethods;
}
for (Method m : methods) {
Annotation[] annotations = m.getDeclaredAnnotations();
boolean isTestMethod = false;
for(Annotation annotation : annotations) {
if(annotation.annotationType() == Test.class) {
isTestMethod = true;
}
}
if(isTestMethod) {
//filter out incompatible test cases.
if(!m.getName().equals("doubleValueCoarsing") && !m.getName().equals("negativeDoubleOverflowTest"))
testMethods.add(m);
}
}
return testMethods;
}
}
Loading