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

net.cassite.pure.ioc.IOCController Maven / Gradle / Ivy

The newest version!
package net.cassite.pure.ioc;

import java.lang.annotation.Annotation;
import java.lang.reflect.Constructor;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;

import net.cassite.pure.ioc.annotations.Singleton;
import net.cassite.pure.ioc.handlers.*;
import net.cassite.pure.ioc.handlers.constructor.ConstructorDefaultFilter;
import net.cassite.pure.ioc.handlers.constructor.DefaultConstructorFilter;
import net.cassite.pure.ioc.handlers.param.*;
import net.cassite.pure.ioc.handlers.type.*;

import static net.cassite.style.Style.*;
import static net.cassite.style.aggregation.Aggregation.*;
import static net.cassite.style.reflect.Reflect.*;

import net.cassite.style.reflect.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * The class is to control the process of handling annotations and constructing
 * objects. 
* Annotation handlers are divided into 4 kinds.
*
    *
  • TypeAnnotationHandler : enabled when constructing objects
  • *
  • ConstructorFilter : enabled when selecting constructors
  • *
  • ParamAnnotationHandler : enabled when getting parameter values of a * constructor
  • *
  • SetterAnnotationHandler : enabled when invoking a setter.
    * (field, method, parameter annotation of a setter are considered as 'setter * annotation'.)
  • *
* All handlers process in a simple logic:
* enable handlers in a chain, low priority handler are earlier to be called, *
* handlers are recommended to call higher priority handlers, check return
* value, then decide whether to run its own handling process. * * @author wkgcass * @see net.cassite.pure.ioc.handlers.TypeHandlerChain * @see net.cassite.pure.ioc.handlers.TypeAnnotationHandler * @see net.cassite.pure.ioc.handlers.type.TypeDefaultHandler * @see net.cassite.pure.ioc.handlers.ConstructorFilterChain * @see net.cassite.pure.ioc.handlers.ConstructorFilter * @see net.cassite.pure.ioc.handlers.ParamHandlerChain * @see net.cassite.pure.ioc.handlers.ParamAnnotationHandler */ public abstract class IOCController { private static final Logger LOGGER = LoggerFactory.getLogger(IOCController.class); // =========================== // ==========handlers========= // =========================== /** * param annotation handlers */ private static List paramAnnotationHandlers = new ArrayList<>(); /** * constructor filters */ private static List constructorFilters = new ArrayList<>(); /** * type annotation handler */ private static List typeAnnotationHandlers = new ArrayList<>(); // ============================ // =========container========== // ============================ /** * singleton class instances
* classes with Singleton annotation * * @see Singleton */ private static Map, Object> singletons = new ConcurrentHashMap<>(); public static final Scope rootScope = new Scope(); static { rootScope.bind(Scope.class, scope -> scope); } protected IOCController() { } /** * get instance by class.
* this method would check TypeHandlerChain to generate instance. * * @param scope wire scope * @param cls class * @param expectingClass the class originally wanted * @return instance handled by type chain */ protected static Object get(Scope scope, Class cls, Class expectingClass) { LOGGER.debug("Invoking get(Class) to get instance of {}", cls); TypeHandlerChain chain = new TypeHandlerChain(typeAnnotationHandlers, cls.getAnnotations()); return chain.next().handle(scope, cls, expectingClass, chain); } @SuppressWarnings("unchecked") protected static void fillField(Scope scope, Object target, @SuppressWarnings("rawtypes") FieldSupport f) { Annotation[] annotations = f.getMember().getAnnotations(); LOGGER.debug("Wiring object {}'s field {} with annotations {}", target, f, annotations); ParamHandlerChain chain = new ParamHandlerChain(paramAnnotationHandlers, annotations); Object obj = chain.next().handle(scope, f, f.getMember().getType(), f.getMember().getType(), annotations, chain); f.set(target, obj); } /** * invoke a setter
* This method would check corresponding field(might not found, that's * unimportant) and method annotations, then go through * SetterHandlerChain. * * @param scope scope * @param target object to invoke * @param m setter */ @SuppressWarnings("unchecked") protected static void invokeSetter(Scope scope, Object target, @SuppressWarnings("rawtypes") MethodSupport m) { LOGGER.debug("Wiring object {}'s method {}", target, m); List> fields = cls(target).allFields(); Set annset = new HashSet<>(); // get inferred field name String fieldName = m.name().substring(3); // try to get field and its annotations ( ignore field name case) If($(fields).findOne(f -> f.name().equalsIgnoreCase(fieldName)), found -> { Collections.addAll(annset, found.getMember().getAnnotations()); }).End(); // try to get method annotations Collections.addAll(annset, m.getMember().getAnnotations()); // parameter value annotations Collections.addAll(annset, m.getMember().getParameterAnnotations()[0]); LOGGER.debug("With Annotations: {}", annset); // handle Annotation[] annoArray = annset.toArray(new Annotation[annset.size()]); ParamHandlerChain chain = new ParamHandlerChain(paramAnnotationHandlers, annoArray); try { Object o = chain.next().handle(scope, m, m.argTypes()[0], m.argTypes()[0], annoArray, chain); m.invoke(target, o); } catch (IrrelevantAnnotationHandlingException | IgnoredAnnotationHandlingException ignore) { } } /** * construct with given class and parameter values. * * @param con constructor to call * @param parameterValues parameter values * @return new instance generated by the constructor and parameterValues */ private static Object construct(ConstructorSup con, Object[] parameterValues) { return con.newInstance(parameterValues); } /** * construct with given class
* this method gets constructor from constructor filter chain, and then * get parameters from ParamHandlerChain.
* finally call {@link #construct(ConstructorSup, Object[])} * * @param scope wire scope * @param cls class to construct * @return instance of the class * @see ParamHandlerChain */ protected static Object constructObject(Scope scope, @SuppressWarnings("rawtypes") Class cls) { LOGGER.debug("Invoking constructObject(Class) to get instance of type {}", cls); Set set = new HashSet<>(); for (Constructor cons : cls.getConstructors()) { Collections.addAll(set, cons.getAnnotations()); } LOGGER.debug("--gathered annotations are {}", set); ConstructorFilterChain chain = new ConstructorFilterChain(constructorFilters, set); @SuppressWarnings("unchecked") ConstructorSup con = chain.next().handle(scope, cls(cls).constructors(), chain); LOGGER.debug("--retrieved constructor is {}", con); Object[] pv = new Object[con.argCount()]; for (int i = 0; i < pv.length; ++i) { ParamHandlerChain chain2 = new ParamHandlerChain(paramAnnotationHandlers, con.getMember().getParameterAnnotations()[i]); pv[i] = chain2.next().handle(scope, con, con.argTypes()[i], con.argTypes()[i], con.getMember().getParameterAnnotations()[i], chain2); LOGGER.debug("--parameter at index {} is {}", i, pv[i]); } return construct(con, pv); } /** * get instance with class.
* this method would check whether it IsSingleton
* then invoke constructObject(Class<?>) to get instance
*
* This method might call singletons.get directly if the singleton class * already in or finished construction or * {@link #constructObject(Scope, Class)}
* Note that, this method will construct the given class, it will * not go through TypeHandlerChain, e.g. it won't find out whether it's * redirected to another class(using Default annotation)
* Use {@link #get(Scope, Class, Class)} to do the type check. * * @param scope wire session * @param cls class to instantiate * @return instance of the class. * @see #constructObject(Scope, Class) * @see #get(Scope, Class, Class) */ @SuppressWarnings("unchecked") protected static Object getObject(Scope scope, @SuppressWarnings("rawtypes") Class cls) { LOGGER.debug("Invoking getObject(Class) to get instance of type {}", cls); if (cls.isAnnotationPresent(Singleton.class)) { LOGGER.debug("--is singleton"); if (singletons.containsKey(cls)) { return singletons.get(cls); } else { return constructObject(scope, cls); } } else { return constructObject(scope, cls); } } /** * This method invokes given method with inferred arguments
* It will check the ParamHandlerChain, and retrieve arguments. * * @param scope wire scope * @param method method to invoke * @param target object of the method to invoke on * @return invocation result * @see ParamHandlerChain */ @SuppressWarnings({"unchecked"}) protected static Object invokeMethod(Scope scope, @SuppressWarnings("rawtypes") MethodSupport method, Object target) { LOGGER.debug("Invoking method {} of object {}", method, target); Object[] pv = new Object[method.argCount()]; for (int i = 0; i < pv.length; ++i) { ParamHandlerChain chain2 = new ParamHandlerChain(paramAnnotationHandlers, method.getMember().getParameterAnnotations()[i]); pv[i] = chain2.next().handle(scope, method, method.argTypes()[i], method.argTypes()[i], method.getMember().getParameterAnnotations()[i], chain2); } return method.invoke(target, pv); } // ================================ // ========register/retrieve======= // ================================ public static void register(ConstructorFilter ah) { LOGGER.info("registering {}", ah); constructorFilters.add(ah); } public static void register(ParamAnnotationHandler ah) { LOGGER.info("registering {}", ah); paramAnnotationHandlers.add(ah); } public static void register(TypeAnnotationHandler ah) { LOGGER.info("registering {}", ah); typeAnnotationHandlers.add(ah); } static void registerSingleton(Object instance) { if (singletons.containsKey(instance.getClass())) { throw new ConstructingMultiSingletonException(instance.getClass()); } if (null != instance.getClass().getAnnotation(Singleton.class)) { singletons.put(instance.getClass(), instance); } } /** * Automatically register built-in handlers */ public static void autoRegister() { LOGGER.info("start auto registering..."); register(new DefaultConstructorFilter()); register(new ConstructorDefaultFilter()); register(new ParamScopeHandler()); register(new PrimitiveParameterHandler()); register(new DefaultParamHandler()); register(new ParamUseHandler()); register(new ParamExtendHandler()); register(new ParamForceHandler()); register(new ParamIgnoreHandler()); register(new TypeAOPHandler()); register(new TypeWireHandler()); register(new DefaultTypeHandler()); register(new TypeIsSingletonHandler()); register(new TypeDefaultHandler()); register(new TypeExtendHandler()); } public static void closeRegistering() { paramAnnotationHandlers = readOnly(paramAnnotationHandlers); constructorFilters = readOnly(constructorFilters); typeAnnotationHandlers = readOnly(typeAnnotationHandlers); LOGGER.info("registration closed."); } /** * determine whether there are handlers registered * * @return true if handlers had been registered, false otherwise */ static boolean isWithHandlers() { return !typeAnnotationHandlers.isEmpty() || !constructorFilters.isEmpty() || !paramAnnotationHandlers.isEmpty(); } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy