protected T getValueWithDefault()

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()));
    }