T newProxy()

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


    <T> T newProxy(final Class<T> type, final String initialPrefix, boolean immutable) {
        Configuration annot = type.getAnnotation(Configuration.class);
        final String prefix = derivePrefix(annot, initialPrefix);

        warnWhenTooMany(PROXIES_COUNT, new InterfaceAndPrefix(type, prefix), excessiveProxyLimit, () -> String.format("Proxy(%s, %s)", type, prefix));


        // There's a circular dependency between these maps and the proxy object. They must be created first because the
        // proxy's invocation handler needs to keep a reference to them, but the proxy must be created before they get
        // filled because we may need to call methods on the interface in order to fill the maps :-|
        final Map<Method, PropertyValueGetter<?>> invokers = new HashMap<>();
        final Map<Method, String> propertyNames = new HashMap<>();

        final InvocationHandler handler = new ConfigProxyInvocationHandler<>(type, prefix, invokers, propertyNames);

        final T proxyObject = (T) Proxy.newProxyInstance(type.getClassLoader(), new Class[] { type }, handler);
        List<RuntimeException> proxyingExceptions = new LinkedList<>();

        // Iterate through all declared methods of the class looking for setter methods.
        // Each setter will be mapped to a Property<T> for the property name:
        //      prefix + lowerCamelCaseDerivedPropertyName
        for (Method method : type.getMethods()) {
            if (Modifier.isStatic(method.getModifiers())) {
                continue;
            }

            try {
                MethodInvokerHolder methodInvokerHolder = buildInvokerForMethod(type, prefix, method, proxyObject, immutable);

                propertyNames.put(method, methodInvokerHolder.propertyName);

                if (immutable) {
                    // Cache the current value of the property and always return that.
                    // Note that this will fail for parameterized properties and for primitive-valued methods
                    // with no value set!
                    Object value = methodInvokerHolder.invoker.invoke(new Object[]{});
                    invokers.put(method, (args) -> value);
                } else {
                    invokers.put(method, methodInvokerHolder.invoker);
                }
            } catch (RuntimeException e) {
                // Capture the exception and continue processing the other methods. We'll throw them all at the end.
                proxyingExceptions.add(e);
            }
        }

        if (!proxyingExceptions.isEmpty()) {
            String errors = proxyingExceptions.stream()
                    .map(Throwable::getMessage)
                    .collect(Collectors.joining("\n\t"));
            RuntimeException exception = new RuntimeException(
                    "Failed to create a configuration proxy for class " + type.getName()
                    + ":\n\t" + errors, proxyingExceptions.get(0));
            proxyingExceptions.subList(1, proxyingExceptions.size()).forEach(exception::addSuppressed);
            throw exception;
        }

        return proxyObject;
    }