org.deephacks.tools4j.config.internal.core.runtime.typesafe.impl.DefaultTransformer Maven / Gradle / Ivy
/**
* Copyright (C) 2011-2012 Typesafe Inc.
*/
package org.deephacks.tools4j.config.internal.core.runtime.typesafe.impl;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.Map;
import org.deephacks.tools4j.config.internal.core.runtime.typesafe.ConfigValueType;
/**
* Default automatic type transformations.
*/
final class DefaultTransformer {
static AbstractConfigValue transform(AbstractConfigValue value,
ConfigValueType requested) {
if (value.valueType() == ConfigValueType.STRING) {
String s = (String) value.unwrapped();
switch (requested) {
case NUMBER:
try {
Long v = Long.parseLong(s);
return new ConfigLong(value.origin(), v, s);
} catch (NumberFormatException e) {
// try Double
}
try {
Double v = Double.parseDouble(s);
return new ConfigDouble(value.origin(), v, s);
} catch (NumberFormatException e) {
// oh well.
}
break;
case NULL:
if (s.equals("null"))
return new ConfigNull(value.origin());
break;
case BOOLEAN:
if (s.equals("true") || s.equals("yes") || s.equals("on")) {
return new ConfigBoolean(value.origin(), true);
} else if (s.equals("false") || s.equals("no")
|| s.equals("off")) {
return new ConfigBoolean(value.origin(), false);
}
break;
case LIST:
// can't go STRING to LIST automatically
break;
case OBJECT:
// can't go STRING to OBJECT automatically
break;
case STRING:
// no-op STRING to STRING
break;
}
} else if (requested == ConfigValueType.STRING) {
// if we converted null to string here, then you wouldn't properly
// get a missing-value error if you tried to get a null value
// as a string.
switch (value.valueType()) {
case NUMBER: // FALL THROUGH
case BOOLEAN:
return new ConfigString(value.origin(),
value.transformToString());
case NULL:
// want to be sure this throws instead of returning "null" as a
// string
break;
case OBJECT:
// no OBJECT to STRING automatically
break;
case LIST:
// no LIST to STRING automatically
break;
case STRING:
// no-op STRING to STRING
break;
}
} else if (requested == ConfigValueType.LIST && value.valueType() == ConfigValueType.OBJECT) {
// attempt to convert an array-like (numeric indices) object to a
// list. This would be used with .properties syntax for example:
// -Dfoo.0=bar -Dfoo.1=baz
// To ensure we still throw type errors for objects treated
// as lists in most cases, we'll refuse to convert if the object
// does not contain any numeric keys. This means we don't allow
// empty objects here though :-/
AbstractConfigObject o = (AbstractConfigObject) value;
Map values = new HashMap();
for (String key : o.keySet()) {
int i;
try {
i = Integer.parseInt(key, 10);
if (i < 0)
continue;
values.put(i, o.get(key));
} catch (NumberFormatException e) {
continue;
}
}
if (!values.isEmpty()) {
ArrayList> entryList = new ArrayList>(
values.entrySet());
// sort by numeric index
Collections.sort(entryList,
new Comparator>() {
@Override
public int compare(Map.Entry a,
Map.Entry b) {
// Integer.compare was added in 1.7 so not using
// it here yet
return Integer.valueOf(a.getKey()).compareTo(b.getKey());
}
});
// drop the indices (we allow gaps in the indices, for better or
// worse)
ArrayList list = new ArrayList();
for (Map.Entry entry : entryList) {
list.add(entry.getValue());
}
return new SimpleConfigList(value.origin(), list);
}
}
return value;
}
}