From d02aa52721393ddc1846d324046d47c479fb8bb9 Mon Sep 17 00:00:00 2001 From: Jason Wells Date: Mon, 19 Aug 2024 10:09:21 -0700 Subject: [PATCH] enahncement/fix based on use elsewhere --- .../misc/PrimitiveTypeParser.java | 117 +++++++++++++++--- .../test/java/PrimitiveTypeParserTests.java | 2 +- 2 files changed, 103 insertions(+), 16 deletions(-) diff --git a/Java/SuperUtilities/src/main/java/com/nuix/superutilities/misc/PrimitiveTypeParser.java b/Java/SuperUtilities/src/main/java/com/nuix/superutilities/misc/PrimitiveTypeParser.java index a7b6ef9..fceea1e 100644 --- a/Java/SuperUtilities/src/main/java/com/nuix/superutilities/misc/PrimitiveTypeParser.java +++ b/Java/SuperUtilities/src/main/java/com/nuix/superutilities/misc/PrimitiveTypeParser.java @@ -1,37 +1,81 @@ package com.nuix.superutilities.misc; - import com.google.common.collect.ImmutableList; import lombok.Getter; +import org.apache.commons.lang3.tuple.Pair; import org.joda.time.DateTime; +import org.joda.time.DateTimeZone; +import org.joda.time.Duration; +import org.joda.time.format.DateTimeFormat; +import org.joda.time.format.DateTimeFormatter; import java.util.ArrayList; +import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.function.Function; +import java.util.regex.Matcher; import java.util.regex.Pattern; @Getter public class PrimitiveTypeParser { public static final Function jodaTimeAutomaticParsing = new Function<>() { - private final List formatValidators = List.of( - // yyyy-MM-dd'T'HH:mm:ss'Z' + private final List> formats = List.of( // 2017-12-11T15:51:24Z // 2022-04-20T17:12:37Z - Pattern.compile("^\\d{4}-[01][0-9]-[0-3][0-9][tT][0-2][0-9]:[0-5][0-9]:\\d{2}Z$"), + Pair.of( + Pattern.compile("^\\d{4}-[01][0-9]-[0-3][0-9][tT][0-2][0-9]:[0-5][0-9]:\\d{2}Z$"), + DateTimeFormat.forPattern("yyyy-MM-dd'T'HH:mm:ss'Z'").withZone(DateTimeZone.UTC) + ), - // yyyy-MM-dd'T'HH:mm:ss.SSSZZ // 2017-12-11T15:51:24.000-07:00 - 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}$") + Pair.of( + 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}$"), + DateTimeFormat.forPattern("yyyy-MM-dd'T'HH:mm:ss.SSSZZ").withZone(DateTimeZone.UTC) + ), + + // 6/26/2024 1:50:33 PM + Pair.of( + Pattern.compile("\\d{1,2}/\\d{1,2}/\\d{4}\\s{2}\\d{1,2}:\\d{2}:\\d{2} [AP]M"), + DateTimeFormat.forPattern("M/d/yyyy h:m:s a").withZone(DateTimeZone.UTC) + ), + + // 26 Jun 2024 13:50:33 + Pair.of( + Pattern.compile("\\d{1,2}\\s{2}[A-Z][a-z]{2} \\d{4} \\d{2}:\\d{2}:\\d{2}"), + DateTimeFormat.forPattern("dd MMM yyyy HH:mm:ss").withZone(DateTimeZone.UTC) + ) ); @Override public Object apply(String s) { - if (formatValidators.stream() - .noneMatch(p -> p.matcher(s.trim()).matches())) { - return null; - } else { - return DateTime.parse(s.trim()); + for (Pair format : formats) { + Matcher matcher = format.getLeft().matcher(s); + if (matcher.matches()) { + return format.getRight().parseDateTime(s); + } + } + return null; + } + }; + + public static final Function durationAutomaticParsing = new Function<>() { + private final List formatValidators = List.of( + Pattern.compile("(?[0-9]{2}):(?[0-9]{2}):(?[0-9]{2})") + ); + + @Override + public Object apply(String s) { + for (Pattern pattern : formatValidators) { + Matcher m = pattern.matcher(s); + if (m.matches()) { + long hours = Long.parseLong(m.group("hours")); + long minutes = Long.parseLong(m.group("minutes")); + long seconds = Long.parseLong(m.group("seconds")); + long millis = ((hours * 3600) + (minutes * 60) + seconds) * 1000; + return new Duration(millis); + } } + return null; } }; @@ -74,6 +118,19 @@ public Object apply(String s) { } }; + public static final Function yesNoBooleanParser = new Function<>() { + private final Pattern formatValidator = Pattern.compile("^(yes)|(no)$", Pattern.CASE_INSENSITIVE); + + @Override + public Object apply(String s) { + if (!formatValidator.matcher(s.trim().toLowerCase()).matches()) { + return null; + } else { + return Boolean.parseBoolean(s.trim()); + } + } + }; + @Getter(lazy = true) private static final PrimitiveTypeParser standard = buildImmutableStandard(); @@ -86,9 +143,11 @@ private static PrimitiveTypeParser buildImmutableStandard() { public static PrimitiveTypeParser buildStandardCopy() { PrimitiveTypeParser result = new PrimitiveTypeParser(); result.getTypeParsers().add(jodaTimeAutomaticParsing); + result.getTypeParsers().add(durationAutomaticParsing); result.getTypeParsers().add(numericParser); result.getTypeParsers().add(decimalParser); result.getTypeParsers().add(booleanParser); + result.getTypeParsers().add(yesNoBooleanParser); return result; } @@ -122,15 +181,43 @@ public Object parse(String input) { return parseWithFallback(input, input); } - public void enrichInPlace(Map input) { - for(Map.Entry entry : input.entrySet()) { + public void enrichInPlace(Map input) { + for (Map.Entry entry : input.entrySet()) { + String key = entry.getKey(); + Object value = entry.getValue(); + if (value instanceof String) { + String stringValue = (String) value; + Object parsedValue = parse(stringValue); + input.put(key, parsedValue); + } + } + } + + public Map parseAndCopy(Map input) { + Map result = new HashMap<>(); + for (Map.Entry entry : input.entrySet()) { String key = entry.getKey(); Object value = entry.getValue(); - if(value instanceof String) { + if (value instanceof String) { String stringValue = (String) value; Object parsedValue = parse(stringValue); - input.put(key,parsedValue); + result.put(key, parsedValue); } } + return result; + } + + public Map parseAndCopy(Map input, Function keyMapper) { + Map result = new HashMap<>(); + for (Map.Entry entry : input.entrySet()) { + String key = entry.getKey(); + Object value = entry.getValue(); + if (value instanceof String) { + String stringValue = (String) value; + Object parsedValue = parse(stringValue); + result.put(keyMapper.apply(key), parsedValue); + } + } + return result; } } diff --git a/Java/SuperUtilities/src/test/java/PrimitiveTypeParserTests.java b/Java/SuperUtilities/src/test/java/PrimitiveTypeParserTests.java index 1a7722d..68f6c04 100644 --- a/Java/SuperUtilities/src/test/java/PrimitiveTypeParserTests.java +++ b/Java/SuperUtilities/src/test/java/PrimitiveTypeParserTests.java @@ -39,7 +39,7 @@ public void testTypeParsing() throws Exception { ); for (String dateToParse : additionalDates) { - Object parsedDate = standardTypeParser.parse("2022-04-20T17:12:37Z"); + Object parsedDate = standardTypeParser.parse(dateToParse); assertTrue(parsedDate instanceof DateTime, String.format("%s did not parse into a DateTime", dateToParse)); }