Newer
Older
danjiangkou_dajiang / DJI-Cloud-API-Demo-main / src / main / java / com / dji / sdk / config / GetSnakeDataBinder.java
@yanghui yanghui on 24 Jan 4 KB 大疆demo代码提交
package com.dji.sdk.config;

import com.dji.sdk.common.Common;
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonProperty;
import org.springframework.beans.MutablePropertyValues;
import org.springframework.beans.PropertyValue;
import org.springframework.web.servlet.mvc.method.annotation.ExtendedServletRequestDataBinder;

import javax.servlet.ServletRequest;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @author sean
 * @version 1.2
 * @date 2022/9/9
 */
public class GetSnakeDataBinder extends ExtendedServletRequestDataBinder {

    public GetSnakeDataBinder(Object target, String objectName) {
        super(target, objectName);
    }

    @Override
    protected void addBindValues(MutablePropertyValues mpvs, ServletRequest request) {
        List<PropertyValue> propertyValueList = mpvs.getPropertyValueList();
        List<PropertyValue> values = new ArrayList<>(propertyValueList);
        Field[] fields = this.getTarget().getClass().getDeclaredFields();
        Map<String, Field> fieldMap = Arrays.stream(fields).collect(Collectors.toMap(Field::getName, field -> field));
        fieldMap.putAll(Arrays.stream(fields).filter(field ->  null != field.getAnnotation(JsonProperty.class))
                .collect(Collectors.toMap(field -> field.getAnnotation(JsonProperty.class).value(), field -> field)));

        for (PropertyValue property : values) {
            if (!fieldMap.containsKey(property.getName())) {
                continue;
            }

            Field field = fieldMap.get(property.getName());
            List list = (List) Objects.requireNonNullElse(property.getConvertedValue(), new ArrayList<>());
            list.addAll((List) convertValue(field, this.getTarget(), property.getValue()));
            if (!list.isEmpty()) {
                property.setConvertedValue(list);
            }

            String fieldName = field.getName();
            if (fieldName.equals(property.getName())) {
                continue;
            }
            if (mpvs.contains(fieldName)) {
                PropertyValue propertyValue = mpvs.getPropertyValue(fieldName);
                if (null != propertyValue.getConvertedValue()) {
                    ((List) propertyValue.getConvertedValue()).addAll((List) property.getConvertedValue());
                }
            } else {
                mpvs.addPropertyValue(new PropertyValue(fieldName, Objects.requireNonNullElse(property.getConvertedValue(), property.getValue())));
            }
            mpvs.removePropertyValue(property);
        }

        super.addBindValues(mpvs, request);
    }

    private Object convertValue(Field field, Object object, Object value) {
        List convertedValue = new ArrayList();
        if (Enum.class.isAssignableFrom(field.getType())) {
            convertedValue.add(getRealEnumValue(field.getType(), object, value));
        }
        if (field.getType() == field.getGenericType()) {
            return convertedValue;
        }
        if (List.class.isAssignableFrom(field.getType())) {
            if (!value.getClass().isArray()) {
                value = String.valueOf(value).split(",");
            }
            for (String v : (String[]) value) {
                if ("".equals(v)) {
                    continue;
                }
                convertedValue.add(getRealEnumValue((Class) ((ParameterizedType) field.getGenericType()).getActualTypeArguments()[0], object, v));
            }
        }

        return convertedValue;
    }

    private Object getRealEnumValue(Class type, Object object, Object... value) {
        if (!type.isEnum()) {
            return value;
        }
        Set<Method> methods = Arrays.stream(type.getDeclaredMethods())
                .filter(m -> null != m.getAnnotation(JsonCreator.class))
                .filter(m -> m.getParameterTypes().length == value.length).collect(Collectors.toSet());
        for (Method m : methods) {
            try {
                Class<?>[] parameterTypes = m.getParameterTypes();
                for (int i = 0; i < value.length; i++) {
                    value[i] = Common.getObjectMapper().convertValue(value[i], parameterTypes[i]);
                }
                return m.invoke(object, value);
            } catch (IllegalAccessException | InvocationTargetException ignored) {
            }
        }
        return value;
    }
}