I have a situation where I will be given a String and I need to determine what Class<?>
best suits its value given the following constraints:
"true"
or "false"
, it's a Boolean
Integer
Double
YYYY-MM-DD hh:mm:ss.sss
, then its a Java Date
String
afterall My best attempt is nasty and involves a lot of nested try/catch
blocks:
// Groovy pseudo-code
Class<?> determineValueType(String value) {
Class<?> clazz
if(value.equalsIgnoreCase('true') || value.equalsIgnoreCase('false')) {
clazz = Boolean
} else {
try {
Integer.parse(value)
clazz = Integer
} catch(Exception ex1) {
try {
Double.parse(value)
clazz = Double
} catch(Exception ex2) {
try {
Date.parse('YYYY-MM-DD hh:mm:ss.sss', value)
clazz = Date
} catch(Exception ex3) {
clazz = String
}
}
}
}
clazz
}
Are there any Groovier ways of accomplishing this, perhaps something endemic to some obscure Groovy reflection API?
There are two methods which can help you in Groovy's extended String class (actually on CharSequence
):
But for other cases, AFAIK, you are on your own to implement the parsing. You could try working with a map and some closures, to reduce some boilerplate:
Class parse(val) {
def convert = [
(Integer) : { it.toInteger() },
(Double) : { it.toDouble() },
(Date) : { Date.parse('YYYY-MM-DD hh:mm:ss.sss', it) },
(Boolean) : { Boolean.parseBoolean it },
(String) : { it }
]
convert.findResult { key, value ->
try {
if (value(val)) return key
} catch (e) {}
}
}
assert parse('9.1') == Double
assert parse('9') == Integer
assert parse('1985-10-26 01:22:00.000') == Date // great scott!
assert parse('chicken') == String
assert parse('True') == Boolean
Note that if (Double)
precedes (Integer)
the tests won't work, since 9
is both a double and a integer.
Groovy has a few features that would allow you to make this logic groovier.
isInteger
and isDouble
built-in CharSequence methods from the Groovy JDK. Sadly, there's not a strict isBoolean
so we'll need to implement that ourselves. Combining these features...
Class<?> determineValueType(String value) {
switch (value) {
case { ['true', 'false'].contains(value?.toLowerCase()) }:
return Boolean
case { value?.isInteger() }:
return Integer
case { value?.isDouble() }:
return Double
case ~/^\d{4}-\d{2}-\d{2} \d{1,2}:\d{2}:\d{2}\.\d{3}$/:
return Date
default:
return String
}
}
assert determineValueType('true') == Boolean
assert determineValueType('false') == Boolean
assert determineValueType('2039230') == Integer
assert determineValueType('203923.0') == Double
assert determineValueType('2016-07-26 12:00:00.000') == Date
assert determineValueType('foo') == String
I used a regex instead of SimpleDateFormat to avoid having to catch an Exception. It probably has slightly difference semantics, but you could alternatively create a helper method that returns false if there's an Exception thrown by Date.parse
.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.