private MethodInvokerHolder buildInvokerForMethod()

in archaius2-core/src/main/java/com/netflix/archaius/ConfigProxyFactory.java [310:358]


    private <T> MethodInvokerHolder buildInvokerForMethod(Class<T> proxyObjectType, String prefix, Method m, T proxyObject, boolean immutable) {
        try {

            final Class<?> returnType = m.getReturnType();
            final PropertyName nameAnnot = m.getAnnotation(PropertyName.class);
            final String propName = getPropertyName(prefix, m, nameAnnot);

            // A supplier for the value to be returned when the method's associated property is not set
            // The proper parametrized type for this would be Function<Object[], returnType>, but we can't say that in Java.
            final Function<Object[], ?> defaultValueSupplier = defaultValueSupplierForMethod(proxyObjectType, m, returnType, proxyObject, propName);

            // This object encapsulates the way to get the value for the current property.
            final PropertyValueGetter propertyValueGetter;

            if (!knownCollections.containsKey(returnType)
                    && returnType.isInterface()
                    && !(decoder instanceof TypeConverter.Registry && ((TypeConverter.Registry) decoder).get(m.getGenericReturnType()).isPresent())) {
                // Our return type is an interface but not a known collection and is also not a type our decoder can handle.
                // We treat it as a nested Config proxy interface and create a proxy with it, with the current property name as the initial prefix for nesting.
                propertyValueGetter = createInterfaceProperty(propName, newProxy(returnType, propName, immutable));

            } else if (m.getParameterCount() > 0) {
                // A parameterized property. Note that this requires a @PropertyName annotation to extract the interpolation positions!
                if (nameAnnot == null) {
                    throw new IllegalArgumentException("Missing @PropertyName annotation on method with parameters " + m.getName());
                }

                // A previous version allowed the full name to be specified, even if the prefix was specified. So, for
                // backwards compatibility, we allow both including or excluding the prefix for parameterized names.
                String propertyNameTemplate;
                if (!StringUtils.isBlank(prefix) && !nameAnnot.name().startsWith(prefix)) {
                    propertyNameTemplate = prefix + nameAnnot.name();
                } else {
                    propertyNameTemplate = nameAnnot.name();
                }

                // TODO: Figure out a way to validate the template. It should have params in the form ${0}, ${1}, etc.
                propertyValueGetter = createParameterizedProperty(m.getGenericReturnType(), propertyNameTemplate, defaultValueSupplier);

            } else {
                // Anything else.
                propertyValueGetter = createScalarProperty(m.getGenericReturnType(), propName, defaultValueSupplier);
            }

            return new MethodInvokerHolder(propertyValueGetter, propName);
        } catch (RuntimeException e) {
            throw new RuntimeException("Failed to create a proxy for method " + m.getName() + ": " + e, e);
        }
    }