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

com.cmeza.spring.ioc.handler.contracts.IocContractManager Maven / Gradle / Ivy

The newest version!
package com.cmeza.spring.ioc.handler.contracts;

import com.cmeza.spring.ioc.handler.contracts.consumers.enums.ConsumerLocation;
import com.cmeza.spring.ioc.handler.contracts.consumers.manager.ConsumerManagerImpl;
import com.cmeza.spring.ioc.handler.handlers.IocMethodInterceptor;
import com.cmeza.spring.ioc.handler.metadata.ClassMetadata;
import com.cmeza.spring.ioc.handler.metadata.MethodMetadata;
import com.cmeza.spring.ioc.handler.metadata.impl.SimpleAnnotationMetadata;
import com.cmeza.spring.ioc.handler.metadata.impl.SimpleClassMetadata;
import com.cmeza.spring.ioc.handler.metadata.impl.SimpleMethodMetadata;
import com.cmeza.spring.ioc.handler.metadata.impl.SimpleParameterMetadata;
import com.cmeza.spring.ioc.handler.processors.IocProcessors;
import com.cmeza.spring.ioc.handler.utils.IocTypes;
import com.cmeza.spring.ioc.handler.utils.IocUtil;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;

import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.List;

@Slf4j
@RequiredArgsConstructor
@SuppressWarnings({"unchecked", "rawtypes"})
public class IocContractManager {
    private final IocContract contract;
    private final IocProcessors processors;
    private final List> methodInterceptors;

    public ClassMetadata parseAndValidateClassMetadata(Class targetType) {
        IocUtil.checkState(targetType.getTypeParameters().length == 0, "Parameterized types unsupported: %s", targetType.getSimpleName());
        IocUtil.checkState(targetType.getInterfaces().length <= 1, "Only single inheritance supported: %s", targetType.getSimpleName());
        if (targetType.getInterfaces().length == 1) {
            IocUtil.checkState(targetType.getInterfaces()[0].getInterfaces().length == 0, "Only single-level inheritance supported: %s", targetType.getSimpleName());
        }

        ConsumerManagerImpl consumerManager = new ConsumerManagerImpl();
        contract.configure(consumerManager);

        //Processors configuration
        contract.processors(processors);

        SimpleClassMetadata classMetadata = new SimpleClassMetadata(targetType);

        //Class Annotation process
        consumerManager.getClassConsumers(ConsumerLocation.ON_START).forEach(consumer -> consumer.accept(classMetadata));
        consumerManager.getClassConsumers(ConsumerLocation.BEFORE_ANNOTATION_PROCESSOR).forEach(consumer -> consumer.accept(classMetadata));
        this.executeClassAnnotatedProcessors(contract.onlyMethodDeclaredAnnotations() ? targetType.getDeclaredAnnotations() : targetType.getAnnotations(), classMetadata);
        consumerManager.getClassConsumers(ConsumerLocation.AFTER_ANNOTATION_PROCESSOR).forEach(consumer -> consumer.accept(classMetadata));

        for (Method method : contract.onlyDeclaredMethods() ? targetType.getDeclaredMethods() : targetType.getMethods()) {
            if (method.getDeclaringClass() != Object.class && (method.getModifiers() & 8) == 0 && !IocUtil.isDefault(method)) {
                MethodMetadata metadata = this.parseAndValidateMethodMetadata(classMetadata, method, consumerManager);

                IocUtil.checkState(!classMetadata.existsMethodMetadata(metadata), "Overrides unsupported: %s", metadata.getConfigKey());
                classMetadata.addMethodMetadata(metadata);
            }
        }

        //Class Annotation process
        consumerManager.getClassConsumers(ConsumerLocation.ON_END).forEach(consumer -> consumer.accept(classMetadata));

        return classMetadata;
    }

    private MethodMetadata parseAndValidateMethodMetadata(SimpleClassMetadata classMetadata, Method method, ConsumerManagerImpl consumerManager) {
        SimpleMethodMetadata methodMetadata = new SimpleMethodMetadata(method, IocTypes.resolve(classMetadata.getTargetClass(), classMetadata.getTargetClass(), method.getGenericReturnType()));
        methodMetadata.setConfigKey(IocUtil.configKey(classMetadata.getTargetClass(), method));
        methodMetadata.setIntercepted(methodInterceptors.stream().anyMatch(i -> i.accept(method.getReturnType())));

        //Method Annotation process
        consumerManager.getMethodConsumers(ConsumerLocation.ON_START).forEach(consumer -> consumer.accept(classMetadata, methodMetadata));
        consumerManager.getMethodConsumers(ConsumerLocation.BEFORE_ANNOTATION_PROCESSOR).forEach(consumer -> consumer.accept(classMetadata, methodMetadata));
        this.executeMethodAnnotatedProcessors(contract.onlyMethodDeclaredAnnotations() ? method.getDeclaredAnnotations() : method.getAnnotations(), classMetadata, methodMetadata);
        consumerManager.getMethodConsumers(ConsumerLocation.AFTER_ANNOTATION_PROCESSOR).forEach(consumer -> consumer.accept(classMetadata, methodMetadata));

        int[] idx = {0};
        Arrays.stream(method.getParameters())
                .forEach(parameter -> {
                    int index = idx[0]++;

                    if (!parameter.isNamePresent()) {
                        log.warn("[{}] Parameter name of method '{}' is not present", parameter.getName(), methodMetadata.getConfigKey());
                    }

                    SimpleParameterMetadata parameterMetadata = new SimpleParameterMetadata(parameter, parameter.getParameterizedType());

                    //Parameter Annotation process
                    consumerManager.getParameterConsumers(ConsumerLocation.ON_START).forEach(consumer -> consumer.accept(classMetadata, methodMetadata, parameterMetadata, index));
                    consumerManager.getParameterConsumers(ConsumerLocation.BEFORE_ANNOTATION_PROCESSOR).forEach(consumer -> consumer.accept(classMetadata, methodMetadata, parameterMetadata, index));
                    this.executeParameterAnnotatedProcessors(contract.onlyParameterDeclaredAnnotations() ? parameter.getDeclaredAnnotations() : parameter.getAnnotations(), classMetadata, methodMetadata, parameterMetadata, index);
                    consumerManager.getParameterConsumers(ConsumerLocation.AFTER_ANNOTATION_PROCESSOR).forEach(consumer -> consumer.accept(classMetadata, methodMetadata, parameterMetadata, index));
                    consumerManager.getParameterConsumers(ConsumerLocation.ON_END).forEach(consumer -> consumer.accept(classMetadata, methodMetadata, parameterMetadata, index));

                    methodMetadata.addParameterMetadata(parameterMetadata);
                });

        //Method Annotation process
        consumerManager.getMethodConsumers(ConsumerLocation.ON_END).forEach(consumer -> consumer.accept(classMetadata, methodMetadata));

        return methodMetadata;
    }

    private void executeClassAnnotatedProcessors(Annotation[] annotations, SimpleClassMetadata classMetadata) {
        int[] idx = {0};
        Arrays.stream(annotations).forEach(annotation -> {
            int index = idx[0]++;
            processors.getAnnotatedClassProcessor(annotation.annotationType()).ifPresent(classProcessor -> {
                SimpleAnnotationMetadata annotationMetadata = new SimpleAnnotationMetadata(annotation, index);
                classMetadata.addProcessorResult(annotation.annotationType(), classProcessor.process(annotationMetadata, classMetadata));
                classMetadata.addAnnotation(annotationMetadata);
            });
        });
    }

    private void executeMethodAnnotatedProcessors(Annotation[] annotations, SimpleClassMetadata classMetadata, SimpleMethodMetadata methodMetadata) {
        int[] idx = {0};
        Arrays.stream(annotations).forEach(annotation -> {
            int index = idx[0]++;
            processors.getAnnotatedMethodProcessor(annotation.annotationType()).ifPresent(methodProcessor -> {
                SimpleAnnotationMetadata annotationMetadata = new SimpleAnnotationMetadata(annotation, index);
                methodMetadata.addProcessorResult(annotation.annotationType(), methodProcessor.process(annotationMetadata, classMetadata, methodMetadata));
                methodMetadata.addAnnotation(annotationMetadata);
            });
        });
    }

    private void executeParameterAnnotatedProcessors(Annotation[] annotations, SimpleClassMetadata classMetadata, SimpleMethodMetadata methodMetadata, SimpleParameterMetadata parameterMetadata, int index) {
        Arrays.stream(annotations).forEach(annotation -> processors.getAnnotatedParameterProcessor(annotation.annotationType()).ifPresent(parameterProcessor -> {
            SimpleAnnotationMetadata annotationMetadata = new SimpleAnnotationMetadata(annotation, index);
            parameterMetadata.addProcessorResult(annotation.annotationType(), parameterProcessor.process(annotationMetadata, classMetadata, methodMetadata, parameterMetadata));
            parameterMetadata.addAnnotation(annotationMetadata);
        }));
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy