Package com.britesnow.snow.web.param.resolver

Source Code of com.britesnow.snow.web.param.resolver.WebParamResolverRegistry

package com.britesnow.snow.web.param.resolver;

import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;

import javax.annotation.Nullable;
import javax.inject.Singleton;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.britesnow.snow.web.binding.WebClasses;
import com.britesnow.snow.web.param.annotation.WebParam;
import com.britesnow.snow.web.param.resolver.annotation.WebParamResolver;
import com.britesnow.snow.web.renderer.freemarker.FreemarkerParamResolvers;
import com.google.inject.Inject;

@Singleton
public class WebParamResolverRegistry {

    @SuppressWarnings("unused")
    static private final Logger                                               logger          = LoggerFactory.getLogger(WebParamResolverRegistry.class);

    private Map<Class, WebParamResolverRef>                                   refByReturnType = new HashMap<Class, WebParamResolverRef>();

    // for now, just support one annotation
    private Map<Class<? extends Annotation>, Map<Class, WebParamResolverRef>> refByAnnotation = new HashMap<Class<? extends Annotation>, Map<Class, WebParamResolverRef>>();

    @Inject(optional = true)
    @Nullable
    @WebClasses
    private Class[]                                                          webClasses;

    /**
     * Must be called before calling registerResolvers. Must be called at init time, no thread safe
     */
    public void init() {
        // first register the SystemWebParamResolvers
        registerWebParamResolvers(SystemWebParamResolvers.class);
        registerWebParamResolvers(FreemarkerParamResolvers.class);

        // then, register the applicaiton WebParamResolvers
        if (webClasses != null) {
            for (Class webClass : webClasses) {
                registerWebParamResolvers(webClass);
            }
        }

    }

    final private void registerWebParamResolvers(Class webResolverClass) {

        //Class cls = WebObjectRegistry.getNonGuiceEnhancedClass(resolversObject);
        Class cls = webResolverClass;

        for (Method method : cls.getMethods()) {
            WebParamResolver webParamResolver = method.getAnnotation(WebParamResolver.class);

            if (webParamResolver != null) {
                WebParamResolverRef ref = new WebParamResolverRef(webParamResolver, cls, method);
                Class returnType = ref.getReturnType();
                Class[] annotatedWith = ref.getAnnotatedWith();

                if (annotatedWith.length == 0) {
                    refByReturnType.put(returnType, ref);
                } else {
                    // for now, support only one annotation
                    // TODO: need to add support for multi annotation
                    Class<? extends Annotation> anCls = annotatedWith[0];
                    Map<Class, WebParamResolverRef> refByType = refByAnnotation.get(anCls);
                    if (refByType == null) {
                        refByType = new HashMap<Class, WebParamResolverRef>();
                        refByAnnotation.put(anCls, refByType);
                    }
                    refByType.put(returnType, ref);
                }
            }

        }

    }

    /**
     * This will return the WebParamResolverRef for webHandlerMethod param at the index paramIdx
     *
     * @param webHandlerMethod
     * @param paramIdx
     * @return
     */
    public WebParamResolverRef getWebParamResolverRef(Method webHandlerMethod, int paramIdx) {
        WebParamResolverRef ref = null;

        Class paramType = webHandlerMethod.getParameterTypes()[paramIdx];

        Annotation[] paramAnnotations = webHandlerMethod.getParameterAnnotations()[paramIdx];
        Annotation paramAnnotation = getFirstAnnotation(paramAnnotations);

        // if we have an annotation, it takes precedence

        // first try to get the annotation
        // TODO: need to support multiple annotations
        if (paramAnnotation != null) {
            Map<Class, WebParamResolverRef> refByType = refByAnnotation.get(paramAnnotation.annotationType());
            if (refByType != null) {
                for (Class type : refByType.keySet()) {
                    if (type.isAssignableFrom(paramType)){
                        ref = findRefForType(paramType, refByType, true);
                        if (ref != null) {
                            break;
                        }
                    }
                }

            }
        }

        // if it is a @WebParam and the refType returnType was just an Object, try to see if we have a direct type resolver with the WebParam
        // NOTE: This makes the @WebParam a default annotation in case it was not specified in the custom returnType binding,
        //       and allows to have the generic System resolveWebParam with Object return type as a fall back.
        // TODO: rather to test with Object.class, we should take the close returnType class to the paramType. It will make it more generic.
        if (ref != null && ref.getReturnType() == Object.class &&  paramAnnotation.annotationType() == WebParam.class){
            WebParamResolverRef tmpRef = findRefForType(paramType,refByReturnType, true);
            if (tmpRef != null){
                ref = tmpRef;
            }
        }
       
        // if could not resolve it with the annotation, try with the type only.
        if (ref == null) {
            ref = findRefForType(paramType,refByReturnType, true);
        }

        return ref;
    }

    private WebParamResolverRef findRefForType(Class paramType,Map<Class,WebParamResolverRef> refByType, boolean withAssignableFrom) {
        WebParamResolverRef ref = null;
        ref = refByType.get(paramType);
        // if still null, then, check the parent classes
        if (ref == null) {
            Class parentClass = paramType.getSuperclass();

            while (parentClass != null && ref == null) {
                ref = refByType.get(parentClass);
                parentClass = parentClass.getSuperclass();
            }
        }

        // if ref still null, then, try to match by isAssignableFrom
        if (withAssignableFrom && ref == null){
            for (Class type : refByType.keySet()) {
                if (type.isAssignableFrom(paramType)){
                    ref = refByType.get(type);
                    if (ref != null) {
                        break;
                    }
                }
            }
        }

        return ref;
    }

    private static Annotation getFirstAnnotation(Annotation[] paramAnnotations) {
        if (paramAnnotations.length > 0){
            return paramAnnotations[0];
        }else{
            return null;
        }
    }

}
TOP

Related Classes of com.britesnow.snow.web.param.resolver.WebParamResolverRegistry

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.