com.taobao.rpc.doclet.RPCAPIInfoHelper.java Source code

Java tutorial

Introduction

Here is the source code for com.taobao.rpc.doclet.RPCAPIInfoHelper.java

Source

/*
 * Copyright 2012 Alibaba.com All right reserved. This software is the
 * confidential and proprietary information of Alibaba.com ("Confidential
 * Information"). You shall not disclose such Confidential Information and shall
 * use it only in accordance with the terms of the license agreement you entered
 * into with Alibaba.com.
 */
package com.taobao.rpc.doclet;

import java.beans.PropertyDescriptor;
import java.lang.annotation.Annotation;
import java.lang.reflect.GenericArrayType;
import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.lang.reflect.WildcardType;
import java.net.URL;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
import java.util.List;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanWrapper;
import org.springframework.beans.BeanWrapperImpl;
import org.springframework.core.LocalVariableTableParameterNameDiscoverer;
import org.springframework.util.ClassUtils;
import org.springframework.util.StringUtils;

import sun.reflect.generics.reflectiveObjects.TypeVariableImpl;

import com.alibaba.citrus.extension.rpc.annotation.ResourceMapping;
import com.alibaba.citrus.extension.rpc.annotation.Security;
import com.alibaba.citrus.extension.rpc.databind.File;
import com.alibaba.citrus.extension.rpc.databind.JsonParam;
import com.alibaba.citrus.extension.rpc.databind.PathParam;
import com.alibaba.citrus.extension.rpc.integration.apiinfo.RPCAPIInfo;
import com.alibaba.citrus.extension.rpc.integration.doclet.support.ClassInfo;
import com.alibaba.citrus.extension.rpc.integration.doclet.support.FieldInfo;
import com.alibaba.citrus.extension.rpc.integration.doclet.support.MethodInfo;
import com.alibaba.citrus.extension.rpc.integration.doclet.support.ParameterInfo;
import com.alibaba.citrus.extension.rpc.validation.ErrorContext;
import com.alibaba.nonda.databind.annotation.RequestParam;
import com.alibaba.nonda.databind.annotation.RequestParams;
import com.taobao.rpc.doclet.util.StringUtil;

/**
 * @author ZhangYouQun
 */
@SuppressWarnings("restriction")
public class RPCAPIInfoHelper {

    static final Logger logger = LoggerFactory.getLogger(RPCAPIInfoHelper.class);

    public static RPCAPIInfo getAPIInfo(String realPath, Method method) {
        RPCAPIInfo apiInfo = new RPCAPIInfo();

        ClassInfo classInfo = RPCAPIDocletUtil.getClassInfo(method.getDeclaringClass().getName());
        MethodInfo methodInfo = null;

        if (classInfo != null) {
            methodInfo = classInfo.getMethodInfo(method.getName());
        }

        if (methodInfo != null) {

            apiInfo.setComment(methodInfo.getComment());
        }

        Annotation[][] parameterAnnotations = method.getParameterAnnotations();

        Security securityAnnotation = method.getAnnotation(Security.class);
        ResourceMapping resourceMapping = method.getAnnotation(ResourceMapping.class);

        Object returnType = null;

        returnType = buildTypeStructure(method.getReturnType(), method.getGenericReturnType(), null);

        boolean checkCSRF = false;
        if (securityAnnotation != null) {
            checkCSRF = securityAnnotation.checkCSRF();
        }

        apiInfo.setPattern(realPath.replaceAll("///", "/"));
        apiInfo.setCheckCSRF(checkCSRF);
        apiInfo.setResponseMimes(StringUtils.arrayToDelimitedString(resourceMapping.produces(), ","));
        apiInfo.setHttpMethod(StringUtils.arrayToDelimitedString(resourceMapping.method(), ","));

        List<RPCAPIInfo.Parameter> parameters = new ArrayList<RPCAPIInfo.Parameter>();

        RPCAPIInfo.Parameter parameter = null;
        LocalVariableTableParameterNameDiscoverer nameDiscoverer = new LocalVariableTableParameterNameDiscoverer();
        String[] paramNames = nameDiscoverer.getParameterNames(method);
        int i = 0;

        Class<?>[] parameterTypes = method.getParameterTypes();

        Type[] genericParameterTypes = method.getGenericParameterTypes();

        Class<?> paramType = null;

        Type genericType;

        for (int k = 0; k < parameterTypes.length; k++) {

            paramType = parameterTypes[k];
            genericType = genericParameterTypes[k];

            Annotation[] pAnnotations = parameterAnnotations[i];

            if (HttpServletRequest.class.isAssignableFrom(paramType)
                    || HttpServletResponse.class.isAssignableFrom(paramType)
                    || ErrorContext.class.isAssignableFrom(paramType)) {
                continue;
            } // end if

            String realParamName = paramNames[k];

            if (pAnnotations.length == 0) {

                parameter = apiInfo.new Parameter();
                parameter.setName(realParamName);
                parameter.setType(buildTypeStructure(paramType, genericType, null));
                parameters.add(parameter);

                setParameterComment(parameter, realParamName, methodInfo);

                continue;
            } // end if

            for (Annotation annotation : pAnnotations) {
                parameter = apiInfo.new Parameter();
                setParameterComment(parameter, realParamName, methodInfo);

                if (annotation instanceof RequestParam) {
                    RequestParam requestParam = (RequestParam) annotation;
                    parameter.setName(requestParam.name());
                    parameter.setType(buildTypeStructure(paramType, genericType, null));
                    if (!StringUtil.isBlank(requestParam.defaultValue())) {
                        parameter.setDefaultValue(requestParam.defaultValue().trim());
                    }
                    parameters.add(parameter);
                } else if (annotation instanceof PathParam) {
                    PathParam pathParam = (PathParam) annotation;
                    parameter.setName(pathParam.name());
                    parameter.setType(buildTypeStructure(paramType, genericType, null));
                    if (!StringUtil.isBlank(pathParam.defaultValue())) {
                        parameter.setDefaultValue(pathParam.defaultValue().trim());
                    }
                    parameters.add(parameter);
                } else if (annotation instanceof JsonParam) {
                    JsonParam pathParam = (JsonParam) annotation;
                    parameter.setName(pathParam.value());
                    parameter.setType(buildTypeStructure(paramType, genericType, null));
                    parameters.add(parameter);
                } else if (annotation instanceof RequestParams) {
                    parameter.setName(realParamName);
                    parameter.setType(buildTypeStructure(paramType, genericType, null));
                    parameters.add(parameter);
                } else if (annotation instanceof File) {
                    File file = (File) annotation;
                    parameter.setName(file.value());
                    parameter.setType("");
                    parameters.add(parameter);
                } // end if
            } // end for
            i++;
        } // end for
        apiInfo.setParmeters(parameters);
        apiInfo.setReturnType(returnType);
        return apiInfo;
    }

    private static void setParameterComment(RPCAPIInfo.Parameter parameter, String realParamName,
            MethodInfo methodInfo) {

        if (methodInfo != null) {

            ParameterInfo parameterInfo = methodInfo.getParameterInfo(realParamName);
            if (parameterInfo != null) {

                parameter.setComment(parameterInfo.getComment());
            }
        }
    }

    public static Object buildTypeStructure(Class<?> type) {
        return buildTypeStructure(type, null, null);
    }

    /**
     * ?
     * 
     * @param method
     * @return
     */
    public static Object buildTypeStructure(Class<?> type, Type genericType, Type oriGenericType) {
        if ("void".equalsIgnoreCase(type.getName()) || ClassUtils.isPrimitiveOrWrapper(type)
                || String.class.isAssignableFrom(type) || Date.class.isAssignableFrom(type)
                || URL.class.isAssignableFrom(type)) {
            // 
            return type.getName().replaceAll("java.lang.", "").replaceAll("java.util.", "").replaceAll("java.sql.",
                    "");
        } // end if

        if (type.isArray()) {
            // 
            return new Object[] {
                    buildTypeStructure(type.getComponentType(), type.getComponentType(), genericType) };
        } // end if

        if (ClassUtils.isAssignable(Map.class, type)) {
            // Map
            return Map.class.getName();
        } // end if

        if (type.isEnum()) {
            // Enum
            return Enum.class.getName();
        } // end if

        boolean isCollection = type != null ? Collection.class.isAssignableFrom(type) : false;

        if (isCollection) {

            Type rawType = type;
            if (genericType != null) {
                if (genericType instanceof ParameterizedType) {
                    ParameterizedType _type = (ParameterizedType) genericType;
                    Type[] actualTypeArguments = _type.getActualTypeArguments();
                    rawType = actualTypeArguments[0];

                } else if (genericType instanceof GenericArrayType) {
                    rawType = ((GenericArrayType) genericType).getGenericComponentType();
                }

                if (genericType instanceof WildcardType) {
                    rawType = ((WildcardType) genericType).getUpperBounds()[0];
                }
            }

            if (rawType == type) {

                return new Object[] { rawType.getClass().getName() };
            } else {

                if (rawType.getClass().isAssignableFrom(TypeVariableImpl.class)) {
                    return new Object[] { buildTypeStructure(
                            (Class<?>) ((ParameterizedType) oriGenericType).getActualTypeArguments()[0], rawType,
                            genericType) };
                } else {
                    if (rawType instanceof ParameterizedType) {
                        if (((ParameterizedType) rawType).getRawType() == Map.class) {
                            return new Object[] { Map.class.getName() };
                        }
                    }
                    if (oriGenericType == rawType) {
                        return new Object[] { rawType.getClass().getName() };
                    }
                    return new Object[] { buildTypeStructure((Class<?>) rawType, rawType, genericType) };
                }
            }
        }

        if (type.isInterface()) {
            return type.getName();
        }

        ClassInfo paramClassInfo = RPCAPIDocletUtil.getClassInfo(type.getName());
        //added 
        if (null == paramClassInfo) {
            System.out.println("failed to get paramClassInfo for :" + type.getName());
            return null;
        }

        List<FieldInfo> typeConstructure = new ArrayList<FieldInfo>();

        BeanWrapper bean = new BeanWrapperImpl(type);

        PropertyDescriptor[] propertyDescriptors = bean.getPropertyDescriptors();
        Method readMethod;

        String name;

        for (PropertyDescriptor propertyDescriptor : propertyDescriptors) {
            readMethod = propertyDescriptor.getReadMethod();

            if (readMethod == null || "getClass".equals(readMethod.getName())) {
                continue;
            }

            name = propertyDescriptor.getName();

            FieldInfo fieldInfo = paramClassInfo.getFieldInfo(name);
            if (readMethod.getReturnType().isAssignableFrom(type)) {
                String comment = "structure is the same with parent.";
                typeConstructure
                        .add(FieldInfo.create(name, fieldInfo != null ? fieldInfo.getComment() : "", comment));
            } else {
                typeConstructure.add(
                        FieldInfo.create(name, fieldInfo != null ? fieldInfo.getComment() : "", buildTypeStructure(
                                readMethod.getReturnType(), readMethod.getGenericReturnType(), genericType)));
            } // end if
        }

        return typeConstructure;
    }

}