package com.yvan.mvc;

import org.springframework.beans.ConversionNotSupportedException;
import org.springframework.beans.TypeMismatchException;
import org.springframework.core.MethodParameter;
import org.springframework.web.bind.WebDataBinder;
import org.springframework.web.bind.support.WebDataBinderFactory;
import org.springframework.web.context.request.NativeWebRequest;
import org.springframework.web.method.annotation.MethodArgumentConversionNotSupportedException;
import org.springframework.web.method.annotation.MethodArgumentTypeMismatchException;
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
import org.springframework.web.method.support.ModelAndViewContainer;

public class QueryParamResolver implements HandlerMethodArgumentResolver {

    public boolean supportsParameter(MethodParameter parameter) {
        return parameter.getParameterAnnotation(Pd.class) != null;
    }

    public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer, NativeWebRequest webRequest,
                                  WebDataBinderFactory binderFactory) throws Exception {
        Pd attr = parameter.getParameterAnnotation(Pd.class);
        // here you can use any logic which you need
        Object arg = webRequest.getParameter(attr.name());
        if (arg == null || ((arg instanceof String) && "".equals(arg))) {
            if (attr.required()) {
                throw new ValidateErrorException(attr.name(), attr.desc());
            }
            arg = attr.defaultValue();
        }

        // 以下类型转换，见 org.springframework.web.method.annotation.AbstractNamedValueMethodArgumentResolver 118行
        WebDataBinder binder = binderFactory.createBinder(webRequest, null, attr.name());
        try {
            arg = binder.convertIfNecessary(arg, parameter.getParameterType(), parameter);
        } catch (ConversionNotSupportedException ex) {
            throw new MethodArgumentConversionNotSupportedException(arg, ex.getRequiredType(),
                    attr.name(), parameter, ex.getCause());
        } catch (TypeMismatchException ex) {
            throw new MethodArgumentTypeMismatchException(arg, ex.getRequiredType(),
                    attr.name(), parameter, ex.getCause());

        }
        return arg;
    }
}
