xiejun
2024-11-01 80b6cbfc9c861469146318d0b3dd5f8b8b525b8a
Source/BladeX-Tool/blade-core-tool/src/main/java/org/springblade/core/tool/convert/StringToEnumConverter.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,126 @@
/*
 *      Copyright (c) 2018-2028, DreamLu All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions are met:
 *
 *  Redistributions of source code must retain the above copyright notice,
 *  this list of conditions and the following disclaimer.
 *  Redistributions in binary form must reproduce the above copyright
 *  notice, this list of conditions and the following disclaimer in the
 *  documentation and/or other materials provided with the distribution.
 *  Neither the name of the dreamlu.net developer nor the names of its
 *  contributors may be used to endorse or promote products derived from
 *  this software without specific prior written permission.
 *  Author: DreamLu å¢æ˜¥æ¢¦ (596392912@qq.com)
 */
package org.springblade.core.tool.convert;
import com.fasterxml.jackson.annotation.JsonCreator;
import lombok.extern.slf4j.Slf4j;
import org.springblade.core.tool.utils.ConvertUtil;
import org.springblade.core.tool.utils.StringUtil;
import org.springframework.core.convert.TypeDescriptor;
import org.springframework.core.convert.converter.ConditionalGenericConverter;
import org.springframework.lang.Nullable;
import java.lang.reflect.AccessibleObject;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
/**
 * æŽ¥æ”¶å‚æ•° åŒ jackson String -》 Enum è½¬æ¢
 *
 * @author L.cm
 */
@Slf4j
public class StringToEnumConverter implements ConditionalGenericConverter {
   /**
    * ç¼“å­˜ Enum ç±»ä¿¡æ¯ï¼Œæä¾›æ€§èƒ½
    */
   private static final ConcurrentMap<Class<?>, AccessibleObject> ENUM_CACHE_MAP = new ConcurrentHashMap<>(8);
   @Nullable
   private static AccessibleObject getAnnotation(Class<?> clazz) {
      Set<AccessibleObject> accessibleObjects = new HashSet<>();
      // JsonCreator METHOD, CONSTRUCTOR
      Constructor<?>[] constructors = clazz.getConstructors();
      Collections.addAll(accessibleObjects, constructors);
      // methods
      Method[] methods = clazz.getDeclaredMethods();
      Collections.addAll(accessibleObjects, methods);
      for (AccessibleObject accessibleObject : accessibleObjects) {
         // å¤ç”¨ jackson çš„ JsonCreator注解
         JsonCreator jsonCreator = accessibleObject.getAnnotation(JsonCreator.class);
         if (jsonCreator != null && JsonCreator.Mode.DISABLED != jsonCreator.mode()) {
            accessibleObject.setAccessible(true);
            return accessibleObject;
         }
      }
      return null;
   }
   @Override
   public boolean matches(TypeDescriptor sourceType, TypeDescriptor targetType) {
      return true;
   }
   @Override
   public Set<ConvertiblePair> getConvertibleTypes() {
      return Collections.singleton(new ConvertiblePair(String.class, Enum.class));
   }
   @Nullable
   @Override
   public Object convert(@Nullable Object source, TypeDescriptor sourceType, TypeDescriptor targetType) {
      if (StringUtil.isBlank((String) source)) {
         return null;
      }
      Class<?> clazz = targetType.getType();
      AccessibleObject accessibleObject = ENUM_CACHE_MAP.computeIfAbsent(clazz, StringToEnumConverter::getAnnotation);
      String value = ((String) source).trim();
      // å¦‚果为null,走默认的转换
      if (accessibleObject == null) {
         return valueOf(clazz, value);
      }
      try {
         return StringToEnumConverter.invoke(clazz, accessibleObject, value);
      } catch (Exception e) {
         log.error(e.getMessage(), e);
      }
      return null;
   }
   @SuppressWarnings("unchecked")
   private static <T extends Enum<T>> T valueOf(Class<?> clazz, String value){
      return Enum.valueOf((Class<T>) clazz, value);
   }
   @Nullable
   private static Object invoke(Class<?> clazz, AccessibleObject accessibleObject, String value)
      throws IllegalAccessException, InvocationTargetException, InstantiationException {
      if (accessibleObject instanceof Constructor) {
         Constructor constructor = (Constructor) accessibleObject;
         Class<?> paramType = constructor.getParameterTypes()[0];
         // ç±»åž‹è½¬æ¢
         Object object = ConvertUtil.convert(value, paramType);
         return constructor.newInstance(object);
      }
      if (accessibleObject instanceof Method) {
         Method method = (Method) accessibleObject;
         Class<?> paramType = method.getParameterTypes()[0];
         // ç±»åž‹è½¬æ¢
         Object object = ConvertUtil.convert(value, paramType);
         return method.invoke(clazz, object);
      }
      return null;
   }
}