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

com.github.anonymousmister.bootfastconfig.config.JsonPathArgumentResolver Maven / Gradle / Ivy

package com.github.anonymousmister.bootfastconfig.config;


import com.fasterxml.jackson.core.JsonProcessingException;
import com.github.anonymousmister.annotation.HeaderParam;
import com.github.anonymousmister.annotation.JsonParam;
import com.github.anonymousmister.web.WebData;
import com.github.anonymousmister.web.WebdDtaContainer;
import com.jayway.jsonpath.Configuration;
import com.jayway.jsonpath.JsonPath;
import com.jayway.jsonpath.Option;
import com.jayway.jsonpath.PathNotFoundException;


import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.Conventions;
import org.springframework.core.MethodParameter;
import org.springframework.core.annotation.AnnotationUtils;

import org.springframework.util.StringUtils;
import org.springframework.validation.BindingResult;
import org.springframework.validation.Errors;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.MethodArgumentNotValidException;
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.support.HandlerMethodArgumentResolver;
import org.springframework.web.method.support.ModelAndViewContainer;

import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.io.InputStream;
import java.lang.annotation.Annotation;


/**
 * The type Json path argument resolver.
 *
 * @author mister
 */
public abstract class JsonPathArgumentResolver implements HandlerMethodArgumentResolver {

    private final static Logger LOGGER = LoggerFactory.getLogger(JsonPathArgumentResolver.class);

    private static final String JSON_REQUEST_BODY = "$_JSON_REQUEST_BODY_$";


    private final Configuration conf;

    protected JsonPathArgumentResolver() {
        Configuration configuration = Configuration.defaultConfiguration();
        this.conf = configuration.addOptions(Option.DEFAULT_PATH_LEAF_TO_NULL, Option.SUPPRESS_EXCEPTIONS);
    }


    @Override
    public boolean supportsParameter(MethodParameter parameter) {
        return (parameter.hasParameterAnnotation(JsonParam.class) || parameter.hasParameterAnnotation(HeaderParam.class));
    }

    @Override
    public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer, NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception {

        if (parameter.hasParameterAnnotation(HeaderParam.class)) {

            return resolveArgumentHeaderParam(parameter, mavContainer, webRequest, binderFactory);
        }

        return resolveArgumentJsonParam(parameter, mavContainer, webRequest, binderFactory);
    }


    private Object resolveArgumentJsonParam(MethodParameter parameter, ModelAndViewContainer mavContainer, NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception {


        Object arg = readWithMessageConverters(parameter, webRequest);
        String name = Conventions.getVariableNameForParameter(parameter);

        if (binderFactory != null) {
            WebDataBinder binder = binderFactory.createBinder(webRequest, arg, name);
            if (arg != null) {
                validateIfApplicable(binder, parameter);
                if (binder.getBindingResult().hasErrors() && isBindExceptionRequired(binder, parameter)) {
                    throw new MethodArgumentNotValidException(parameter, binder.getBindingResult());
                }
            }
            if (mavContainer != null) {
                mavContainer.addAttribute(BindingResult.MODEL_KEY_PREFIX + name, binder.getBindingResult());
            }
        }

        return arg;
    }


    private Object resolveArgumentHeaderParam(MethodParameter parameter, ModelAndViewContainer mavContainer, NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception {
        String name = parameter.getParameterName();
        HeaderParam headerParam = parameter.getParameterAnnotation(HeaderParam.class);
        if (!StringUtils.isEmpty(headerParam.value())) {
            name = headerParam.value();
        }
        Class parameterType = parameter.getParameterType();
        String[] headerValues = webRequest.getHeaderValues(name);
        if (headerValues == null) {
            return null;
        }
        if (parameterType == String.class) {
            if (headerValues.length == 1) {
                return headerValues[0];
            }
        }
        String jsonData = objectToString(headerValues);
        return objectToClassTypeObject(parameterType, jsonData);

    }


    private void validateIfApplicable(WebDataBinder binder, MethodParameter parameter) {
        Annotation[] annotations = parameter.getParameterAnnotations();
        for (Annotation ann : annotations) {
            Validated validatedAnn = AnnotationUtils.getAnnotation(ann, Validated.class);
            if (validatedAnn != null || ann.annotationType().getSimpleName().startsWith("Valid")) {
                Object hints = (validatedAnn != null ? validatedAnn.value() : AnnotationUtils.getValue(ann));
                Object[] validationHints = (hints instanceof Object[] ? (Object[]) hints : new Object[]{hints});
                binder.validate(validationHints);
                break;
            }
        }
    }

    /**
     * Whether to raise a fatal bind exception on validation errors.
     *
     * @param binder    the data binder used to perform data binding
     * @param parameter the method parameter descriptor
     * @return {@code true} if the next method argument is not of type {@link Errors}
     * @since 4.1.5
     */
    private boolean isBindExceptionRequired(WebDataBinder binder, MethodParameter parameter) {
        int i = parameter.getParameterIndex();
        Class[] paramTypes = parameter.getExecutable().getParameterTypes();
        boolean hasBindingResult = (paramTypes.length > (i + 1) && Errors.class.isAssignableFrom(paramTypes[i + 1]));
        return !hasBindingResult;
    }


    private Object readWithMessageConverters(MethodParameter parameter, NativeWebRequest webRequest) throws IOException {
        String name = parameter.getParameterName();
        JsonParam jsonParam = parameter.getParameterAnnotation(JsonParam.class);
        if (!StringUtils.isEmpty(jsonParam.value())) {
            name = jsonParam.value();
        }
        Class clazz = parameter.getParameterType();
        String jsonData = getData(webRequest, name);
        if (jsonData == null) {
            IsNull(jsonParam, clazz);
            return null;
        }
        Object val = getJsonPath(jsonData, name);
        if (val == null && jsonData != null) {
            val = webRequest.getParameter(name);
        }
        if (val == null) {
            IsNull(jsonParam, clazz);
            return null;
        }

        Class parameterType = parameter.getParameterType();
        Object arg = objectToClassTypeObject(parameterType, val);
        if (arg == null) {
            IsNull(jsonParam, clazz);
            return null;
        }
        WebdDtaContainer.setWebData(new WebData(parameter, arg, val.getClass() == String.class ? (String) val : objectToString(val)));
        return arg;
    }


    /**
     * Object to class type object object.
     *
     * @param c the c
     * @param r the r
     * @return the object
     * @throws JsonProcessingException the json processing exception
     */
    public Object objectToClassTypeObject(Class c, Object r) throws JsonProcessingException {
        if (r == null) {
            return null;
        }
        if (c.isAssignableFrom(r.getClass())) {
            return r;
        }
        if (c == String.class) {
            if (!(r instanceof String)) {
                r = objectToString(r);
            }
            return r;
        }
        r = JsonStringToObject(c, r.getClass() == String.class ? (String) r : objectToString(r));
        return r;
    }

    /**
     * Json string to object object.
     *
     * @param c   the c
     * @param val the val
     * @return the object
     */
    public abstract Object JsonStringToObject(Class c, String val);

    /**
     * Object to string string.
     *
     * @param o the o
     * @return the string
     * @throws JsonProcessingException the json processing exception
     */
    public abstract String objectToString(Object o) throws JsonProcessingException;

    /**
     * Input stream toc t.
     *
     * @param          the type parameter
     * @param inputStream the input stream
     * @param c           the c
     * @return the t
     * @throws IOException the io exception
     */
    public abstract  T inputStreamToc(InputStream inputStream, Class c) throws IOException;

    /**
     * Gets json path.
     *
     * @param jsonData the json data
     * @param name     the name
     * @return the json path
     */
    public Object getJsonPath(String jsonData, String name) {
        Object val = null;
        try {
            val = JsonPath.using(conf).parse(jsonData).read(name);
        } catch (PathNotFoundException | IllegalArgumentException e) {
            /**
             * 这里生吞异常 因为分解参数 不应该影响 主线程的运行
             */
            LOGGER.error("入参解析器出错 在json 为获取到对应的值 ", e);
        }
        return val;
    }

    private String getData(NativeWebRequest webRequest, String name) throws IOException {
        String jsonData = webRequest.getParameter(name);
        if (jsonData == null) {
            HttpServletRequest servletRequest = webRequest.getNativeRequest(HttpServletRequest.class);
            jsonData = (String) servletRequest.getAttribute(JSON_REQUEST_BODY);
            if (jsonData == null) {
                jsonData = webRequest.getParameter(JSON_REQUEST_BODY);
                if (jsonData == null) {
                    jsonData = inputStreamToc(servletRequest.getInputStream(), String.class);
                    servletRequest.setAttribute(JSON_REQUEST_BODY, jsonData);
                }
            }
        }
        return jsonData;
    }


    /**
     * Is null.
     *
     * @param jsonParam the json param
     * @param clazz     the clazz
     */
    public void IsNull(JsonParam jsonParam, Class clazz) {
        if (jsonParam.required()) {
            throw new NullPointerException("");
        }
    }


}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy