in archaius2-core/src/main/java/com/netflix/archaius/config/AbstractConfig.java [322:414]
protected <T> T getValueWithDefault(Type type, String key, T defaultValue) {
Object rawProp = getRawProperty(key);
if (rawProp == null && type instanceof ParameterizedType) {
ParameterizedType parameterizedType = (ParameterizedType) type;
if (isMap(parameterizedType)) {
Map<?, ?> ret = new LinkedHashMap<>();
String keyAndDelimiter = key + ".";
Type keyType = parameterizedType.getActualTypeArguments()[0];
Type valueType = parameterizedType.getActualTypeArguments()[1];
for (String k : keys()) {
if (k.startsWith(keyAndDelimiter)) {
ret.put(getDecoder().decode(keyType, k.substring(keyAndDelimiter.length())), get(valueType, k));
}
}
return ret.isEmpty() ? defaultValue : (T) Collections.unmodifiableMap(ret);
} else if (isCollection(parameterizedType)) {
Type valueType = parameterizedType.getActualTypeArguments()[0];
List<?> ret = createListForKey(key, valueType);
if (Set.class.isAssignableFrom((Class<?>) parameterizedType.getRawType())) {
Set<?> retSet = new LinkedHashSet<>(ret);
return ret.isEmpty() ? defaultValue : (T) Collections.unmodifiableSet(retSet);
} else {
return ret.isEmpty() ? defaultValue : (T) Collections.unmodifiableList(ret);
}
}
}
// Not found. Return the default.
if (rawProp == null) {
return defaultValue;
}
// raw prop is a String. Decode it or fail.
if (rawProp instanceof String) {
try {
String value = resolve(rawProp.toString());
return decoder.decode(type, value);
} catch (RuntimeException e) {
return parseError(key, rawProp.toString(), e);
}
}
if (type instanceof Class) {
// Caller wants a simple class.
Class<?> cls = (Class<?>) type;
// The raw object is already of the right type
if (cls.isInstance(rawProp)) {
return (T) rawProp;
}
// Caller wants a string
if (String.class.isAssignableFrom(cls)) {
return (T) rawProp.toString();
}
// Caller wants an unwrapped boolean.
if (rawProp instanceof Boolean && cls == boolean.class) {
return (T) rawProp;
}
// Caller wants a number AND we have one. Handle widening and narrowing conversions.
// Char is not included here. It's not a Number and the semantics of converting it to/from a number or a
// string have rough edges. Just ask users to avoid it.
if (rawProp instanceof Number
&& ( Number.class.isAssignableFrom(cls)
|| ( cls.isPrimitive() && cls != char.class ))) { // We handled boolean above, so if cls is a primitive and not char then it's a number type
if (cls == int.class || cls == Integer.class) {
return (T) Integer.valueOf(((Number) rawProp).intValue());
}
if (cls == long.class || cls == Long.class) {
return (T) Long.valueOf(((Number) rawProp).longValue());
}
if (cls == double.class || cls == Double.class) {
return (T) Double.valueOf(((Number) rawProp).doubleValue());
}
if (cls == float.class || cls == Float.class) {
return (T) Float.valueOf(((Number) rawProp).floatValue());
}
if (cls == short.class || cls == Short.class) {
return (T) Short.valueOf(((Number) rawProp).shortValue());
}
if (cls == byte.class || cls == Byte.class) {
return (T) Byte.valueOf(((Number) rawProp).byteValue());
}
}
}
// Nothing matches (ie, caller wants a ParametrizedType, or the rawProp is not easily cast to the desired type)
return parseError(key, rawProp.toString(),
new IllegalArgumentException("Property " + rawProp + " is not convertible to " + type.getTypeName()));
}