You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@nifi.apache.org by jo...@apache.org on 2017/06/02 14:09:53 UTC
nifi git commit: NIFI-3989: This closes #1869. Avoid calling
Long.parseLong,
etc. in order to determine if a String is a valid number because we don't want
the Exceptions that occur if it is not
Repository: nifi
Updated Branches:
refs/heads/master 37be0b982 -> 239bbfbb9
NIFI-3989: This closes #1869. Avoid calling Long.parseLong, etc. in order to determine if a String is a valid number because we don't want the Exceptions that occur if it is not
Signed-off-by: joewitt <jo...@apache.org>
Project: http://git-wip-us.apache.org/repos/asf/nifi/repo
Commit: http://git-wip-us.apache.org/repos/asf/nifi/commit/239bbfbb
Tree: http://git-wip-us.apache.org/repos/asf/nifi/tree/239bbfbb
Diff: http://git-wip-us.apache.org/repos/asf/nifi/diff/239bbfbb
Branch: refs/heads/master
Commit: 239bbfbb9d08a8b39f330d2ac0a6c4fd6f59dd67
Parents: 37be0b9
Author: Mark Payne <ma...@hotmail.com>
Authored: Sat May 27 14:25:00 2017 -0400
Committer: joewitt <jo...@apache.org>
Committed: Fri Jun 2 10:09:38 2017 -0400
----------------------------------------------------------------------
.../record/util/DataTypeUtils.java | 126 ++++++++++++++++---
1 file changed, 106 insertions(+), 20 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/nifi/blob/239bbfbb/nifi-commons/nifi-record/src/main/java/org/apache/nifi/serialization/record/util/DataTypeUtils.java
----------------------------------------------------------------------
diff --git a/nifi-commons/nifi-record/src/main/java/org/apache/nifi/serialization/record/util/DataTypeUtils.java b/nifi-commons/nifi-record/src/main/java/org/apache/nifi/serialization/record/util/DataTypeUtils.java
index 05c8281..4feec24 100644
--- a/nifi-commons/nifi-record/src/main/java/org/apache/nifi/serialization/record/util/DataTypeUtils.java
+++ b/nifi-commons/nifi-record/src/main/java/org/apache/nifi/serialization/record/util/DataTypeUtils.java
@@ -34,8 +34,9 @@ import java.util.Objects;
import java.util.Optional;
import java.util.Set;
import java.util.TimeZone;
-import java.util.function.Consumer;
+import java.util.function.Predicate;
import java.util.function.Supplier;
+import java.util.regex.Pattern;
import org.apache.nifi.serialization.SimpleRecordSchema;
import org.apache.nifi.serialization.record.DataType;
@@ -49,11 +50,38 @@ import org.apache.nifi.serialization.record.type.RecordDataType;
public class DataTypeUtils {
+ // Regexes for parsing Floting-Point numbers
+ private static final String OptionalSign = "[\\-\\+]?";
+ private static final String Infinity = "(Infinity)";
+ private static final String NotANumber = "(NaN)";
+
+ private static final String Base10Digits = "\\d+";
+ private static final String Base10Decimal = "\\." + Base10Digits;
+ private static final String OptionalBase10Decimal = Base10Decimal + "?";
+
+ private static final String Base10Exponent = "[eE]" + OptionalSign + Base10Digits;
+ private static final String OptionalBase10Exponent = "(" + Base10Exponent + ")?";
+
+ private static final String doubleRegex =
+ OptionalSign +
+ "(" +
+ Infinity + "|" +
+ NotANumber + "|"+
+ "(" + Base10Digits + Base10Decimal + ")" + "|" +
+ "(" + Base10Digits + OptionalBase10Decimal + Base10Exponent + ")" + "|" +
+ "(" + Base10Decimal + OptionalBase10Exponent + ")" +
+ ")";
+
+ private static final Pattern FLOATING_POINT_PATTERN = Pattern.compile(doubleRegex);
+
private static final TimeZone gmt = TimeZone.getTimeZone("gmt");
+ private static final Supplier<DateFormat> DEFAULT_DATE_FORMAT = () -> getDateFormat(RecordFieldType.DATE.getDefaultFormat());
+ private static final Supplier<DateFormat> DEFAULT_TIME_FORMAT = () -> getDateFormat(RecordFieldType.TIME.getDefaultFormat());
+ private static final Supplier<DateFormat> DEFAULT_TIMESTAMP_FORMAT = () -> getDateFormat(RecordFieldType.TIMESTAMP.getDefaultFormat());
+
public static Object convertType(final Object value, final DataType dataType, final String fieldName) {
- return convertType(value, dataType, () -> getDateFormat(RecordFieldType.DATE.getDefaultFormat()), () -> getDateFormat(RecordFieldType.TIME.getDefaultFormat()),
- () -> getDateFormat(RecordFieldType.TIMESTAMP.getDefaultFormat()), fieldName);
+ return convertType(value, dataType, DEFAULT_DATE_FORMAT, DEFAULT_TIME_FORMAT, DEFAULT_TIMESTAMP_FORMAT, fieldName);
}
public static DateFormat getDateFormat(final RecordFieldType fieldType, final Supplier<DateFormat> dateFormat,
@@ -616,10 +644,10 @@ public class DataTypeUtils {
}
public static boolean isDoubleTypeCompatible(final Object value) {
- return isNumberTypeCompatible(value, s -> Double.parseDouble(s));
+ return isNumberTypeCompatible(value, s -> isDouble(s));
}
- private static boolean isNumberTypeCompatible(final Object value, final Consumer<String> stringValueVerifier) {
+ private static boolean isNumberTypeCompatible(final Object value, final Predicate<String> stringPredicate) {
if (value == null) {
return false;
}
@@ -629,12 +657,7 @@ public class DataTypeUtils {
}
if (value instanceof String) {
- try {
- stringValueVerifier.accept((String) value);
- return true;
- } catch (final NumberFormatException nfe) {
- return false;
- }
+ return stringPredicate.test((String) value);
}
return false;
@@ -657,7 +680,45 @@ public class DataTypeUtils {
}
public static boolean isFloatTypeCompatible(final Object value) {
- return isNumberTypeCompatible(value, s -> Float.parseFloat(s));
+ return isNumberTypeCompatible(value, s -> isFloatingPoint(s));
+ }
+
+ private static boolean isFloatingPoint(final String value) {
+ if (value == null || value.isEmpty()) {
+ return false;
+ }
+
+ if (!FLOATING_POINT_PATTERN.matcher(value).matches()) {
+ return false;
+ }
+
+ // Just to ensure that the exponents are in range, etc.
+ try {
+ Float.parseFloat(value);
+ } catch (final NumberFormatException nfe) {
+ return false;
+ }
+
+ return true;
+ }
+
+ private static boolean isDouble(final String value) {
+ if (value == null || value.isEmpty()) {
+ return false;
+ }
+
+ if (!FLOATING_POINT_PATTERN.matcher(value).matches()) {
+ return false;
+ }
+
+ // Just to ensure that the exponents are in range, etc.
+ try {
+ Double.parseDouble(value);
+ } catch (final NumberFormatException nfe) {
+ return false;
+ }
+
+ return true;
}
public static Long toLong(final Object value, final String fieldName) {
@@ -694,15 +755,40 @@ public class DataTypeUtils {
}
if (value instanceof String) {
- try {
- Long.parseLong((String) value);
- return true;
- } catch (final NumberFormatException nfe) {
+ return isIntegral((String) value, Long.MIN_VALUE, Long.MAX_VALUE);
+ }
+
+ return false;
+ }
+
+ private static boolean isIntegral(final String value, final long minValue, final long maxValue) {
+ if (value == null || value.isEmpty()) {
+ return false;
+ }
+
+ int initialPosition = 0;
+ final char firstChar = value.charAt(0);
+ if (firstChar == '+' || firstChar == '-') {
+ initialPosition = 1;
+
+ if (value.length() == 1) {
return false;
}
}
- return false;
+ for (int i = initialPosition; i < value.length(); i++) {
+ if (!Character.isDigit(value.charAt(i))) {
+ return false;
+ }
+ }
+
+ try {
+ final long longValue = Long.parseLong(value);
+ return longValue >= minValue && longValue <= maxValue;
+ } catch (final NumberFormatException nfe) {
+ // In case the value actually exceeds the max value of a Long
+ return false;
+ }
}
@@ -723,7 +809,7 @@ public class DataTypeUtils {
}
public static boolean isIntegerTypeCompatible(final Object value) {
- return isNumberTypeCompatible(value, s -> Integer.parseInt(s));
+ return isNumberTypeCompatible(value, s -> isIntegral(s, Integer.MIN_VALUE, Integer.MAX_VALUE));
}
@@ -744,7 +830,7 @@ public class DataTypeUtils {
}
public static boolean isShortTypeCompatible(final Object value) {
- return isNumberTypeCompatible(value, s -> Short.parseShort(s));
+ return isNumberTypeCompatible(value, s -> isIntegral(s, Short.MIN_VALUE, Short.MAX_VALUE));
}
public static Byte toByte(final Object value, final String fieldName) {
@@ -764,7 +850,7 @@ public class DataTypeUtils {
}
public static boolean isByteTypeCompatible(final Object value) {
- return isNumberTypeCompatible(value, s -> Byte.parseByte(s));
+ return isNumberTypeCompatible(value, s -> isIntegral(s, Byte.MIN_VALUE, Byte.MAX_VALUE));
}