Skip to content

Commit 89d5ed3

Browse files
committed
primitive type parser with tests
1 parent 759f63d commit 89d5ed3

File tree

3 files changed

+249
-0
lines changed

3 files changed

+249
-0
lines changed

Java/SuperUtilities/.idea/gradle.xml

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 136 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,136 @@
1+
package com.nuix.superutilities.misc;
2+
3+
import com.google.common.collect.ImmutableList;
4+
import lombok.Getter;
5+
import org.joda.time.DateTime;
6+
7+
import java.util.ArrayList;
8+
import java.util.List;
9+
import java.util.Map;
10+
import java.util.function.Function;
11+
import java.util.regex.Pattern;
12+
13+
@Getter
14+
public class PrimitiveTypeParser {
15+
public static final Function<String, Object> jodaTimeAutomaticParsing = new Function<>() {
16+
private final List<Pattern> formatValidators = List.of(
17+
// yyyy-MM-dd'T'HH:mm:ss'Z'
18+
// 2017-12-11T15:51:24Z
19+
// 2022-04-20T17:12:37Z
20+
Pattern.compile("^\\d{4}-[01][0-9]-[0-3][0-9][tT][0-2][0-9]:[0-5][0-9]:\\d{2}Z$"),
21+
22+
// yyyy-MM-dd'T'HH:mm:ss.SSSZZ
23+
// 2017-12-11T15:51:24.000-07:00
24+
Pattern.compile("^\\d{4}-[01][0-9]-[0-3][0-9][tT][0-2][0-9]:[0-5][0-9]:\\d{2}\\.\\d{3}[+\\-]\\d{2}:\\d{2}$")
25+
);
26+
27+
@Override
28+
public Object apply(String s) {
29+
if (formatValidators.stream()
30+
.noneMatch(p -> p.matcher(s.trim()).matches())) {
31+
return null;
32+
} else {
33+
return DateTime.parse(s.trim());
34+
}
35+
}
36+
};
37+
38+
public static final Function<String, Object> numericParser = new Function<>() {
39+
private final Pattern formatValidator = Pattern.compile("^[+\\-]?[0-9]+$");
40+
41+
@Override
42+
public Object apply(String s) {
43+
if (!formatValidator.matcher(s.trim()).matches()) {
44+
return null;
45+
} else {
46+
return Long.parseLong(s.trim());
47+
}
48+
}
49+
};
50+
51+
public static final Function<String, Object> decimalParser = new Function<>() {
52+
private final Pattern formatValidator = Pattern.compile("^[+\\-]?[0-9]+\\.[0-9]*$");
53+
54+
@Override
55+
public Object apply(String s) {
56+
if (!formatValidator.matcher(s.trim()).matches()) {
57+
return null;
58+
} else {
59+
return Double.parseDouble(s.trim());
60+
}
61+
}
62+
};
63+
64+
public static final Function<String, Object> booleanParser = new Function<>() {
65+
private final Pattern formatValidator = Pattern.compile("^(true)|(false)$");
66+
67+
@Override
68+
public Object apply(String s) {
69+
if (!formatValidator.matcher(s.trim().toLowerCase()).matches()) {
70+
return null;
71+
} else {
72+
return Boolean.parseBoolean(s.trim());
73+
}
74+
}
75+
};
76+
77+
@Getter(lazy = true)
78+
private static final PrimitiveTypeParser standard = buildImmutableStandard();
79+
80+
private static PrimitiveTypeParser buildImmutableStandard() {
81+
PrimitiveTypeParser result = buildStandardCopy();
82+
result.typeParsers = ImmutableList.copyOf(result.typeParsers);
83+
return result;
84+
}
85+
86+
public static PrimitiveTypeParser buildStandardCopy() {
87+
PrimitiveTypeParser result = new PrimitiveTypeParser();
88+
result.getTypeParsers().add(jodaTimeAutomaticParsing);
89+
result.getTypeParsers().add(numericParser);
90+
result.getTypeParsers().add(decimalParser);
91+
result.getTypeParsers().add(booleanParser);
92+
return result;
93+
}
94+
95+
private List<Function<String, Object>> typeParsers;
96+
97+
public PrimitiveTypeParser() {
98+
typeParsers = new ArrayList<>();
99+
}
100+
101+
public Object parseWithFallback(String input, Object fallback) {
102+
if (input == null || input.trim().isBlank()) {
103+
return fallback;
104+
} else {
105+
Object parsedValue = null;
106+
for (Function<String, Object> parser : typeParsers) {
107+
parsedValue = parser.apply(input);
108+
if (parsedValue != null) {
109+
break;
110+
}
111+
}
112+
113+
if (parsedValue == null) {
114+
return fallback;
115+
} else {
116+
return parsedValue;
117+
}
118+
}
119+
}
120+
121+
public Object parse(String input) {
122+
return parseWithFallback(input, input);
123+
}
124+
125+
public void enrichInPlace(Map<String,Object> input) {
126+
for(Map.Entry<String,Object> entry : input.entrySet()) {
127+
String key = entry.getKey();
128+
Object value = entry.getValue();
129+
if(value instanceof String) {
130+
String stringValue = (String) value;
131+
Object parsedValue = parse(stringValue);
132+
input.put(key,parsedValue);
133+
}
134+
}
135+
}
136+
}
Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
import com.nuix.superutilities.misc.PrimitiveTypeParser;
2+
import org.joda.time.DateTime;
3+
import org.joda.time.DateTimeZone;
4+
import org.junit.jupiter.api.Test;
5+
6+
import java.util.List;
7+
8+
import static org.junit.jupiter.api.Assertions.*;
9+
10+
public class PrimitiveTypeParserTests extends TestFoundation {
11+
@Test
12+
public void testTypeParsing() throws Exception {
13+
PrimitiveTypeParser standardTypeParser = PrimitiveTypeParser.getStandard();
14+
15+
// Since we are testing some without millis precision, we trim millis off so
16+
// round trip still succeeds
17+
DateTime now = DateTime.now(DateTimeZone.UTC).millisOfSecond().setCopy(0);
18+
List<String> formatStrings = List.of(
19+
"yyyy-MM-dd'T'HH:mm:ss.SSSZZ",
20+
"yyyy-MM-dd'T'HH:mm:ss'Z'"
21+
);
22+
23+
for (String formatString : formatStrings) {
24+
log.info(formatString + " => " + now.toString(formatString));
25+
}
26+
27+
for (String formatString : formatStrings) {
28+
String inputString = now.toString(formatString);
29+
Object parsedObject = standardTypeParser.parse(inputString);
30+
assertNotNull(parsedObject);
31+
assertInstanceOf(DateTime.class, parsedObject);
32+
assertTrue(now.isEqual((DateTime) parsedObject),
33+
String.format("Format String: %s, Expected: %s, Got: %s",
34+
formatString, now, ((DateTime) parsedObject)));
35+
}
36+
37+
List<String> additionalDates = List.of(
38+
"2022-04-20T17:12:37Z"
39+
);
40+
41+
for (String dateToParse : additionalDates) {
42+
Object parsedDate = standardTypeParser.parse("2022-04-20T17:12:37Z");
43+
assertTrue(parsedDate instanceof DateTime, String.format("%s did not parse into a DateTime", dateToParse));
44+
}
45+
46+
assertEquals("cat", standardTypeParser.parse("cat"));
47+
assertEquals(" cat ", standardTypeParser.parse(" cat "));
48+
assertEquals("dog", standardTypeParser.parseWithFallback("", "dog"));
49+
assertEquals(0, standardTypeParser.parseWithFallback("bird", 0));
50+
51+
assertEquals(true, standardTypeParser.parse("true"));
52+
assertEquals(false, standardTypeParser.parse("false"));
53+
assertEquals(true, standardTypeParser.parse("True"));
54+
assertEquals(false, standardTypeParser.parse("False"));
55+
assertEquals(true, standardTypeParser.parse(" True "));
56+
assertEquals(false, standardTypeParser.parse(" False "));
57+
58+
assertEquals(0L, standardTypeParser.parse("0"));
59+
assertEquals(0L, standardTypeParser.parse("-0"));
60+
assertEquals(0L, standardTypeParser.parse("+0"));
61+
assertEquals(123456789L, standardTypeParser.parse("123456789"));
62+
assertEquals(123456789L, standardTypeParser.parse("0123456789"));
63+
assertEquals(123456789L, standardTypeParser.parse("+0123456789"));
64+
assertEquals(-123456789L, standardTypeParser.parse("-0123456789"));
65+
66+
assertEquals(0L, standardTypeParser.parse(" 0 "));
67+
assertEquals(0L, standardTypeParser.parse(" -0 "));
68+
assertEquals(0L, standardTypeParser.parse(" +0 "));
69+
assertEquals(123456789L, standardTypeParser.parse(" 123456789 "));
70+
assertEquals(123456789L, standardTypeParser.parse(" 0123456789 "));
71+
assertEquals(123456789L, standardTypeParser.parse(" +0123456789 "));
72+
assertEquals(-123456789L, standardTypeParser.parse(" -0123456789 "));
73+
74+
assertEquals(0.0d, standardTypeParser.parse("0."));
75+
assertEquals(-0.0d, standardTypeParser.parse("-0."));
76+
assertEquals(0.0d, standardTypeParser.parse("+0."));
77+
assertEquals(0.0d, standardTypeParser.parse("0.0"));
78+
assertEquals(0.0d, standardTypeParser.parse("+0.0"));
79+
assertEquals(-0.0d, standardTypeParser.parse("-0.0"));
80+
assertEquals(123456789d, standardTypeParser.parse("123456789."));
81+
assertEquals(123456789d, standardTypeParser.parse("+123456789."));
82+
assertEquals(-123456789d, standardTypeParser.parse("-123456789."));
83+
assertEquals(123456789d, standardTypeParser.parse("123456789.0"));
84+
assertEquals(123456789d, standardTypeParser.parse("+123456789.0"));
85+
assertEquals(-123456789d, standardTypeParser.parse("-123456789.0"));
86+
assertEquals(123456789d, standardTypeParser.parse("123456789.000"));
87+
assertEquals(123456789d, standardTypeParser.parse("+123456789.000"));
88+
assertEquals(-123456789d, standardTypeParser.parse("-123456789.000"));
89+
assertEquals(123456789.314d, standardTypeParser.parse("123456789.314"));
90+
assertEquals(123456789.314d, standardTypeParser.parse("+123456789.314"));
91+
assertEquals(-123456789.314d, standardTypeParser.parse("-123456789.314"));
92+
93+
assertEquals(0.0d, standardTypeParser.parse(" 0. "));
94+
assertEquals(-0.0d, standardTypeParser.parse(" -0. "));
95+
assertEquals(0.0d, standardTypeParser.parse(" +0. "));
96+
assertEquals(0.0d, standardTypeParser.parse(" 0.0 "));
97+
assertEquals(0.0d, standardTypeParser.parse(" +0.0 "));
98+
assertEquals(-0.0d, standardTypeParser.parse(" -0.0 "));
99+
assertEquals(123456789d, standardTypeParser.parse(" 123456789. "));
100+
assertEquals(123456789d, standardTypeParser.parse(" +123456789. "));
101+
assertEquals(-123456789d, standardTypeParser.parse(" -123456789. "));
102+
assertEquals(123456789d, standardTypeParser.parse(" 123456789.0 "));
103+
assertEquals(123456789d, standardTypeParser.parse(" +123456789.0 "));
104+
assertEquals(-123456789d, standardTypeParser.parse(" -123456789.0 "));
105+
assertEquals(123456789d, standardTypeParser.parse(" 123456789.000 "));
106+
assertEquals(123456789d, standardTypeParser.parse(" +123456789.000 "));
107+
assertEquals(-123456789d, standardTypeParser.parse(" -123456789.000 "));
108+
assertEquals(123456789.314d, standardTypeParser.parse(" 123456789.314 "));
109+
assertEquals(123456789.314d, standardTypeParser.parse(" +123456789.314 "));
110+
assertEquals(-123456789.314d, standardTypeParser.parse(" -123456789.314 "));
111+
}
112+
}

0 commit comments

Comments
 (0)