
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