[OLINGO-1393]Validate the values for a Decimal data type as per latest spec
diff --git a/fit/src/test/java/org/apache/olingo/fit/tecsvc/client/BasicITCase.java b/fit/src/test/java/org/apache/olingo/fit/tecsvc/client/BasicITCase.java
index aa1fea5..1295c4d 100644
--- a/fit/src/test/java/org/apache/olingo/fit/tecsvc/client/BasicITCase.java
+++ b/fit/src/test/java/org/apache/olingo/fit/tecsvc/client/BasicITCase.java
@@ -1275,7 +1275,7 @@
entity.getProperties().add(getFactory().newPrimitiveProperty(PROPERTY_INT64,
getFactory().newPrimitiveValueBuilder().buildInt64(Long.MAX_VALUE)));
entity.getProperties().add(getFactory().newPrimitiveProperty(PROPERTY_DECIMAL,
- getFactory().newPrimitiveValueBuilder().buildDecimal(BigDecimal.valueOf(Long.MAX_VALUE))));
+ getFactory().newPrimitiveValueBuilder().buildDecimal(BigDecimal.valueOf(922337203685477L))));
final ODataEntityUpdateRequest<ClientEntity> requestUpdate = getEdmEnabledClient().getCUDRequestFactory()
.getEntityUpdateRequest(uri, UpdateType.PATCH, entity);
@@ -1292,7 +1292,7 @@
final ODataRetrieveResponse<ClientEntity> responseGet = requestGet.execute();
assertEquals(Long.MAX_VALUE, responseGet.getBody().getProperty(PROPERTY_INT64).getPrimitiveValue().toValue());
- assertEquals(BigDecimal.valueOf(Long.MAX_VALUE), responseGet.getBody().getProperty(PROPERTY_DECIMAL)
+ assertEquals(BigDecimal.valueOf(922337203685477L), responseGet.getBody().getProperty(PROPERTY_DECIMAL)
.getPrimitiveValue()
.toValue());
}
@@ -1395,7 +1395,7 @@
.add(getFactory().newPrimitiveProperty(PROPERTY_INT64,
getFactory().newPrimitiveValueBuilder().buildInt64(Long.MIN_VALUE)))
.add(getFactory().newPrimitiveProperty(PROPERTY_DECIMAL,
- getFactory().newPrimitiveValueBuilder().buildDecimal(BigDecimal.valueOf(12345678912L))))
+ getFactory().newPrimitiveValueBuilder().buildDecimal(BigDecimal.valueOf(123456.78912))))
.add(getFactory().newPrimitiveProperty(PROPERTY_INT16,
getFactory().newPrimitiveValueBuilder().buildInt16((short) 2)))));
@@ -1413,7 +1413,7 @@
final ClientComplexValue complexValue = responseGet.getBody().getComplexValue();
assertEquals(Long.MIN_VALUE, complexValue.get(PROPERTY_INT64).getPrimitiveValue().toValue());
- assertEquals(BigDecimal.valueOf(12345678912L), complexValue.get(PROPERTY_DECIMAL).getPrimitiveValue().toValue());
+ assertEquals(BigDecimal.valueOf(123456.78912), complexValue.get(PROPERTY_DECIMAL).getPrimitiveValue().toValue());
assertEquals(2, complexValue.get(PROPERTY_INT16).getPrimitiveValue().toValue());
}
@@ -1428,7 +1428,7 @@
final ODataPropertyUpdateRequest requestUpdate = getEdmEnabledClient().getCUDRequestFactory()
.getPropertyPrimitiveValueUpdateRequest(uri,
getFactory().newPrimitiveProperty(PROPERTY_DECIMAL,
- getFactory().newPrimitiveValueBuilder().buildInt64(Long.MAX_VALUE)));
+ getFactory().newPrimitiveValueBuilder().buildInt64(922337203685477L)));
requestUpdate.setContentType(CONTENT_TYPE_JSON_IEEE754_COMPATIBLE);
requestUpdate.setAccept(CONTENT_TYPE_JSON_IEEE754_COMPATIBLE);
@@ -1441,7 +1441,7 @@
requestGet.setAccept(CONTENT_TYPE_JSON_IEEE754_COMPATIBLE);
final ODataRetrieveResponse<ClientProperty> responseGet = requestGet.execute();
- assertEquals(BigDecimal.valueOf(Long.MAX_VALUE), responseGet.getBody().getPrimitiveValue().toValue());
+ assertEquals(BigDecimal.valueOf(922337203685477L), responseGet.getBody().getPrimitiveValue().toValue());
}
@Test
diff --git a/lib/commons-api/src/main/java/org/apache/olingo/commons/api/edm/EdmPrimitiveType.java b/lib/commons-api/src/main/java/org/apache/olingo/commons/api/edm/EdmPrimitiveType.java
index 8e4b6b5..ebe9cd7 100644
--- a/lib/commons-api/src/main/java/org/apache/olingo/commons/api/edm/EdmPrimitiveType.java
+++ b/lib/commons-api/src/main/java/org/apache/olingo/commons/api/edm/EdmPrimitiveType.java
@@ -72,7 +72,7 @@
public interface EdmPrimitiveType extends EdmType {
String EDM_NAMESPACE = "Edm";
-
+
/**
* Checks type compatibility.
*
@@ -164,4 +164,20 @@
* @throws EdmPrimitiveTypeException if a required prefix or required surrounding quotation marks are missing
*/
String fromUriLiteral(String literal) throws EdmPrimitiveTypeException;
+
+ /**
+ * Validates literal value for Decimal values in V4.01
+ *
+ * @param value the literal value
+ * @param isNullable whether the <code>null</code> value is allowed
+ * @param maxLength the maximum length
+ * @param precision the precision
+ * @param scale the scale (could be variable or floating)
+ * @param isUnicode whether non-ASCII characters are allowed (relevant only for Edm.String)
+ * @return <code>true</code> if the validation is successful
+ */
+ default boolean validateDecimals(String value, Boolean isNullable, Integer maxLength,
+ Integer precision, String scale, Boolean isUnicode) {
+ return false;
+ }
}
diff --git a/lib/commons-core/src/main/java/org/apache/olingo/commons/core/edm/primitivetype/EdmDecimal.java b/lib/commons-core/src/main/java/org/apache/olingo/commons/core/edm/primitivetype/EdmDecimal.java
index 8b9f8f9..e177d7d 100644
--- a/lib/commons-core/src/main/java/org/apache/olingo/commons/core/edm/primitivetype/EdmDecimal.java
+++ b/lib/commons-core/src/main/java/org/apache/olingo/commons/core/edm/primitivetype/EdmDecimal.java
@@ -83,8 +83,65 @@
}
final int significantIntegerDigits = "0".equals(matcher.group(1)) ? 0 : matcher.group(1).length();
final int decimals = matcher.group(2) == null ? 0 : matcher.group(2).length();
- return (precision == null || precision >= significantIntegerDigits + decimals)
- && (decimals <= (scale == null ? 0 : scale));
+ return (precision == null || (significantIntegerDigits >= 0 &&
+ significantIntegerDigits <= precision - ((scale == null) ? 0 : scale))) &&
+ (decimals >= 0 && decimals <= ((scale == null) ? 0 : scale));
+ }
+
+ @Override
+ public boolean validateDecimals(final String value,
+ final Boolean isNullable, final Integer maxLength, final Integer precision,
+ final String scale, final Boolean isUnicode) {
+
+ return value == null
+ ? isNullable == null || isNullable
+ : validateLiteral(value) && validatePrecisionAndScale(value, precision, scale);
+ }
+
+ private boolean validatePrecisionAndScale(String value, Integer precision, String scale) {
+ Matcher matcher = PATTERN.matcher(value);
+ matcher.matches();
+ if (matcher.group(3) != null) {
+ String plainValue = new BigDecimal(value).toPlainString();
+ matcher = PATTERN.matcher(plainValue);
+ matcher.matches();
+ }
+ int significantIntegerDigits = "0".equals(matcher.group(1)) ? 0 : matcher.group(1).length();
+ int decimals = matcher.group(2) == null ? 0 : matcher.group(2).length();
+
+ try {
+ int scaleValue = (scale == null) ? 0 : Integer.parseInt(scale);
+ return (precision == null || (significantIntegerDigits >= 0 &&
+ significantIntegerDigits <= precision - scaleValue)) &&
+ (decimals >= 0 && decimals <= scaleValue);
+ } catch(NumberFormatException e) {
+ String scaleValue = (scale == null) ? String.valueOf(0) : scale;
+ if (scaleValue.equals("variable")) {
+ return (precision == null ||
+ (significantIntegerDigits >= 0 &&
+ (significantIntegerDigits <= precision - decimals))) &&
+ (decimals >= 0 && decimals <= ((precision == null) ? 0 : precision));
+ } else if (scaleValue.equals("floating")) {
+ Matcher matcher1 = PATTERN.matcher(value);
+ matcher1.matches();
+ significantIntegerDigits = "0".equals(matcher1.group(1)) ? 0 : matcher1.group(1).length();
+ decimals = matcher1.group(2) == null ? 0 : matcher1.group(2).length();
+ int exponents = 0;
+ if (matcher1.group(3) != null) {
+ exponents = Integer.parseInt(matcher1.group(3).substring(1));
+ if (exponents < -95 || exponents > 96) {
+ if (String.valueOf(exponents).startsWith("-")) {
+ significantIntegerDigits += Integer.parseInt(String.valueOf(exponents + 95).substring(1));
+ exponents = -95;
+ }
+ }
+ return (significantIntegerDigits + decimals) <= 7 && (exponents >= -95 && exponents <= 96);
+ }
+ } else {
+ return false;
+ }
+ }
+ return false;
}
@Override
diff --git a/lib/commons-core/src/test/java/org/apache/olingo/commons/core/edm/primitivetype/EdmDecimalTest.java b/lib/commons-core/src/test/java/org/apache/olingo/commons/core/edm/primitivetype/EdmDecimalTest.java
index 3fb1c34..14ec110 100644
--- a/lib/commons-core/src/test/java/org/apache/olingo/commons/core/edm/primitivetype/EdmDecimalTest.java
+++ b/lib/commons-core/src/test/java/org/apache/olingo/commons/core/edm/primitivetype/EdmDecimalTest.java
@@ -19,6 +19,7 @@
package org.apache.olingo.commons.core.edm.primitivetype;
import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import java.math.BigDecimal;
@@ -97,11 +98,10 @@
assertEquals(Double.valueOf(0.5), instance.valueOfString("0.5", null, null, 1, 1, null, Double.class));
assertEquals(Float.valueOf(0.5F), instance.valueOfString("0.5", null, null, null, 1, null, Float.class));
assertEquals(new BigDecimal("12.3"), instance.valueOfString("12.3", null, null, 3, 1, null, BigDecimal.class));
- assertEquals(new BigDecimal("31991163"), instance.valueOfString("3.1991163E7", null, null, 8, 7,
- null, BigDecimal.class));
assertEquals(new BigDecimal("31991163.34"),
instance.valueOfString("3.199116334E7", null, null, 10, 2, null, BigDecimal.class));
+ expectFacetsErrorInValueOfString(instance, "3.1991163E7", null, 8, 7, null, null);
expectFacetsErrorInValueOfString(instance, "0.5", null, null, null, null, null);
expectFacetsErrorInValueOfString(instance, "-1234", null, null, 2, null, null);
expectFacetsErrorInValueOfString(instance, "1234", null, null, 3, null, null);
@@ -110,6 +110,9 @@
expectFacetsErrorInValueOfString(instance, "12.34", null, null, 4, 1, null);
expectFacetsErrorInValueOfString(instance, "0.00390625", null, null, 5, null, null);
expectFacetsErrorInValueOfString(instance, "0.00390625", null, null, null, 7, null);
+ expectFacetsErrorInValueOfString(instance, "-129", null, null, Integer.MAX_VALUE, Integer.MAX_VALUE, null);
+ expectFacetsErrorInValueOfString(instance, "-32769", null, null, Integer.MAX_VALUE, Integer.MAX_VALUE, null);
+ expectFacetsErrorInValueOfString(instance, "32768", null, null, Integer.MAX_VALUE, Integer.MAX_VALUE, null);
expectContentErrorInValueOfString(instance, "1.");
expectContentErrorInValueOfString(instance, ".1");
@@ -117,10 +120,6 @@
expectContentErrorInValueOfString(instance, "1M");
expectContentErrorInValueOfString(instance, "0x42");
- expectUnconvertibleErrorInValueOfString(instance, "-129", Byte.class);
- expectUnconvertibleErrorInValueOfString(instance, "128", Byte.class);
- expectUnconvertibleErrorInValueOfString(instance, "-32769", Short.class);
- expectUnconvertibleErrorInValueOfString(instance, "32768", Short.class);
expectUnconvertibleErrorInValueOfString(instance, "-2147483649", Integer.class);
expectUnconvertibleErrorInValueOfString(instance, "2147483648", Integer.class);
expectUnconvertibleErrorInValueOfString(instance, "-9223372036854775809", Long.class);
@@ -130,4 +129,84 @@
expectTypeErrorInValueOfString(instance, "1");
}
+
+ @Test
+ public void validateDecimal() throws Exception {
+ assertFalse(EdmPrimitiveTypeFactory.getInstance(EdmPrimitiveTypeKind.Decimal).
+ validate("3.1991163E7", null, null, 8, 7, null));
+ assertTrue(EdmPrimitiveTypeFactory.getInstance(EdmPrimitiveTypeKind.Decimal).
+ validate("1", null, null, null, null, null));
+ assertFalse(EdmPrimitiveTypeFactory.getInstance(EdmPrimitiveTypeKind.Decimal).
+ validate("1.2", null, null, null, 0, null));
+ assertFalse(EdmPrimitiveTypeFactory.getInstance(EdmPrimitiveTypeKind.Decimal).
+ validate("10.2", false, null, 3, 2, null));
+ assertTrue(EdmPrimitiveTypeFactory.getInstance(EdmPrimitiveTypeKind.Decimal).
+ validate("1.2", false, null, 3, 2, null));
+ assertTrue(EdmPrimitiveTypeFactory.getInstance(EdmPrimitiveTypeKind.Decimal).
+ validate("0.12", false, null, 3, 2, null));
+ assertTrue(EdmPrimitiveTypeFactory.getInstance(EdmPrimitiveTypeKind.Decimal).
+ validate("1.23", false, null, 3, 2, null));
+ assertTrue(EdmPrimitiveTypeFactory.getInstance(EdmPrimitiveTypeKind.Decimal).
+ validate("1.03", false, null, 3, 2, null));
+ assertFalse(EdmPrimitiveTypeFactory.getInstance(EdmPrimitiveTypeKind.Decimal).
+ validate("1.03", false, null, 3, null, null));
+ assertTrue(EdmPrimitiveTypeFactory.getInstance(EdmPrimitiveTypeKind.Decimal).
+ validate("12", false, null, 3, null, null));
+ assertTrue(EdmPrimitiveTypeFactory.getInstance(EdmPrimitiveTypeKind.Decimal).
+ validate("12", false, null, null, 2, null));
+ assertTrue(EdmPrimitiveTypeFactory.getInstance(EdmPrimitiveTypeKind.Decimal).
+ validate("0.12", false, null, null, 2, null));
+ assertTrue(EdmPrimitiveTypeFactory.getInstance(EdmPrimitiveTypeKind.Decimal).
+ validate("12", false, null, null, null, null));
+ assertFalse(EdmPrimitiveTypeFactory.getInstance(EdmPrimitiveTypeKind.Decimal).
+ validate("0.12", false, null, null, null, null));
+ assertTrue(EdmPrimitiveTypeFactory.getInstance(EdmPrimitiveTypeKind.Decimal).
+ validate("0.23", false, null, 2, 2, null));
+ assertTrue(EdmPrimitiveTypeFactory.getInstance(EdmPrimitiveTypeKind.Decimal).
+ validate("0.7", false, null, 2, 2, null));
+ assertFalse(EdmPrimitiveTypeFactory.getInstance(EdmPrimitiveTypeKind.Decimal).
+ validate("12e-101", false, null, 2, 2, null));
+ assertFalse(EdmPrimitiveTypeFactory.getInstance(EdmPrimitiveTypeKind.Decimal).
+ validate("12e101", false, null, 2, 2, null));
+ assertTrue(EdmPrimitiveTypeFactory.getInstance(EdmPrimitiveTypeKind.Decimal).
+ validate("-1.234567e3", false, null, 7, 3, null));
+ assertFalse(EdmPrimitiveTypeFactory.getInstance(EdmPrimitiveTypeKind.Decimal).
+ validate("0.7", false, null, 2, 3, null));
+ }
+
+ @Test
+ public void validateDecimalInV401() throws Exception {
+ assertTrue(EdmPrimitiveTypeFactory.getInstance(EdmPrimitiveTypeKind.Decimal).
+ validateDecimals("0.123", null, null, 3, "variable", null));
+ assertTrue(EdmPrimitiveTypeFactory.getInstance(EdmPrimitiveTypeKind.Decimal).
+ validateDecimals("1.23", null, null, 3, "variable", null));
+ assertTrue(EdmPrimitiveTypeFactory.getInstance(EdmPrimitiveTypeKind.Decimal).
+ validateDecimals("0.23", null, null, 3, "variable", null));
+ assertTrue(EdmPrimitiveTypeFactory.getInstance(EdmPrimitiveTypeKind.Decimal).
+ validateDecimals("0.7", null, null, 3, "variable", null));
+ assertTrue(EdmPrimitiveTypeFactory.getInstance(EdmPrimitiveTypeKind.Decimal).
+ validateDecimals("123", null, null, 3, "variable", null));
+ assertTrue(EdmPrimitiveTypeFactory.getInstance(EdmPrimitiveTypeKind.Decimal).
+ validateDecimals("12.3", null, null, 3, "variable", null));
+ assertFalse(EdmPrimitiveTypeFactory.getInstance(EdmPrimitiveTypeKind.Decimal).
+ validateDecimals("12.34", null, null, 3, "variable", null));
+ assertFalse(EdmPrimitiveTypeFactory.getInstance(EdmPrimitiveTypeKind.Decimal).
+ validateDecimals("1234", null, null, 3, "variable", null));
+ assertFalse(EdmPrimitiveTypeFactory.getInstance(EdmPrimitiveTypeKind.Decimal).
+ validateDecimals("123.4", null, null, 3, "variable", null));
+ assertFalse(EdmPrimitiveTypeFactory.getInstance(EdmPrimitiveTypeKind.Decimal).
+ validateDecimals("123.4", null, null, null, "variable", null));
+
+ assertTrue(EdmPrimitiveTypeFactory.getInstance(EdmPrimitiveTypeKind.Decimal).
+ validateDecimals("-1.234567e3", null, null, 7, "floating", null));
+ assertTrue(EdmPrimitiveTypeFactory.getInstance(EdmPrimitiveTypeKind.Decimal).
+ validateDecimals("1e-101", null, null, 7, "floating", null));
+ assertTrue(EdmPrimitiveTypeFactory.getInstance(EdmPrimitiveTypeKind.Decimal).
+ validateDecimals("9.999999e96", null, null, 7, "floating", null));
+ assertFalse(EdmPrimitiveTypeFactory.getInstance(EdmPrimitiveTypeKind.Decimal).
+ validateDecimals("1e-102", null, null, 7, "floating", null));
+ assertFalse(EdmPrimitiveTypeFactory.getInstance(EdmPrimitiveTypeKind.Decimal).
+ validateDecimals("1e97", null, null, 7, "floating", null));
+
+ }
}
diff --git a/lib/commons-core/src/test/java/org/apache/olingo/commons/core/edm/primitivetype/PrimitiveTypeBaseTest.java b/lib/commons-core/src/test/java/org/apache/olingo/commons/core/edm/primitivetype/PrimitiveTypeBaseTest.java
index 40152c9..5d5851c 100644
--- a/lib/commons-core/src/test/java/org/apache/olingo/commons/core/edm/primitivetype/PrimitiveTypeBaseTest.java
+++ b/lib/commons-core/src/test/java/org/apache/olingo/commons/core/edm/primitivetype/PrimitiveTypeBaseTest.java
@@ -85,7 +85,7 @@
protected void expectUnconvertibleErrorInValueOfString(final EdmPrimitiveType instance, final String value,
final Class<?> type) {
- expectErrorInValueOfString(instance, value, true, Integer.MAX_VALUE, Integer.MAX_VALUE, Integer.MAX_VALUE, true,
+ expectErrorInValueOfString(instance, value, true, Integer.MAX_VALUE, Integer.MAX_VALUE, null, true,
type, "cannot be converted to");
}