All Downloads are FREE. Search and download functionalities are using the official Maven repository.

global.namespace.neuron.di.internal.ProxyContext Maven / Gradle / Ivy

/*
 * Copyright © 2016 Schlichtherle IT Services
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     https://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package global.namespace.neuron.di.internal;

import global.namespace.neuron.di.java.BreedingException;

import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Optional;

import static global.namespace.neuron.di.internal.Reflection.overridableMethods;
import static java.lang.reflect.Modifier.PROTECTED;
import static java.lang.reflect.Modifier.PUBLIC;

final class ProxyContext {

    private final ClassElement element;

    ProxyContext(final ClassElement element) {
        element.assertCanBeProxied();
        this.element = element;
    }

    ProxyFactory factory() {
        final Class adaptedClass = adaptedClass();
        return new ProxyFactory<>(adaptedClass, bindableElements(adaptedClass));
    }

    private Class adaptedClass() {
        final Class clazz = clazz();
        return Optional
                .ofNullable(clazz.getDeclaredAnnotation(Shim.class))
                .>map(this::shimClass)
                .orElse(clazz);
    }

    @SuppressWarnings("unchecked")
    private Class shimClass(final Shim annotation) {
        Class shimClass;
        try {
            shimClass = (Class) clazz().getClassLoader().loadClass(annotation.name());
        } catch (ClassNotFoundException e) {
            throw new BreedingException(e);
        }
        if (shimClass == Object.class) {
            shimClass = (Class) annotation.value();
        }
        if (shimClass == Object.class) {
            throw new BreedingException("The @Shim annotation must reference a @Neuron class: " + clazz());
        }
        return shimClass;
    }

    private Class clazz() {
        return element.clazz();
    }

    private List> bindableElements(Class clazz) {
        return new Visitor() {

            final ArrayList> bindableElements;

            {
                // Package-private methods of bootstrap classes cannot be bound because their packages are sealed, so
                // you cannot define a subclass in the same package:
                final Package pkg = null != clazz.getClassLoader() ? clazz.getPackage() : null;
                final Collection methods = overridableMethods(clazz);
                bindableElements = new ArrayList<>(methods.size());
                methods.forEach(method -> {
                    if (0 != (method.getModifiers() & (PROTECTED | PUBLIC))
                            || method.getDeclaringClass().getPackage() == pkg) {
                        element.element(method).accept(this);
                    }
                });
                bindableElements.trimToSize();
            }

            @Override
            public void visitSynapse(SynapseElement element) {
                bindableElements.add(element);
            }

            @Override
            public void visitMethod(final MethodElement element) {
                if (!element.hasParameters() && !element.isVoid()) {
                    bindableElements.add(element);
                }
            }
        }.bindableElements;
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy