content: package com.alibaba.fastjson2.util;
  
  import com.alibaba.fastjson2.*;
  import com.alibaba.fastjson2.reader.ObjectReader;
  import com.alibaba.fastjson2.reader.ObjectReaderImplEnum;
  import com.alibaba.fastjson2.reader.ObjectReaderImplInstant;
  import com.alibaba.fastjson2.reader.ObjectReaderProvider;
  import com.alibaba.fastjson2.writer.ObjectWriter;
  import com.alibaba.fastjson2.writer.ObjectWriterPrimitiveImpl;
  
  import java.lang.invoke.*;
  import java.lang.reflect.*;
  import java.math.BigDecimal;
  import java.math.BigInteger;
  import java.nio.charset.StandardCharsets;
  import java.text.NumberFormat;
  import java.text.ParseException;
  import java.time.*;
  import java.util.*;
  import java.util.concurrent.*;
  import java.util.concurrent.atomic.AtomicBoolean;
  import java.util.concurrent.atomic.AtomicInteger;
  import java.util.concurrent.atomic.AtomicLong;
  import java.util.concurrent.atomic.AtomicReferenceFieldUpdater;
  import java.util.function.*;
  
  import static com.alibaba.fastjson2.util.JDKUtils.*;
  import static java.lang.invoke.MethodType.methodType;
  
  public class TypeUtils {
      public static final Class CLASS_JSON_OBJECT_1x;
      public static final Field FIELD_JSON_OBJECT_1x_map;
      public static final Class CLASS_JSON_ARRAY_1x;
  
      public static final Class CLASS_SINGLE_SET = Collections.singleton(1).getClass();
      public static final Class CLASS_SINGLE_LIST = Collections.singletonList(1).getClass();
      public static final Class CLASS_UNMODIFIABLE_COLLECTION = Collections.unmodifiableCollection(new ArrayList<>()).getClass();
      public static final Class CLASS_UNMODIFIABLE_LIST = Collections.unmodifiableList(new ArrayList<>()).getClass();
      public static final Class CLASS_UNMODIFIABLE_SET = Collections.unmodifiableSet(new HashSet<>()).getClass();
      public static final Class CLASS_UNMODIFIABLE_SORTED_SET = Collections.unmodifiableSortedSet(new TreeSet<>()).getClass();
      public static final Class CLASS_UNMODIFIABLE_NAVIGABLE_SET = Collections.unmodifiableNavigableSet(new TreeSet<>()).getClass();
      public static final ParameterizedType PARAM_TYPE_LIST_STR = new ParameterizedTypeImpl(List.class, String.class);
  
      public static final MethodType METHOD_TYPE_SUPPLIER = MethodType.methodType(Supplier.class);
      public static final MethodType METHOD_TYPE_FUNCTION = MethodType.methodType(Function.class);
      public static final MethodType METHOD_TYPE_TO_INT_FUNCTION = MethodType.methodType(ToIntFunction.class);
      public static final MethodType METHOD_TYPE_TO_LONG_FUNCTION = MethodType.methodType(ToLongFunction.class);
      public static final MethodType METHOD_TYPE_OBJECT_INT_CONSUMER = MethodType.methodType(ObjIntConsumer.class);
      public static final MethodType METHOD_TYPE_INT_FUNCTION = MethodType.methodType(IntFunction.class);
      public static final MethodType METHOD_TYPE_LONG_FUNCTION = MethodType.methodType(LongFunction.class);
      public static final MethodType METHOD_TYPE_BI_FUNCTION = MethodType.methodType(BiFunction.class);
      public static final MethodType METHOD_TYPE_BI_CONSUMER = MethodType.methodType(BiConsumer.class);
      public static final MethodType METHOD_TYPE_VOO = MethodType.methodType(void.class, Object.class, Object.class);
  
      public static final MethodType METHOD_TYPE_OBJECT = MethodType.methodType(Object.class);
      public static final MethodType METHOD_TYPE_OBJECT_OBJECT = MethodType.methodType(Object.class, Object.class);
      public static final MethodType METHOD_TYPE_INT_OBJECT = MethodType.methodType(int.class, Object.class);
      public static final MethodType METHOD_TYPE_LONG_OBJECT = MethodType.methodType(long.class, Object.class);
      public static final MethodType METHOD_TYPE_VOID_OBJECT_INT = MethodType.methodType(void.class, Object.class, int.class);
      public static final MethodType METHOD_TYPE_OBJECT_LONG = MethodType.methodType(Object.class, long.class);
      public static final MethodType METHOD_TYPE_VOID_LONG = MethodType.methodType(void.class, long.class);
      public static final MethodType METHOD_TYPE_OBJECT_OBJECT_OBJECT = MethodType.methodType(Object.class, Object.class, Object.class);
  
      public static final MethodType METHOD_TYPE_VOID = MethodType.methodType(void.class);
      public static final MethodType METHOD_TYPE_VOID_INT = MethodType.methodType(void.class, int.class);
      public static final MethodType METHOD_TYPE_VOID_STRING = MethodType.methodType(void.class, String.class);
      public static final MethodType METHOD_TYPE_OBJECT_INT = MethodType.methodType(Object.class, int.class);
  
      public static final BigInteger BIGINT_INT32_MIN = BigInteger.valueOf(Integer.MIN_VALUE);
      public static final BigInteger BIGINT_INT32_MAX = BigInteger.valueOf(Integer.MAX_VALUE);
      public static final BigInteger BIGINT_INT64_MIN = BigInteger.valueOf(Long.MIN_VALUE);
      public static final BigInteger BIGINT_INT64_MAX = BigInteger.valueOf(Long.MAX_VALUE);
  
      static final long LONG_JAVASCRIPT_LOW = -9007199254740991L;
      static final long LONG_JAVASCRIPT_HIGH = 9007199254740991L;
  
      static final BigInteger BIGINT_JAVASCRIPT_LOW = BigInteger.valueOf(LONG_JAVASCRIPT_LOW);
      static final BigInteger BIGINT_JAVASCRIPT_HIGH = BigInteger.valueOf(LONG_JAVASCRIPT_HIGH);
  
      /**
       * All the positive powers of 10 that can be
       * represented exactly in double/float.
       */
      public static final double[] SMALL_10_POW = {
              1.0e0, 1.0e1, 1.0e2, 1.0e3, 1.0e4,
              1.0e5, 1.0e6, 1.0e7, 1.0e8, 1.0e9,
              1.0e10, 1.0e11, 1.0e12, 1.0e13, 1.0e14,
              1.0e15, 1.0e16, 1.0e17, 1.0e18, 1.0e19,
              1.0e20, 1.0e21, 1.0e22
      };
  
      static final float[] SINGLE_SMALL_10_POW = {
              1.0e0f, 1.0e1f, 1.0e2f, 1.0e3f, 1.0e4f,
              1.0e5f, 1.0e6f, 1.0e7f, 1.0e8f, 1.0e9f,
              1.0e10f
      };
  
      static final double[] BIG_10_POW = {
              1e16, 1e32, 1e64, 1e128, 1e256};
      static final double[] TINY_10_POW = {
              1e-16, 1e-32, 1e-64, 1e-128, 1e-256};
      static volatile boolean METHOD_NEW_PROXY_INSTANCE_ERROR;
      static volatile MethodHandle METHOD_NEW_PROXY_INSTANCE;
  
      public static <T> T newProxyInstance(Class<T> objectClass, JSONObject object) {
          MethodHandle newProxyInstance = METHOD_NEW_PROXY_INSTANCE;
          try {
              if (newProxyInstance == null) {
                  Class<?> proxyClass = Class.forName("java.lang.reflect.Proxy");
                  MethodHandles.Lookup lookup = JDKUtils.trustedLookup(proxyClass);
                  newProxyInstance = lookup.findStatic(
                          proxyClass,
                          "newProxyInstance",
                          methodType(Object.class, ClassLoader.class, Class[].class, InvocationHandler.class)
                  );
                  METHOD_NEW_PROXY_INSTANCE = newProxyInstance;
              }
          } catch (Throwable ignored) {
              METHOD_NEW_PROXY_INSTANCE_ERROR = true;
          }
  
          try {
              return (T) newProxyInstance.invokeExact(objectClass.getClassLoader(), new Class[]{objectClass}, (InvocationHandler) object);
          } catch (Throwable e) {
              throw new JSONException("create proxy error : " + objectClass, e);
          }
      }
  
      static class X1 {
          static final Function<byte[], char[]> TO_CHARS;
  
          static {
              Function<byte[], char[]> toChars = null;
              if (JDKUtils.JVM_VERSION > 9) {
                  try {
                      Class<?> latin1Class = Class.forName("java.lang.StringLatin1");
                      MethodHandles.Lookup lookup = JDKUtils.trustedLookup(latin1Class);
                      MethodHandle handle = lookup.findStatic(
                              latin1Class, "toChars", MethodType.methodType(char[].class, byte[].class)
                      );
  
                      CallSite callSite = LambdaMetafactory.metafactory(
                              lookup,
                              "apply",
                              methodType(Function.class),
                              methodType(Object.class, Object.class),
                              handle,
                              methodType(char[].class, byte[].class)
                      );
                      toChars = (Function<byte[], char[]>) callSite.getTarget().invokeExact();
                  } catch (Throwable ignored) {
                      // ignored
                  }
              }
  
              if (toChars == null) {
                  toChars = TypeUtils::toAsciiCharArray;
              }
              TO_CHARS = toChars;
          }
      }
  
      static class X2 {
          static final String[] chars;
          static final String[] chars2;
          static final char START = ' '; // 32
          static final char END = '~'; // 126
          static final int SIZE2 = (END - START + 1);
  
          static {
              String[] array0 = new String[128];
              for (char i = 0; i < array0.length; i++) {
                  array0[i] = Character.toString(i);
              }
              chars = array0;
  
              String[] array1 = new String[SIZE2 * SIZE2];
              char[] c2 = new char[2];
              for (char i = START; i <= END; i++) {
                  for (char j = START; j <= END; j++) {
                      int value = (i - START) * SIZE2 + (j - START);
                      c2[0] = i;
                      c2[1] = j;
                      array1[value] = new String(c2);
                  }
              }
              chars2 = array1;
          }
      }
  
      static char[] toAsciiCharArray(byte[] bytes) {
          char[] charArray = new char[bytes.length];
          for (int i = 0; i < bytes.length; i++) {
              charArray[i] = (char) bytes[i];
          }
          return charArray;
      }
  
      public static String toString(char ch) {
          if (ch < X2.chars.length) {
              return X2.chars[ch];
          }
          return Character.toString(ch);
      }
  
      public static String toString(byte ch) {
          if (ch >= 0 && ch < X2.chars.length) {
              return X2.chars[ch];
          }
          return new String(new byte[]{ch}, StandardCharsets.ISO_8859_1);
      }
  
      public static String toString(char c0, char c1) {
          if (c0 >= X2.START && c0 <= X2.END && c1 >= X2.START && c1 <= X2.END) {
              int value = (c0 - X2.START) * X2.SIZE2 + (c1 - X2.START);
              return X2.chars2[value];
          }
          return new String(new char[]{c0, c1});
      }
  
      public static String toString(byte c0, byte c1) {
          if (c0 >= X2.START && c0 <= X2.END && c1 >= X2.START && c1 <= X2.END) {
              int value = (c0 - X2.START) * X2.SIZE2 + (c1 - X2.START);
              return X2.chars2[value];
          }
          return new String(new byte[]{c0, c1}, StandardCharsets.ISO_8859_1);
      }
  
      public static Type intern(Type type) {
          if (type instanceof ParameterizedType) {
              ParameterizedType paramType = (ParameterizedType) type;
              Type rawType = paramType.getRawType();
              Type[] actualTypeArguments = paramType.getActualTypeArguments();
              if (rawType == List.class) {
                  if (actualTypeArguments.length == 1) {
                      if (actualTypeArguments[0] == String.class) {
                          return PARAM_TYPE_LIST_STR;
                      }
                  }
              }
          }
          return type;
      }
  
      public static double parseDouble(byte[] in, int off, int len) throws NumberFormatException {
          boolean isNegative = false;
          boolean signSeen = false;
          int decExp;
          byte c;
          int end = off + len;
  
          parseNumber:
          try {
              // throws NullPointerException if null
              if (len == 0) {
                  throw new NumberFormatException("empty String");
              }
              int i = off;
              switch (in[i]) {
                  case '-':
                      isNegative = true;
                  case '+':
                      i++;
                      signSeen = true;
              }
  
              byte[] digits = new byte[len];
  
              int nDigits = 0;
              boolean decSeen = false;
              int decPt = 0;
              int nLeadZero = 0;
              int nTrailZero = 0;
  
              while (i < end) {
                  c = in[i];
                  if (c == '0') {
                      nLeadZero++;
                  } else if (c == '.') {
                      if (decSeen) {
                          throw new NumberFormatException("multiple points");
                      }
                      decPt = i - off;
                      if (signSeen) {
                          decPt -= 1;
                      }
                      decSeen = true;
                  } else {
                      break;
                  }
                  i++;
              }
  
              while (i < end) {
                  c = in[i];
                  if (c >= '1' && c <= '9') {
                      digits[nDigits++] = c;
                      nTrailZero = 0;
                  } else if (c == '0') {
                      digits[nDigits++] = c;
                      nTrailZero++;
                  } else if (c == '.') {
                      if (decSeen) {
                          throw new NumberFormatException("multiple points");
                      }
                      decPt = i - off;
                      if (signSeen) {
                          decPt -= 1;
                      }
                      decSeen = true;
                  } else {
                      break;
                  }
                  i++;
              }
              nDigits -= nTrailZero;
  
              boolean isZero = (nDigits == 0);
              if (isZero && nLeadZero == 0) {
                  break parseNumber; // go throw exception
              }
              if (decSeen) {
                  decExp = decPt - nLeadZero;
              } else {
                  decExp = nDigits + nTrailZero;
              }
  
              if ((i < end) && (((c = in[i]) == 'e') || (c == 'E'))) {
                  int expSign = 1;
                  int expVal = 0;
                  int reallyBig = Integer.MAX_VALUE / 10;
                  boolean expOverflow = false;
                  switch (in[++i]) {
                      case '-':
                          expSign = -1;
                      case '+':
                          i++;
                  }
                  int expAt = i;
                  while (i < end) {
                      if (expVal >= reallyBig) {
                          expOverflow = true;
                      }
                      c = in[i++];
                      if (c >= '0' && c <= '9') {
                          expVal = expVal * 10 + ((int) c - (int) '0');
                      } else {
                          i--;           // back up.
                          break; // stop parsing exponent.
                      }
                  }
                  final int BIG_DECIMAL_EXPONENT = 324;
                  int expLimit = BIG_DECIMAL_EXPONENT + nDigits + nTrailZero;
                  if (expOverflow || (expVal > expLimit)) {
                      decExp = expSign * expLimit;
                  } else {
                      decExp = decExp + expSign * expVal;
                  }
  
                  if (i == expAt) {
                      break parseNumber; // certainly bad
                  }
              }
  
              if (i < end && (i != end - 1)) {
                  break parseNumber; // go throw exception
              }
              if (isZero) {
                  return isNegative ? -0D : 0D;
              }
              return doubleValue(isNegative, decExp, digits, nDigits);
          } catch (StringIndexOutOfBoundsException ignored) {
              // ignored
          }
          throw new NumberFormatException("For input string: \"" + new String(in, off, len) + "\"");
      }
  
      public static double parseDouble(char[] in, int off, int len) throws NumberFormatException {
          boolean isNegative = false;
          boolean signSeen = false;
          int decExp;
          char c;
          int end = off + len;
  
          parseNumber:
          try {
              // throws NullPointerException if null
              if (len == 0) {
                  throw new NumberFormatException("empty String");
              }
              int i = off;
              switch (in[i]) {
                  case '-':
                      isNegative = true;
                  case '+':
                      i++;
                      signSeen = true;
              }
  
              byte[] digits = new byte[len];
  
              int nDigits = 0;
              boolean decSeen = false;
              int decPt = 0;
              int nLeadZero = 0;
              int nTrailZero = 0;
  
              while (i < end) {
                  c = in[i];
                  if (c == '0') {
                      nLeadZero++;
                  } else if (c == '.') {
                      if (decSeen) {
                          throw new NumberFormatException("multiple points");
                      }
                      decPt = i - off;
                      if (signSeen) {
                          decPt -= 1;
                      }
                      decSeen = true;
                  } else {
                      break;
                  }
                  i++;
              }
  
              while (i < end) {
                  c = in[i];
                  if (c >= '1' && c <= '9') {
                      digits[nDigits++] = (byte) c;
                      nTrailZero = 0;
                  } else if (c == '0') {
                      digits[nDigits++] = (byte) c;
                      nTrailZero++;
                  } else if (c == '.') {
                      if (decSeen) {
                          throw new NumberFormatException("multiple points");
                      }
                      decPt = i - off;
                      if (signSeen) {
                          decPt -= 1;
                      }
                      decSeen = true;
                  } else {
                      break;
                  }
                  i++;
              }
              nDigits -= nTrailZero;
  
              boolean isZero = (nDigits == 0);
              if (isZero && nLeadZero == 0) {
                  break parseNumber; // go throw exception
              }
              if (decSeen) {
                  decExp = decPt - nLeadZero;
              } else {
                  decExp = nDigits + nTrailZero;
              }
  
              if ((i < end) && (((c = in[i]) == 'e') || (c == 'E'))) {
                  int expSign = 1;
                  int expVal = 0;
                  int reallyBig = Integer.MAX_VALUE / 10;
                  boolean expOverflow = false;
                  switch (in[++i]) {
                      case '-':
                          expSign = -1;
                      case '+':
                          i++;
                  }
                  int expAt = i;
  
                  while (i < end) {
                      if (expVal >= reallyBig) {
                          expOverflow = true;
                      }
                      c = in[i++];
                      if (c >= '0' && c <= '9') {
                          expVal = expVal * 10 + ((int) c - (int) '0');
                      } else {
                          i--;           // back up.
                          break; // stop parsing exponent.
                      }
                  }
                  final int BIG_DECIMAL_EXPONENT = 324;
                  int expLimit = BIG_DECIMAL_EXPONENT + nDigits + nTrailZero;
                  if (expOverflow || (expVal > expLimit)) {
                      decExp = expSign * expLimit;
                  } else {
                      decExp = decExp + expSign * expVal;
                  }
  
                  if (i == expAt) {
                      break parseNumber; // certainly bad
                  }
              }
  
              if (i < end && (i != end - 1)) {
                  break parseNumber; // go throw exception
              }
              if (isZero) {
                  return isNegative ? -0D : 0D;
              }
              return doubleValue(isNegative, decExp, digits, nDigits);
          } catch (StringIndexOutOfBoundsException ignored) {
              // ignored
          }
          throw new NumberFormatException("For input string: \"" + new String(in, off, len) + "\"");
      }
  
      public static float parseFloat(byte[] in, int off, int len) throws NumberFormatException {
          boolean isNegative = false;
          boolean signSeen = false;
          int decExp;
          byte c;
          int end = off + len;
  
          parseNumber:
          try {
              // throws NullPointerException if null
              if (len == 0) {
                  throw new NumberFormatException("empty String");
              }
              int i = off;
              switch (in[i]) {
                  case '-':
                      isNegative = true;
                  case '+':
                      i++;
                      signSeen = true;
              }
  
              byte[] digits = new byte[len];
  
              int nDigits = 0;
              boolean decSeen = false;
              int decPt = 0;
              int nLeadZero = 0;
              int nTrailZero = 0;
  
              while (i < end) {
                  c = in[i];
                  if (c == '0') {
                      nLeadZero++;
                  } else if (c == '.') {
                      if (decSeen) {
                          throw new NumberFormatException("multiple points");
                      }
                      decPt = i - off;
                      if (signSeen) {
                          decPt -= 1;
                      }
                      decSeen = true;
                  } else {
                      break;
                  }
                  i++;
              }
  
              while (i < end) {
                  c = in[i];
                  if (c >= '1' && c <= '9') {
                      digits[nDigits++] = c;
                      nTrailZero = 0;
                  } else if (c == '0') {
                      digits[nDigits++] = c;
                      nTrailZero++;
                  } else if (c == '.') {
                      if (decSeen) {
                          throw new NumberFormatException("multiple points");
                      }
                      decPt = i - off;
                      if (signSeen) {
                          decPt -= 1;
                      }
                      decSeen = true;
                  } else {
                      break;
                  }
                  i++;
              }
              nDigits -= nTrailZero;
  
              boolean isZero = (nDigits == 0);
              if (isZero && nLeadZero == 0) {
                  break parseNumber; // go throw exception
              }
              if (decSeen) {
                  decExp = decPt - nLeadZero;
              } else {
                  decExp = nDigits + nTrailZero;
              }
  
              if ((i < end) && (((c = in[i]) == 'e') || (c == 'E'))) {
                  int expSign = 1;
                  int expVal = 0;
                  int reallyBig = Integer.MAX_VALUE / 10;
                  boolean expOverflow = false;
                  switch (in[++i]) {
                      case '-':
                          expSign = -1;
                      case '+':
                          i++;
                  }
                  int expAt = i;
  
                  while (i < end) {
                      if (expVal >= reallyBig) {
                          expOverflow = true;
                      }
                      c = in[i++];
                      if (c >= '0' && c <= '9') {
                          expVal = expVal * 10 + ((int) c - (int) '0');
                      } else {
                          i--;           // back up.
                          break; // stop parsing exponent.
                      }
                  }
                  final int BIG_DECIMAL_EXPONENT = 324;
                  int expLimit = BIG_DECIMAL_EXPONENT + nDigits + nTrailZero;
                  if (expOverflow || (expVal > expLimit)) {
                      decExp = expSign * expLimit;
                  } else {
                      decExp = decExp + expSign * expVal;
                  }
  
                  if (i == expAt) {
                      break parseNumber; // certainly bad
                  }
              }
  
              if (i < end && (i != end - 1)) {
                  break parseNumber; // go throw exception
              }
              if (isZero) {
                  return isNegative ? -0F : 0F;
              }
              return floatValue(isNegative, decExp, digits, nDigits);
          } catch (StringIndexOutOfBoundsException ignored) {
              // ignored
          }
          throw new NumberFormatException("For input string: \"" + new String(in, off, len) + "\"");
      }
  
      public static float parseFloat(char[] in, int off, int len) throws NumberFormatException {
          boolean isNegative = false;
          boolean signSeen = false;
          int decExp;
          char c;
          int end = off + len;
  
          parseNumber:
          try {
              // throws NullPointerException if null
              if (len == 0) {
                  throw new NumberFormatException("empty String");
              }
              int i = off;
              switch (in[i]) {
                  case '-':
                      isNegative = true;
                  case '+':
                      i++;
                      signSeen = true;
              }
  
              byte[] digits = new byte[len];
  
              int nDigits = 0;
              boolean decSeen = false;
              int decPt = 0;
              int nLeadZero = 0;
              int nTrailZero = 0;
  
              while (i < end) {
                  c = in[i];
                  if (c == '0') {
                      nLeadZero++;
                  } else if (c == '.') {
                      if (decSeen) {
                          throw new NumberFormatException("multiple points");
                      }
                      decPt = i - off;
                      if (signSeen) {
                          decPt -= 1;
                      }
                      decSeen = true;
                  } else {
                      break;
                  }
                  i++;
              }
  
              while (i < end) {
                  c = in[i];
                  if (c >= '1' && c <= '9') {
                      digits[nDigits++] = (byte) c;
                      nTrailZero = 0;
                  } else if (c == '0') {
                      digits[nDigits++] = (byte) c;
                      nTrailZero++;
                  } else if (c == '.') {
                      if (decSeen) {
                          throw new NumberFormatException("multiple points");
                      }
                      decPt = i - off;
                      if (signSeen) {
                          decPt -= 1;
                      }
                      decSeen = true;
                  } else {
                      break;
                  }
                  i++;
              }
              nDigits -= nTrailZero;
  
              boolean isZero = (nDigits == 0);
              if (isZero && nLeadZero == 0) {
                  break parseNumber; // go throw exception
              }
              if (decSeen) {
                  decExp = decPt - nLeadZero;
              } else {
                  decExp = nDigits + nTrailZero;
              }
  
              if ((i < end) && (((c = in[i]) == 'e') || (c == 'E'))) {
                  int expSign = 1;
                  int expVal = 0;
                  int reallyBig = Integer.MAX_VALUE / 10;
                  boolean expOverflow = false;
                  switch (in[++i]) {
                      case '-':
                          expSign = -1;
                      case '+':
                          i++;
                  }
                  int expAt = i;
                  while (i < end) {
                      if (expVal >= reallyBig) {
                          expOverflow = true;
                      }
                      c = in[i++];
                      if (c >= '0' && c <= '9') {
                          expVal = expVal * 10 + ((int) c - (int) '0');
                      } else {
                          i--;           // back up.
                          break; // stop parsing exponent.
                      }
                  }
                  final int BIG_DECIMAL_EXPONENT = 324;
                  int expLimit = BIG_DECIMAL_EXPONENT + nDigits + nTrailZero;
                  if (expOverflow || (expVal > expLimit)) {
                      decExp = expSign * expLimit;
                  } else {
                      decExp = decExp + expSign * expVal;
                  }
  
                  if (i == expAt) {
                      break parseNumber; // certainly bad
                  }
              }
  
              if (i < end && (i != end - 1)) {
                  break parseNumber; // go throw exception
              }
              if (isZero) {
                  return isNegative ? -0F : 0F;
              }
              return floatValue(isNegative, decExp, digits, nDigits);
          } catch (StringIndexOutOfBoundsException ignored) {
              // ignored
          }
          throw new NumberFormatException("For input string: \"" + new String(in, off, len) + "\"");
      }
  
      public static double doubleValue(boolean isNegative, int decExp, byte[] digits, int nDigits) {
          final int MAX_DECIMAL_EXPONENT = 308;
          final int MIN_DECIMAL_EXPONENT = -324;
          final int MAX_NDIGITS = 1100;
          final int INT_DECIMAL_DIGITS = 9;
          final int MAX_DECIMAL_DIGITS = 15;
          final int DOUBLE_EXP_BIAS = 1023;
          final int EXP_SHIFT = 53 /*DOUBLE_SIGNIFICAND_WIDTH*/ - 1;
          final long FRACT_HOB = (1L << EXP_SHIFT); // assumed High-Order bit
          final int MAX_SMALL_TEN = SMALL_10_POW.length - 1;
  
          int kDigits = Math.min(nDigits, MAX_DECIMAL_DIGITS + 1);
  
          int iValue = (int) digits[0] - (int) '0';
          int iDigits = Math.min(kDigits, INT_DECIMAL_DIGITS);
          for (int i = 1; i < iDigits; i++) {
              iValue = iValue * 10 + (int) digits[i] - (int) '0';
          }
          long lValue = iValue;
          for (int i = iDigits; i < kDigits; i++) {
              lValue = lValue * 10L + (long) ((int) digits[i] - (int) '0');
          }
          double dValue = (double) lValue;
          int exp = decExp - kDigits;
  
          if (nDigits <= MAX_DECIMAL_DIGITS) {
              if (exp == 0 || dValue == 0.0) {
                  return (isNegative) ? -dValue : dValue; // small floating integer
              } else if (exp >= 0) {
                  if (exp <= MAX_SMALL_TEN) {
                      double rValue = dValue * SMALL_10_POW[exp];
                      return (isNegative) ? -rValue : rValue;
                  }
                  int slop = MAX_DECIMAL_DIGITS - kDigits;
                  if (exp <= MAX_SMALL_TEN + slop) {
                      dValue *= SMALL_10_POW[slop];
                      double rValue = dValue * SMALL_10_POW[exp - slop];
                      return (isNegative) ? -rValue : rValue;
                  }
              } else {
                  if (exp >= -MAX_SMALL_TEN) {
                      double rValue = dValue / SMALL_10_POW[-exp];
                      return (isNegative) ? -rValue : rValue;
                  }
              }
          }
  
          if (exp > 0) {
              if (decExp > MAX_DECIMAL_EXPONENT + 1) {
                  return (isNegative) ? Double.NEGATIVE_INFINITY : Double.POSITIVE_INFINITY;
              }
              if ((exp & 15) != 0) {
                  dValue *= SMALL_10_POW[exp & 15];
              }
              if ((exp >>= 4) != 0) {
                  int j;
                  for (j = 0; exp > 1; j++, exp >>= 1) {
                      if ((exp & 1) != 0) {
                          dValue *= BIG_10_POW[j];
                      }
                  }
  
                  double t = dValue * BIG_10_POW[j];
                  if (Double.isInfinite(t)) {
                      t = dValue / 2.0;
                      t *= BIG_10_POW[j];
                      if (Double.isInfinite(t)) {
                          return (isNegative) ? Double.NEGATIVE_INFINITY : Double.POSITIVE_INFINITY;
                      }
                      t = Double.MAX_VALUE;
                  }
                  dValue = t;
              }
          } else if (exp < 0) {
              exp = -exp;
              if (decExp < MIN_DECIMAL_EXPONENT - 1) {
                  return (isNegative) ? -0.0 : 0.0;
              }
              if ((exp & 15) != 0) {
                  dValue /= SMALL_10_POW[exp & 15];
              }
              if ((exp >>= 4) != 0) {
                  int j;
                  for (j = 0; exp > 1; j++, exp >>= 1) {
                      if ((exp & 1) != 0) {
                          dValue *= TINY_10_POW[j];
                      }
                  }
  
                  double t = dValue * TINY_10_POW[j];
                  if (t == 0.0) {
                      t = dValue * 2.0;
                      t *= TINY_10_POW[j];
                      if (t == 0.0) {
                          return (isNegative) ? -0.0 : 0.0;
                      }
                      t = Double.MIN_VALUE;
                  }
                  dValue = t;
              }
          }
  
          if (nDigits > MAX_NDIGITS) {
              nDigits = MAX_NDIGITS + 1;
              digits[MAX_NDIGITS] = '1';
          }
          FDBigInteger bigD0 = new FDBigInteger(lValue, digits, kDigits, nDigits);
          exp = decExp - nDigits;
  
          long ieeeBits = Double.doubleToRawLongBits(dValue); // IEEE-754 bits of double candidate
          final int B5 = Math.max(0, -exp); // powers of 5 in bigB, value is not modified inside correctionLoop
          final int D5 = Math.max(0, exp); // powers of 5 in bigD, value is not modified inside correctionLoop
          bigD0 = bigD0.multByPow52(D5, 0);
          bigD0.makeImmutable();   // prevent bigD0 modification inside correctionLoop
          FDBigInteger bigD = null;
          int prevD2 = 0;
  
          while (true) {
              // here ieeeBits can't be NaN, Infinity or zero
              int binexp = (int) (ieeeBits >>> EXP_SHIFT);
              final long DOUBLE_SIGNIF_BIT_MASK = 0x000FFFFFFFFFFFFFL;
              long bigBbits = ieeeBits & DOUBLE_SIGNIF_BIT_MASK;
              if (binexp > 0) {
                  bigBbits |= FRACT_HOB;
              } else { // Normalize denormalized numbers.
                  assert bigBbits != 0L : bigBbits; // doubleToBigInt(0.0)
                  int leadingZeros = Long.numberOfLeadingZeros(bigBbits);
                  int shift = leadingZeros - (63 - EXP_SHIFT);
                  bigBbits <<= shift;
                  binexp = 1 - shift;
              }
              binexp -= DOUBLE_EXP_BIAS;
              int lowOrderZeros = Long.numberOfTrailingZeros(bigBbits);
              bigBbits >>>= lowOrderZeros;
              final int bigIntExp = binexp - EXP_SHIFT + lowOrderZeros;
              final int bigIntNBits = EXP_SHIFT + 1 - lowOrderZeros;
  
              int B2 = B5; // powers of 2 in bigB
              int D2 = D5; // powers of 2 in bigD
              int Ulp2;   // powers of 2 in halfUlp.
              if (bigIntExp >= 0) {
                  B2 += bigIntExp;
              } else {
                  D2 -= bigIntExp;
              }
              Ulp2 = B2;
              // shift bigB and bigD left by a number s. t.
              // halfUlp is still an integer.
              int hulpbias;
              if (binexp <= -DOUBLE_EXP_BIAS) {
                  // This is going to be a denormalized number
                  // (if not actually zero).
                  // half an ULP is at 2^-(EXP_BIAS+EXP_SHIFT+1)
                  hulpbias = binexp + lowOrderZeros + DOUBLE_EXP_BIAS;
              } else {
                  hulpbias = 1 + lowOrderZeros;
              }
              B2 += hulpbias;
              D2 += hulpbias;
              // if there are common factors of 2, we might just as well
              // factor them out, as they add nothing useful.
              int common2 = Math.min(B2, Math.min(D2, Ulp2));
              B2 -= common2;
              D2 -= common2;
              Ulp2 -= common2;
              // do multiplications by powers of 5 and 2
              FDBigInteger bigB = FDBigInteger.valueOfMulPow52(bigBbits, B5, B2);
              if (bigD == null || prevD2 != D2) {
                  bigD = bigD0.leftShift(D2);
                  prevD2 = D2;
              }
  
              FDBigInteger diff;
              int cmpResult;
              boolean overvalue;
              if ((cmpResult = bigB.cmp(bigD)) > 0) {
                  overvalue = true; // our candidate is too big.
                  diff = bigB.leftInplaceSub(bigD); // bigB is not user further - reuse
                  if ((bigIntNBits == 1) && (bigIntExp > -DOUBLE_EXP_BIAS + 1)) {
                      // candidate is a normalized exact power of 2 and
                      // is too big (larger than Double.MIN_NORMAL). We will be subtracting.
                      // For our purposes, ulp is the ulp of the
                      // next smaller range.
                      Ulp2 -= 1;
                      if (Ulp2 < 0) {
                          // rats. Cannot de-scale ulp this far.
                          // must scale diff in other direction.
                          Ulp2 = 0;
                          diff = diff.leftShift(1);
                      }
                  }
              } else if (cmpResult < 0) {
                  overvalue = false; // our candidate is too small.
                  diff = bigD.rightInplaceSub(bigB); // bigB is not user further - reuse
              } else {
                  // the candidate is exactly right!
                  // this happens with surprising frequency
                  break;
              }
              cmpResult = diff.cmpPow52(B5, Ulp2);
              if ((cmpResult) < 0) {
                  // difference is small.
                  // this is close enough
                  break;
              } else if (cmpResult == 0) {
                  // difference is exactly half an ULP
                  // round to some other value maybe, then finish
                  if ((ieeeBits & 1) != 0) { // half ties to even
                      ieeeBits += overvalue ? -1 : 1; // nextDown or nextUp
                  }
                  break;
              } else {
                  // difference is non-trivial.
                  // could scale addend by ratio of difference to
                  // halfUlp here, if we bothered to compute that difference.
                  // Most of the time ( I hope ) it is about 1 anyway.
                  ieeeBits += overvalue ? -1 : 1; // nextDown or nextUp
                  final long DOUBLE_EXP_BIT_MASK = 0x7FF0000000000000L;
                  if (ieeeBits == 0 || ieeeBits == DOUBLE_EXP_BIT_MASK) { // 0.0 or Double.POSITIVE_INFINITY
                      break; // oops. Fell off end of range.
                  }
                  // try again.
              }
          }
          if (isNegative) {
              final long DOUBLE_SIGN_BIT_MASK = 0x8000000000000000L;
              ieeeBits |= DOUBLE_SIGN_BIT_MASK;
          }
          return Double.longBitsToDouble(ieeeBits);
      }
  
      public static float floatValue(boolean isNegative, int decExponent, byte[] digits, int nDigits) {
          final int SINGLE_MAX_NDIGITS = 200;
          final int SINGLE_MAX_DECIMAL_DIGITS = 7;
          final int MAX_DECIMAL_DIGITS = 15;
          final int FLOAT_EXP_BIAS = 127;
          final int SINGLE_EXP_SHIFT = 24 /*FLOAT_SIGNIFICAND_WIDTH*/ - 1;
          final int SINGLE_MAX_SMALL_TEN = SINGLE_SMALL_10_POW.length - 1;
  
          int kDigits = Math.min(nDigits, SINGLE_MAX_DECIMAL_DIGITS + 1);
          int iValue = (int) digits[0] - (int) '0';
          for (int i = 1; i < kDigits; i++) {
              iValue = iValue * 10 + (int) digits[i] - (int) '0';
          }
          float fValue = (float) iValue;
          int exp = decExponent - kDigits;
  
          if (nDigits <= SINGLE_MAX_DECIMAL_DIGITS) {
              if (exp == 0 || fValue == 0.0f) {
                  return (isNegative) ? -fValue : fValue; // small floating integer
              } else if (exp >= 0) {
                  if (exp <= SINGLE_MAX_SMALL_TEN) {
                      fValue *= SINGLE_SMALL_10_POW[exp];
                      return (isNegative) ? -fValue : fValue;
                  }
                  int slop = SINGLE_MAX_DECIMAL_DIGITS - kDigits;
                  if (exp <= SINGLE_MAX_SMALL_TEN + slop) {
                      fValue *= SINGLE_SMALL_10_POW[slop];
                      fValue *= SINGLE_SMALL_10_POW[exp - slop];
                      return (isNegative) ? -fValue : fValue;
                  }
              } else {
                  if (exp >= -SINGLE_MAX_SMALL_TEN) {
                      fValue /= SINGLE_SMALL_10_POW[-exp];
                      return (isNegative) ? -fValue : fValue;
                  }
              }
          } else if ((decExponent >= nDigits) && (nDigits + decExponent <= MAX_DECIMAL_DIGITS)) {
              long lValue = iValue;
              for (int i = kDigits; i < nDigits; i++) {
                  lValue = lValue * 10L + (long) ((int) digits[i] - (int) '0');
              }
              double dValue = (double) lValue;
              exp = decExponent - nDigits;
              dValue *= SMALL_10_POW[exp];
              fValue = (float) dValue;
              return (isNegative) ? -fValue : fValue;
          }
          double dValue = fValue;
          if (exp > 0) {
              final int SINGLE_MAX_DECIMAL_EXPONENT = 38;
              if (decExponent > SINGLE_MAX_DECIMAL_EXPONENT + 1) {
                  return (isNegative) ? Float.NEGATIVE_INFINITY : Float.POSITIVE_INFINITY;
              }
              if ((exp & 15) != 0) {
                  dValue *= SMALL_10_POW[exp & 15];
              }
              if ((exp >>= 4) != 0) {
                  int j;
                  for (j = 0; exp > 0; j++, exp >>= 1) {
                      if ((exp & 1) != 0) {
                          dValue *= BIG_10_POW[j];
                      }
                  }
              }
          } else if (exp < 0) {
              exp = -exp;
              final int SINGLE_MIN_DECIMAL_EXPONENT = -45;
              if (decExponent < SINGLE_MIN_DECIMAL_EXPONENT - 1) {
                  return (isNegative) ? -0.0f : 0.0f;
              }
              if ((exp & 15) != 0) {
                  dValue /= SMALL_10_POW[exp & 15];
              }
              if ((exp >>= 4) != 0) {
                  int j;
                  for (j = 0; exp > 0; j++, exp >>= 1) {
                      if ((exp & 1) != 0) {
                          dValue *= TINY_10_POW[j];
                      }
                  }
              }
          }
          fValue = Math.max(Float.MIN_VALUE, Math.min(Float.MAX_VALUE, (float) dValue));
  
          if (nDigits > SINGLE_MAX_NDIGITS) {
              nDigits = SINGLE_MAX_NDIGITS + 1;
              digits[SINGLE_MAX_NDIGITS] = '1';
          }
          FDBigInteger bigD0 = new FDBigInteger(iValue, digits, kDigits, nDigits);
          exp = decExponent - nDigits;
  
          int ieeeBits = Float.floatToRawIntBits(fValue); // IEEE-754 bits of float candidate
          final int B5 = Math.max(0, -exp); // powers of 5 in bigB, value is not modified inside correctionLoop
          final int D5 = Math.max(0, exp); // powers of 5 in bigD, value is not modified inside correctionLoop
          bigD0 = bigD0.multByPow52(D5, 0);
          bigD0.makeImmutable();   // prevent bigD0 modification inside correctionLoop
          FDBigInteger bigD = null;
          int prevD2 = 0;
  
          while (true) {
              // here ieeeBits can't be NaN, Infinity or zero
              int binexp = ieeeBits >>> SINGLE_EXP_SHIFT;
              final int FLOAT_SIGNIF_BIT_MASK = 0x007FFFFF;
              int bigBbits = ieeeBits & FLOAT_SIGNIF_BIT_MASK;
              if (binexp > 0) {
                  final int SINGLE_FRACT_HOB = 1 << 23;
                  bigBbits |= SINGLE_FRACT_HOB;
              } else { // Normalize denormalized numbers.
                  assert bigBbits != 0 : bigBbits; // floatToBigInt(0.0)
                  int leadingZeros = Integer.numberOfLeadingZeros(bigBbits);
                  int shift = leadingZeros - (31 - SINGLE_EXP_SHIFT);
                  bigBbits <<= shift;
                  binexp = 1 - shift;
              }
              binexp -= FLOAT_EXP_BIAS;
              int lowOrderZeros = Integer.numberOfTrailingZeros(bigBbits);
              bigBbits >>>= lowOrderZeros;
              final int bigIntExp = binexp - SINGLE_EXP_SHIFT + lowOrderZeros;
              final int bigIntNBits = SINGLE_EXP_SHIFT + 1 - lowOrderZeros;
  
              int B2 = B5; // powers of 2 in bigB
              int D2 = D5; // powers of 2 in bigD
              int Ulp2;   // powers of 2 in halfUlp.
              if (bigIntExp >= 0) {
                  B2 += bigIntExp;
              } else {
                  D2 -= bigIntExp;
              }
              Ulp2 = B2;
  
              int hulpbias;
              if (binexp <= -FLOAT_EXP_BIAS) {
                  hulpbias = binexp + lowOrderZeros + FLOAT_EXP_BIAS;
              } else {
                  hulpbias = 1 + lowOrderZeros;
              }
              B2 += hulpbias;
              D2 += hulpbias;
  
              int common2 = Math.min(B2, Math.min(D2, Ulp2));
              B2 -= common2;
              D2 -= common2;
              Ulp2 -= common2;
              // do multiplications by powers of 5 and 2
              FDBigInteger bigB = FDBigInteger.valueOfMulPow52(bigBbits, B5, B2);
              if (bigD == null || prevD2 != D2) {
                  bigD = bigD0.leftShift(D2);
                  prevD2 = D2;
              }
  
              FDBigInteger diff;
              int cmpResult;
              boolean overvalue;
              if ((cmpResult = bigB.cmp(bigD)) > 0) {
                  overvalue = true; // our candidate is too big.
                  diff = bigB.leftInplaceSub(bigD); // bigB is not user further - reuse
                  if ((bigIntNBits == 1) && (bigIntExp > -FLOAT_EXP_BIAS + 1)) {
                      Ulp2 -= 1;
                      if (Ulp2 < 0) {
                          Ulp2 = 0;
                          diff = diff.leftShift(1);
                      }
                  }
              } else if (cmpResult < 0) {
                  overvalue = false; // our candidate is too small.
                  diff = bigD.rightInplaceSub(bigB); // bigB is not user further - reuse
              } else {
                  break;
              }
              cmpResult = diff.cmpPow52(B5, Ulp2);
              if ((cmpResult) < 0) {
                  break;
              } else if (cmpResult == 0) {
                  if ((ieeeBits & 1) != 0) { // half ties to even
                      ieeeBits += overvalue ? -1 : 1; // nextDown or nextUp
                  }
                  break;
              } else {
                  ieeeBits += overvalue ? -1 : 1; // nextDown or nextUp
                  final int FLOAT_EXP_BIT_MASK = 0x7F800000;
                  if (ieeeBits == 0 || ieeeBits == FLOAT_EXP_BIT_MASK) { // 0.0 or Float.POSITIVE_INFINITY
                      break; // oops. Fell off end of range.
                  }
              }
          }
          if (isNegative) {
              final int FLOAT_SIGN_BIT_MASK = 0x80000000;
              ieeeBits |= FLOAT_SIGN_BIT_MASK;
          }
          return Float.intBitsToFloat(ieeeBits);
      }
  
      static class Cache {
          volatile char[] chars;
      }
  
      static final Cache CACHE = new Cache();
      static final AtomicReferenceFieldUpdater<Cache, char[]> CHARS_UPDATER
              = AtomicReferenceFieldUpdater.newUpdater(Cache.class, char[].class, "chars");
  
      public static Class<?> getMapping(Type type) {
          if (type == null) {
              return null;
          }
  
          if (type.getClass() == Class.class) {
              return (Class<?>) type;
          }
  
          if (type instanceof ParameterizedType) {
              return getMapping(((ParameterizedType) type).getRawType());
          }
  
          if (type instanceof TypeVariable) {
              Type boundType = ((TypeVariable<?>) type).getBounds()[0];
              if (boundType instanceof Class) {
                  return (Class) boundType;
              }
              return getMapping(boundType);
          }
  
          if (type instanceof WildcardType) {
              Type[] upperBounds = ((WildcardType) type).getUpperBounds();
              if (upperBounds.length == 1) {
                  return getMapping(upperBounds[0]);
              }
          }
  
          if (type instanceof GenericArrayType) {
              Type genericComponentType = ((GenericArrayType) type).getGenericComponentType();
              Class<?> componentClass = getClass(genericComponentType);
              return getArrayClass(componentClass);
          }
  
          return Object.class;
      }
  
      public static Date toDate(Object obj) {
          if (obj == null) {
              return null;
          }
  
          if (obj instanceof Date) {
              return (Date) obj;
          }
  
          if (obj instanceof Instant) {
              Instant instant = (Instant) obj;
              return new Date(
                      instant.toEpochMilli());
          }
  
          if (obj instanceof ZonedDateTime) {
              ZonedDateTime zdt = (ZonedDateTime) obj;
              return new Date(
                      zdt.toInstant().toEpochMilli());
          }
  
          if (obj instanceof LocalDate) {
              LocalDate localDate = (LocalDate) obj;
              ZonedDateTime zdt = localDate.atStartOfDay(ZoneId.systemDefault());
              return new Date(
                      zdt.toInstant().toEpochMilli());
          }
  
          if (obj instanceof LocalDateTime) {
              LocalDateTime ldt = (LocalDateTime) obj;
              ZonedDateTime zdt = ldt.atZone(ZoneId.systemDefault());
              return new Date(
                      zdt.toInstant().toEpochMilli());
          }
  
          if (obj instanceof String) {
              return DateUtils.parseDate((String) obj);
          }
  
          if (obj instanceof Long || obj instanceof Integer) {
              return new Date(((Number) obj).longValue());
          }
  
          if (obj instanceof Map) {
              Object date = ((Map) obj).get("$date");
              if (date instanceof String) {
                  return DateUtils.parseDate((String) date);
              }
          }
  
          throw new JSONException("can not cast to Date from " + obj.getClass());
      }
  
      public static Instant toInstant(Object obj) {
          if (obj == null) {
              return null;
          }
  
          if (obj instanceof Instant) {
              return (Instant) obj;
          }
  
          if (obj instanceof Date) {
              return ((Date) obj).toInstant();
          }
  
          if (obj instanceof ZonedDateTime) {
              ZonedDateTime zdt = (ZonedDateTime) obj;
              return zdt.toInstant();
          }
  
          if (obj instanceof String) {
              String str = (String) obj;
              if (str.isEmpty() || "null".equals(str)) {
                  return null;
              }
  
              JSONReader jsonReader;
              if (str.charAt(0) != '"') {
                  jsonReader = JSONReader.of('"' + str + '"');
              } else {
                  jsonReader = JSONReader.of(str);
              }
              return jsonReader.read(Instant.class);
          }
  
          if (obj instanceof Map) {
              return (Instant) ObjectReaderImplInstant.INSTANCE.createInstance((Map) obj, 0L);
          }
  
          throw new JSONException("can not cast to Date from " + obj.getClass());
      }
  
      public static Object[] cast(Object obj, Type[] types) {
          if (obj == null) {
              return null;
          }
  
          Object[] array = new Object[types.length];
  
          if (obj instanceof Collection) {
              int i = 0;
              for (Object item : (Collection) obj) {
                  int index = i++;
                  array[index] = TypeUtils.cast(item, types[index]);
              }
          } else {
              Class<?> objectClass = obj.getClass();
              if (objectClass.isArray()) {
                  int length = Array.getLength(obj);
                  for (int i = 0; i < array.length && i < length; i++) {
                      Object item = Array.get(obj, i);
                      array[i] = TypeUtils.cast(item, types[i]);
                  }
              } else {
                  throw new JSONException("can not cast to types " + JSON.toJSONString(types) + " from " + objectClass);
              }
          }
  
          return array;
      }
  
      public static String[] toStringArray(Object object) {
          if (object == null || object instanceof String[]) {
              return (String[]) object;
          }
  
          if (object instanceof Collection) {
              Collection collection = (Collection) object;
              String[] array = new String[collection.size()];
              int i = 0;
              for (Object item : (Collection) object) {
                  int index = i++;
                  array[index] = item == null || (item instanceof String) ? (String) item : item.toString();
              }
              return array;
          }
  
          Class<?> objectClass = object.getClass();
          if (objectClass.isArray()) {
              int length = Array.getLength(object);
              String[] array = new String[length];
              for (int i = 0; i < array.length; i++) {
                  Object item = Array.get(object, i);
                  array[i] = item == null || (item instanceof String) ? (String) item : item.toString();
              }
              return array;
          }
  
          return cast(object, String[].class);
      }
  
      public static <T> T cast(Object obj, Type type) {
          return cast(obj, type, JSONFactory.getDefaultObjectReaderProvider());
      }
  
      @SuppressWarnings({ "rawtypes", "unchecked" })
      public static <T> T cast(Object obj, Type type, ObjectReaderProvider provider) {
          if (type instanceof Class) {
              return cast(obj, (Class<T>) type, provider);
          }
  
          if (obj instanceof Collection) {
              return (T) provider.getObjectReader(type)
                      .createInstance((Collection) obj);
          }
  
          if (obj instanceof Map) {
              return (T) provider.getObjectReader(type)
                      .createInstance((Map) obj, 0L);
          }
  
          return JSON.parseObject(
                  JSON.toJSONString(obj),
                  type
          );
      }
  
      public static <T> T cast(Object obj, Class<T> targetClass) {
          return cast(obj, targetClass, JSONFactory.getDefaultObjectReaderProvider());
      }
  
      @SuppressWarnings({ "rawtypes", "unchecked" })
      public static <T> T cast(Object obj, Class<T> targetClass, ObjectReaderProvider provider) {
          if (obj == null) {
              return null;
          }
  
          if (targetClass.isInstance(obj)) {
              return (T) obj;
          }
  
          if (targetClass == Date.class) {
              return (T) toDate(obj);
          }
  
          if (targetClass == Instant.class) {
              return (T) toInstant(obj);
          }
  
          if (targetClass == LocalDate.class) {
              if (obj instanceof Date) {
                  Date date = (Date) obj;
                  return (T) date.toInstant().atZone(DateUtils.DEFAULT_ZONE_ID).toLocalDate();
              }
          }
  
          if (targetClass == LocalDateTime.class) {
              if (obj instanceof Date) {
                  Date date = (Date) obj;
                  return (T) date.toInstant().atZone(DateUtils.DEFAULT_ZONE_ID).toLocalDateTime();
              }
          }
  
          if (targetClass == String.class) {
              if (obj instanceof Character) {
                  return (T) obj.toString();
              }
  
              return (T) JSON.toJSONString(obj);
          }
  
          if (targetClass == AtomicInteger.class) {
              return (T) new AtomicInteger(toIntValue(obj));
          }
  
          if (targetClass == AtomicLong.class) {
              return (T) new AtomicLong(toLongValue(obj));
          }
  
          if (targetClass == AtomicBoolean.class) {
              return (T) new AtomicBoolean((Boolean) obj);
          }
  
          if (obj instanceof Map) {
              ObjectReader objectReader = provider.getObjectReader(targetClass);
              return (T) objectReader.createInstance((Map) obj, 0L);
          }
  
          Function typeConvert = provider.getTypeConvert(obj.getClass(), targetClass);
          if (typeConvert != null) {
              return (T) typeConvert.apply(obj);
          }
  
          if (targetClass.isEnum()) {
              ObjectReader objectReader = JSONFactory.getDefaultObjectReaderProvider().getObjectReader(targetClass);
              if (objectReader instanceof ObjectReaderImplEnum) {
                  if (obj instanceof Integer) {
                      int intValue = (Integer) obj;
                      return (T) ((ObjectReaderImplEnum) objectReader).of(intValue);
                  }
              } else {
                  JSONReader jsonReader = JSONReader.of(JSON.toJSONString(obj));
                  return (T) objectReader.readObject(jsonReader, targetClass, null, 0);
              }
          }
  
          if (obj instanceof String) {
              String json = (String) obj;
              if (json.isEmpty() || "null".equals(json)) {
                  return null;
              }
  
              JSONReader jsonReader;
              char first = json.trim().charAt(0);
              if (first == '"' || first == '{' || first == '[') {
                  jsonReader = JSONReader.of(json);
              } else {
                  jsonReader = JSONReader.of(
                          JSON.toJSONString(json));
              }
  
              ObjectReader objectReader = JSONFactory
                      .getDefaultObjectReaderProvider()
                      .getObjectReader(targetClass);
              return (T) objectReader.readObject(jsonReader, targetClass, null, 0);
          }
  
          if (obj instanceof Collection) {
              return (T) provider.getObjectReader(targetClass)
                      .createInstance((Collection) obj);
          }
  
          String className = targetClass.getName();
          if (obj instanceof Integer || obj instanceof Long) {
              long millis = ((Number) obj).longValue();
              switch (className) {
                  case "java.sql.Date":
                      return (T) JdbcSupport.createDate(millis);
                  case "java.sql.Timestamp":
                      return (T) JdbcSupport.createTimestamp(millis);
                  case "java.sql.Time":
                      return (T) JdbcSupport.createTime(millis);
                  case "java.time.LocalDateTime":
                      return (T) LocalDateTime.ofInstant(
                              Instant.ofEpochMilli(millis),
                              DateUtils.DEFAULT_ZONE_ID);
                  default:
                      break;
              }
          }
          // fix org.bson.types.Decimal128 to Double
          String objClassName = obj.getClass().getName();
          if (objClassName.equals("org.bson.types.Decimal128") && targetClass == Double.class) {
              ObjectWriter objectWriter = JSONFactory
                      .getDefaultObjectWriterProvider()
                      .getObjectWriter(obj.getClass());
              if (objectWriter instanceof ObjectWriterPrimitiveImpl) {
                  Function function = ((ObjectWriterPrimitiveImpl<?>) objectWriter).getFunction();
                  if (function != null) {
                      Object apply = function.apply(obj);
                      Function DecimalTypeConvert = provider.getTypeConvert(apply.getClass(), targetClass);
                      if (DecimalTypeConvert != null) {
                          return (T) DecimalTypeConvert.apply(obj);
                      }
                  }
              }
          }
  
          ObjectWriter objectWriter = JSONFactory
                  .getDefaultObjectWriterProvider()
                  .getObjectWriter(obj.getClass());
          if (objectWriter instanceof ObjectWriterPrimitiveImpl) {
              Function function = ((ObjectWriterPrimitiveImpl<?>) objectWriter).getFunction();
              if (function != null) {
                  Object apply = function.apply(obj);
                  if (targetClass.isInstance(apply)) {
                      return (T) apply;
                  }
              }
          }
  
          throw new JSONException("can not cast to " + className + ", from " + obj.getClass());
      }
  
      static final Map<Class, String> NAME_MAPPINGS = new IdentityHashMap<>();
      static final Map<String, Class> TYPE_MAPPINGS = new ConcurrentHashMap<>();
  
      static {
          CLASS_JSON_OBJECT_1x = loadClass("com.alibaba.fastjson.JSONObject");
          {
              Field field = null;
              if (CLASS_JSON_OBJECT_1x != null) {
                  try {
                      field = CLASS_JSON_OBJECT_1x.getDeclaredField("map");
                      field.setAccessible(true);
                  } catch (Throwable ignore) {
                      // ignore
                  }
              }
              FIELD_JSON_OBJECT_1x_map = field;
          }
  
          CLASS_JSON_ARRAY_1x = loadClass("com.alibaba.fastjson.JSONArray");
  
          NAME_MAPPINGS.put(byte.class, "B");
          NAME_MAPPINGS.put(short.class, "S");
          NAME_MAPPINGS.put(int.class, "I");
          NAME_MAPPINGS.put(long.class, "J");
          NAME_MAPPINGS.put(float.class, "F");
          NAME_MAPPINGS.put(double.class, "D");
          NAME_MAPPINGS.put(char.class, "C");
          NAME_MAPPINGS.put(boolean.class, "Z");
  
          NAME_MAPPINGS.put(Object[].class, "[O");
          NAME_MAPPINGS.put(Object[][].class, "[[O");
          NAME_MAPPINGS.put(byte[].class, "[B");
          NAME_MAPPINGS.put(byte[][].class, "[[B");
          NAME_MAPPINGS.put(short[].class, "[S");
          NAME_MAPPINGS.put(short[][].class, "[[S");
          NAME_MAPPINGS.put(int[].class, "[I");
          NAME_MAPPINGS.put(int[][].class, "[[I");
          NAME_MAPPINGS.put(long[].class, "[J");
          NAME_MAPPINGS.put(long[][].class, "[[J");
          NAME_MAPPINGS.put(float[].class, "[F");
          NAME_MAPPINGS.put(float[][].class, "[[F");
          NAME_MAPPINGS.put(double[].class, "[D");
          NAME_MAPPINGS.put(double[][].class, "[[D");
          NAME_MAPPINGS.put(char[].class, "[C");
          NAME_MAPPINGS.put(char[][].class, "[[C");
          NAME_MAPPINGS.put(boolean[].class, "[Z");
          NAME_MAPPINGS.put(boolean[][].class, "[[Z");
  
          NAME_MAPPINGS.put(Byte[].class, "[Byte");
          NAME_MAPPINGS.put(Byte[][].class, "[[Byte");
          NAME_MAPPINGS.put(Short[].class, "[Short");
          NAME_MAPPINGS.put(Short[][].class, "[[Short");
          NAME_MAPPINGS.put(Integer[].class, "[Integer");
          NAME_MAPPINGS.put(Integer[][].class, "[[Integer");
          NAME_MAPPINGS.put(Long[].class, "[Long");
          NAME_MAPPINGS.put(Long[][].class, "[[Long");
          NAME_MAPPINGS.put(Float[].class, "[Float");
          NAME_MAPPINGS.put(Float[][].class, "[[Float");
          NAME_MAPPINGS.put(Double[].class, "[Double");
          NAME_MAPPINGS.put(Double[][].class, "[[Double");
          NAME_MAPPINGS.put(Character[].class, "[Character");
          NAME_MAPPINGS.put(Character[][].class, "[[Character");
          NAME_MAPPINGS.put(Boolean[].class, "[Boolean");
          NAME_MAPPINGS.put(Boolean[][].class, "[[Boolean");
  
          NAME_MAPPINGS.put(String[].class, "[String");
          NAME_MAPPINGS.put(String[][].class, "[[String");
  
          NAME_MAPPINGS.put(BigDecimal[].class, "[BigDecimal");
          NAME_MAPPINGS.put(BigDecimal[][].class, "[[BigDecimal");
  
          NAME_MAPPINGS.put(BigInteger[].class, "[BigInteger");
          NAME_MAPPINGS.put(BigInteger[][].class, "[[BigInteger");
  
          NAME_MAPPINGS.put(UUID[].class, "[UUID");
          NAME_MAPPINGS.put(UUID[][].class, "[[UUID");
  
          NAME_MAPPINGS.put(Object.class, "Object");
  
          NAME_MAPPINGS.put(HashMap.class, "M");
          TYPE_MAPPINGS.put("HashMap", HashMap.class);
          TYPE_MAPPINGS.put("java.util.HashMap", HashMap.class);
  
          NAME_MAPPINGS.put(LinkedHashMap.class, "LM");
          TYPE_MAPPINGS.put("LinkedHashMap", LinkedHashMap.class);
          TYPE_MAPPINGS.put("java.util.LinkedHashMap", LinkedHashMap.class);
  
          NAME_MAPPINGS.put(TreeMap.class, "TM");
          TYPE_MAPPINGS.put("TreeMap", TreeMap.class);
  
          NAME_MAPPINGS.put(ArrayList.class, "A");
          TYPE_MAPPINGS.put("ArrayList", ArrayList.class);
          TYPE_MAPPINGS.put("java.util.ArrayList", ArrayList.class);
  
          NAME_MAPPINGS.put(LinkedList.class, "LA");
          TYPE_MAPPINGS.put("LA", LinkedList.class);
          TYPE_MAPPINGS.put("LinkedList", LinkedList.class);
          TYPE_MAPPINGS.put("java.util.LinkedList", LinkedList.class);
          TYPE_MAPPINGS.put("java.util.concurrent.ConcurrentLinkedQueue", ConcurrentLinkedQueue.class);
          TYPE_MAPPINGS.put("java.util.concurrent.ConcurrentLinkedDeque", ConcurrentLinkedDeque.class);
  
          //java.util.LinkedHashMap.class,
  
          NAME_MAPPINGS.put(HashSet.class, "HashSet");
          NAME_MAPPINGS.put(TreeSet.class, "TreeSet");
          NAME_MAPPINGS.put(LinkedHashSet.class, "LinkedHashSet");
          NAME_MAPPINGS.put(ConcurrentHashMap.class, "ConcurrentHashMap");
          NAME_MAPPINGS.put(ConcurrentLinkedQueue.class, "ConcurrentLinkedQueue");
          NAME_MAPPINGS.put(ConcurrentLinkedDeque.class, "ConcurrentLinkedDeque");
          NAME_MAPPINGS.put(JSONObject.class, "JSONObject");
          NAME_MAPPINGS.put(JSONArray.class, "JSONArray");
          NAME_MAPPINGS.put(Currency.class, "Currency");
          NAME_MAPPINGS.put(TimeUnit.class, "TimeUnit");
  
          Class<?>[] classes = new Class[]{
                  Object.class,
                  Cloneable.class,
                  AutoCloseable.class,
                  java.lang.Exception.class,
                  java.lang.RuntimeException.class,
                  java.lang.IllegalAccessError.class,
                  java.lang.IllegalAccessException.class,
                  java.lang.IllegalArgumentException.class,
                  java.lang.IllegalMonitorStateException.class,
                  java.lang.IllegalStateException.class,
                  java.lang.IllegalThreadStateException.class,
                  java.lang.IndexOutOfBoundsException.class,
                  java.lang.InstantiationError.class,
                  java.lang.InstantiationException.class,
                  java.lang.InternalError.class,
                  java.lang.InterruptedException.class,
                  java.lang.LinkageError.class,
                  java.lang.NegativeArraySizeException.class,
                  java.lang.NoClassDefFoundError.class,
                  java.lang.NoSuchFieldError.class,
                  java.lang.NoSuchFieldException.class,
                  java.lang.NoSuchMethodError.class,
                  java.lang.NoSuchMethodException.class,
                  java.lang.NullPointerException.class,
                  java.lang.NumberFormatException.class,
                  java.lang.OutOfMemoryError.class,
                  java.lang.SecurityException.class,
                  java.lang.StackOverflowError.class,
                  java.lang.StringIndexOutOfBoundsException.class,
                  java.lang.TypeNotPresentException.class,
                  java.lang.VerifyError.class,
                  java.lang.StackTraceElement.class,
                  java.util.Hashtable.class,
                  java.util.TreeMap.class,
                  java.util.IdentityHashMap.class,
                  java.util.WeakHashMap.class,
                  java.util.HashSet.class,
                  java.util.LinkedHashSet.class,
                  java.util.TreeSet.class,
                  java.util.LinkedList.class,
                  java.util.concurrent.TimeUnit.class,
                  java.util.concurrent.ConcurrentHashMap.class,
                  java.util.concurrent.atomic.AtomicInteger.class,
                  java.util.concurrent.atomic.AtomicLong.class,
                  java.util.Collections.EMPTY_MAP.getClass(),
                  java.lang.Boolean.class,
                  java.lang.Character.class,
                  java.lang.Byte.class,
                  java.lang.Short.class,
                  java.lang.Integer.class,
                  java.lang.Long.class,
                  java.lang.Float.class,
                  java.lang.Double.class,
                  java.lang.Number.class,
                  java.lang.String.class,
                  java.math.BigDecimal.class,
                  java.math.BigInteger.class,
                  java.util.BitSet.class,
                  java.util.Calendar.class,
                  java.util.Date.class,
                  java.util.Locale.class,
                  java.util.UUID.class,
                  java.util.Currency.class,
                  java.text.SimpleDateFormat.class,
                  JSONObject.class,
                  JSONArray.class,
                  java.util.concurrent.ConcurrentSkipListMap.class,
                  java.util.concurrent.ConcurrentSkipListSet.class,
          };
          for (Class clazz : classes) {
              TYPE_MAPPINGS.put(clazz.getSimpleName(), clazz);
              TYPE_MAPPINGS.put(clazz.getName(), clazz);
              NAME_MAPPINGS.put(clazz, clazz.getSimpleName());
          }
  
          TYPE_MAPPINGS.put("JO10", JSONObject1O.class);
          TYPE_MAPPINGS.put("[O", Object[].class);
          TYPE_MAPPINGS.put("[Ljava.lang.Object;", Object[].class);
          TYPE_MAPPINGS.put("[java.lang.Object", Object[].class);
          TYPE_MAPPINGS.put("[Object", Object[].class);
          TYPE_MAPPINGS.put("StackTraceElement", StackTraceElement.class);
          TYPE_MAPPINGS.put("[StackTraceElement", StackTraceElement[].class);
  
          String[] items = {
                  "java.util.Collections$UnmodifiableMap",
                  "java.util.Collections$UnmodifiableCollection",
          };
  
          for (String className : items) {
              Class<?> clazz = loadClass(className);
              TYPE_MAPPINGS.put(clazz.getName(), clazz);
          }
  
          {
              if (CLASS_JSON_OBJECT_1x != null) {
                  TYPE_MAPPINGS.putIfAbsent("JO1", CLASS_JSON_OBJECT_1x);
                  TYPE_MAPPINGS.putIfAbsent(CLASS_JSON_OBJECT_1x.getName(), CLASS_JSON_OBJECT_1x);
              }
              if (CLASS_JSON_ARRAY_1x != null) {
                  TYPE_MAPPINGS.putIfAbsent("JA1", CLASS_JSON_ARRAY_1x);
                  TYPE_MAPPINGS.putIfAbsent(CLASS_JSON_ARRAY_1x.getName(), CLASS_JSON_ARRAY_1x);
              }
          }
  
          NAME_MAPPINGS.put(new HashMap().keySet().getClass(), "Set");
          NAME_MAPPINGS.put(new LinkedHashMap().keySet().getClass(), "Set");
          NAME_MAPPINGS.put(new TreeMap<>().keySet().getClass(), "Set");
          NAME_MAPPINGS.put(((Map) new ConcurrentHashMap()).keySet().getClass(), "Set"); // bug fix for android9
          NAME_MAPPINGS.put(((Map) new ConcurrentSkipListMap()).keySet().getClass(), "Set"); // bug fix for android9
          TYPE_MAPPINGS.put("Set", HashSet.class);
  
          NAME_MAPPINGS.put(new HashMap().values().getClass(), "List");
          NAME_MAPPINGS.put(new LinkedHashMap().values().getClass(), "List");
          NAME_MAPPINGS.put(new TreeMap().values().getClass(), "List");
          NAME_MAPPINGS.put(new ConcurrentHashMap().values().getClass(), "List");
          NAME_MAPPINGS.put(new ConcurrentSkipListMap().values().getClass(), "List");
  
          TYPE_MAPPINGS.put("List", ArrayList.class);
          TYPE_MAPPINGS.put("java.util.ImmutableCollections$Map1", HashMap.class);
          TYPE_MAPPINGS.put("java.util.ImmutableCollections$MapN", LinkedHashMap.class);
          TYPE_MAPPINGS.put("java.util.ImmutableCollections$Set12", LinkedHashSet.class);
          TYPE_MAPPINGS.put("java.util.ImmutableCollections$SetN", LinkedHashSet.class);
          TYPE_MAPPINGS.put("java.util.ImmutableCollections$List12", ArrayList.class);
          TYPE_MAPPINGS.put("java.util.ImmutableCollections$ListN", ArrayList.class);
          TYPE_MAPPINGS.put("java.util.ImmutableCollections$SubList", ArrayList.class);
  
          for (Map.Entry<Class, String> entry : NAME_MAPPINGS.entrySet()) {
              TYPE_MAPPINGS.putIfAbsent(entry.getValue(), entry.getKey());
          }
      }
  
      public static String getTypeName(Class type) {
          String mapTypeName = NAME_MAPPINGS.get(type);
          if (mapTypeName != null) {
              return mapTypeName;
          }
  
          if (Proxy.isProxyClass(type)) {
              Class[] interfaces = type.getInterfaces();
              if (interfaces.length > 0) {
                  type = interfaces[0];
              }
          }
  
          String typeName = type.getTypeName();
          switch (typeName) {
              case "com.alibaba.fastjson.JSONObject":
                  NAME_MAPPINGS.putIfAbsent(type, "JO1");
                  return NAME_MAPPINGS.get(type);
              case "com.alibaba.fastjson.JSONArray":
                  NAME_MAPPINGS.putIfAbsent(type, "JA1");
                  return NAME_MAPPINGS.get(type);
  //            case "org.apache.commons.lang3.tuple.ImmutablePair":
  //                NAME_MAPPINGS.putIfAbsent(type, "org.apache.commons.lang3.tuple.Pair");
  //                return NAME_MAPPINGS.get(type);
              default:
                  break;
          }
  
          int index = typeName.indexOf('$');
          if (index != -1 && TypeUtils.isInteger(typeName.substring(index + 1))) {
              Class superclass = type.getSuperclass();
              if (Map.class.isAssignableFrom(superclass)) {
                  return getTypeName(superclass);
              }
          }
  
          return typeName;
      }
  
      public static Class getMapping(String typeName) {
          return TYPE_MAPPINGS.get(typeName);
      }
  
      public static BigDecimal toBigDecimal(Object value) {
          if (value == null || value instanceof BigDecimal) {
              return (BigDecimal) value;
          }
  
          if (value instanceof Byte || value instanceof Short || value instanceof Integer || value instanceof Long) {
              return BigDecimal.valueOf(((Number) value).longValue());
          }
  
          if (value instanceof String) {
              String str = (String) value;
              if (str.isEmpty() || "null".equals(str)) {
                  return null;
              }
              return new BigDecimal(str);
          }
  
          return cast(value, BigDecimal.class);
      }
  
      public static BigDecimal toBigDecimal(long i) {
          return BigDecimal.valueOf(i);
      }
  
      public static BigDecimal toBigDecimal(float f) {
          byte[] bytes = new byte[15];
          int size = NumberUtils.writeFloat(bytes, 0, f, true);
          return parseBigDecimal(bytes, 0, size);
      }
  
      public static BigDecimal toBigDecimal(double d) {
          byte[] bytes = new byte[24];
          int size = NumberUtils.writeDouble(bytes, 0, d, true);
          return parseBigDecimal(bytes, 0, size);
      }
  
      public static BigDecimal toBigDecimal(String str) {
          if (str == null || str.isEmpty() || "null".equals(str)) {
              return null;
          }
  
          if (JDKUtils.STRING_CODER != null) {
              int code = JDKUtils.STRING_CODER.applyAsInt(str);
              if (code == JDKUtils.LATIN1 && JDKUtils.STRING_VALUE != null) {
                  byte[] bytes = JDKUtils.STRING_VALUE.apply(str);
                  return parseBigDecimal(bytes, 0, bytes.length);
              }
          }
  
          char[] chars = JDKUtils.getCharArray(str);
          return parseBigDecimal(chars, 0, chars.length);
      }
  
      public static BigDecimal toBigDecimal(char[] chars) {
          if (chars == null) {
              return null;
          }
          return parseBigDecimal(chars, 0, chars.length);
      }
  
      public static BigDecimal toBigDecimal(byte[] strBytes) {
          if (strBytes == null) {
              return null;
          }
          return parseBigDecimal(strBytes, 0, strBytes.length);
      }
  
      public static boolean isInt32(BigInteger value) {
          if (FIELD_BIGINTEGER_MAG_OFFSET != -1) {
              int[] mag = (int[]) UNSAFE.getObject(value, FIELD_BIGINTEGER_MAG_OFFSET);
              return mag.length == 0
                      || (mag.length == 1 && (mag[0] >= 0 || (mag[0] == Integer.MIN_VALUE && value.signum() == -1)));
          }
  
          return value.compareTo(BIGINT_INT32_MIN) >= 0 && value.compareTo(BIGINT_INT32_MAX) <= 0;
      }
  
      public static boolean isInt64(BigInteger value) {
          if (FIELD_BIGINTEGER_MAG_OFFSET != -1) {
              int[] mag = (int[]) UNSAFE.getObject(value, FIELD_BIGINTEGER_MAG_OFFSET);
              if (mag.length <= 1) {
                  return true;
              }
  
              if (mag.length == 2) {
                  int mag0 = mag[0];
                  return mag[0] >= 0 || (mag0 == Integer.MIN_VALUE && mag[1] == 0 && value.signum() == -1);
              }
          }
          return value.compareTo(BIGINT_INT64_MIN) >= 0 && value.compareTo(BIGINT_INT64_MAX) <= 0;
      }
  
      /**
       * decimal is integer, check has non-zero small
       *
       * @param decimal the BigDecimal value to check
       * @return true if the decimal is an integer, false otherwise
       */
      public static boolean isInteger(BigDecimal decimal) {
          int scale = decimal.scale();
          if (scale == 0) {
              return true;
          }
  
          int precision = decimal.precision();
          if (precision < 20) {
              if (FIELD_DECIMAL_INT_COMPACT_OFFSET != -1) {
                  long intCompact = UNSAFE.getLong(decimal, FIELD_DECIMAL_INT_COMPACT_OFFSET);
                  switch (scale) {
                      case 1:
                          return intCompact % 10 == 0;
                      case 2:
                          return intCompact % 100 == 0;
                      case 3:
                          return intCompact % 1000 == 0;
                      case 4:
                          return intCompact % 10000 == 0;
                      case 5:
                          return intCompact % 100000 == 0;
                      case 6:
                          return intCompact % 1000000 == 0;
                      case 7:
                          return intCompact % 10000000 == 0;
                      case 8:
                          return intCompact % 100000000 == 0;
                      case 9:
                          return intCompact % 1000000000 == 0;
                      default:
                          break;
                  }
              }
          }
  
          return decimal.stripTrailingZeros().scale() == 0;
      }
  
      public static BigInteger toBigInteger(Object value) {
          if (value == null || value instanceof BigInteger) {
              return (BigInteger) value;
          }
  
          if (value instanceof Byte || value instanceof Short || value instanceof Integer || value instanceof Long) {
              return BigInteger.valueOf(((Number) value).longValue());
          }
  
          if (value instanceof String) {
              String str = (String) value;
              if (str.isEmpty() || "null".equals(str)) {
                  return null;
              }
              return new BigInteger(str);
          }
  
          throw new JSONException("can not cast to bigint");
      }
  
      public static Long toLong(Object value) {
          if (value == null || value instanceof Long) {
              return (Long) value;
          }
  
          if (value instanceof String) {
              String str = (String) value;
              if (str.isEmpty() || "null".equals(str)) {
                  return null;
              }
          }
  
          return toLongValue(value);
      }
  
      public static long toLongValue(Object value) {
          if (value == null) {
              return 0L;
          }
  
          if (value instanceof Long) {
              return (Long) value;
          }
  
          if (value instanceof Number) {
              return ((Number) value).longValue();
          }
  
          if (value instanceof String) {
              String str = (String) value;
              if (str.isEmpty() || "null".equals(str)) {
                  return 0;
              }
  
              try {
                  int lastCommaIndex = str.lastIndexOf(',');
                  if (lastCommaIndex == str.length() - 4 && str.indexOf('.') == -1) {
                      return NumberFormat
                              .getNumberInstance()
                              .parse(str)
                              .longValue();
                  }
              } catch (ParseException ignored) {
                  // ignored
              }
  
              if (IOUtils.isNumber(str)) {
                  return Long.parseLong(str);
              }
  
              throw new JSONException("parseLong error " + str);
          }
  
          throw new JSONException("can not cast to long from " + value.getClass());
      }
  
      public static Boolean parseBoolean(byte[] bytes, int off, int len) {
          if (len == 0) {
              return null;
          }
          byte b0;
          return (len == 1 && ((b0 = bytes[off]) == '1' || b0 == 'Y'))
                  || (len == 4 && (IOUtils.getIntUnaligned(bytes, off) | 0x20202020) == IOUtils.TRUE);
      }
  
      public static Boolean parseBoolean(char[] chars, int off, int len) {
          if (len == 0) {
              return null;
          }
          char b0;
          return (len == 1 && ((b0 = chars[off]) == '1' || b0 == 'Y'))
                  || (len == 4 && (IOUtils.getLongLE(chars, off) | 0x20002000200020L) == 0x65007500720074L);
      }
  
      public static int parseInt(byte[] bytes, int off, int len) {
          /* Accumulating negatively avoids surprises near MAX_VALUE */
          int max = off + len;
          int fc = bytes[off++];
          int result = IOUtils.isDigit(fc)
                  ? '0' - fc
                  : len != 1 && (fc == '-' || fc == '+')
                  ? 0
                  : 1;  // or any value > 0
          int d;
          while (off + 1 < max
                  && (d = IOUtils.digit2(bytes, off)) != -1
                  && Integer.MIN_VALUE / 100 <= result & result <= 0) {
              result = result * 100 - d;  // overflow from d => result > 0
              off += 2;
          }
          if (off < max
                  && IOUtils.isDigit(d = bytes[off])
                  && Integer.MIN_VALUE / 10 <= result & result <= 0) {
              result = result * 10 + '0' - d;  // overflow from '0' - d => result > 0
              off += 1;
          }
          if (off == max
                  & result <= 0
                  & (Integer.MIN_VALUE < result || fc == '-')) {
              return fc == '-' ? result : -result;
          }
          throw new NumberFormatException("parseInt error " + new String(bytes, off, len));
      }
  
      public static int parseInt(char[] chars, int off, int len) {
          int max = off + len;
          int fc = chars[off++];
          int result = IOUtils.isDigit(fc)
                  ? '0' - fc
                  : len != 1 && (fc == '-' || fc == '+')
                  ? 0
                  : 1;  // or any value > 0
          int d;
          while (off + 1 < max
                  && (d = IOUtils.digit2(chars, off)) != -1
                  && Integer.MIN_VALUE / 100 <= result & result <= 0) {
              result = result * 100 - d;  // overflow from d => result > 0
              off += 2;
          }
          if (off < max
                  && IOUtils.isDigit(d = chars[off])
                  && Integer.MIN_VALUE / 10 <= result & result <= 0) {
              result = result * 10 + '0' - d;  // overflow from '0' - d => result > 0
              off += 1;
          }
          if (off == max
                  & result <= 0
                  & (Integer.MIN_VALUE < result || fc == '-')) {
              return fc == '-' ? result : -result;
          }
          throw new NumberFormatException("parseInt error " + new String(chars, off, len));
      }
  
      public static long parseLong(byte[] bytes, int off, int len) {
          int max = off + len;
          int fc = bytes[off++];
          long result = IOUtils.isDigit(fc)
                  ? '0' - fc
                  : len != 1 && (fc == '-' || fc == '+')
                  ? 0
                  : 1;  // or any value > 0
          int d;
          while (off + 1 < max
                  && (d = IOUtils.digit2(bytes, off)) != -1
                  && Long.MIN_VALUE / 100 <= result & result <= 0) {
              result = result * 100 - d;  // overflow from d => result > 0
              off += 2;
          }
          if (off < max
                  && IOUtils.isDigit(d = bytes[off])
                  && Long.MIN_VALUE / 10 <= result & result <= 0) {
              result = result * 10 + '0' - d;  // overflow from '0' - d => result > 0
              off += 1;
          }
          if (off == max
                  & result <= 0
                  & (Long.MIN_VALUE < result || fc == '-')) {
              return fc == '-' ? result : -result;
          }
          throw new NumberFormatException("parseInt error " + new String(bytes, off, len));
      }
  
      public static long parseLong(char[] chars, int off, int len) {
          int max = off + len;
          int fc = chars[off++];
          long result = IOUtils.isDigit(fc)
                  ? '0' - fc
                  : len != 1 && (fc == '-' || fc == '+')
                  ? 0
                  : 1;  // or any value > 0
          int d;
          while (off + 1 < max
                  && (d = IOUtils.digit2(chars, off)) != -1
                  && Long.MIN_VALUE / 100 <= result & result <= 0) {
              result = result * 100 - d;  // overflow from d => result > 0
              off += 2;
          }
          if (off < max
                  && IOUtils.isDigit(d = chars[off])
                  && Long.MIN_VALUE / 10 <= result & result <= 0) {
              result = result * 10 + '0' - d;  // overflow from '0' - d => result > 0
              off += 1;
          }
          if (off == max
                  & result <= 0
                  & (Long.MIN_VALUE < result || fc == '-')) {
              return fc == '-' ? result : -result;
          }
          throw new NumberFormatException("parseInt error " + new String(chars, off, len));
      }
  
      public static BigDecimal parseBigDecimal(char[] bytes, int off, int len) {
          if (bytes == null || len == 0) {
              return null;
          }
  
          boolean negative = false;
          int j = off;
          if (bytes[off] == '-') {
              negative = true;
              j++;
          }
  
          if (len <= 20 || (negative && len == 21)) {
              int end = off + len;
              int dot = 0;
              int dotIndex = -1;
              long unscaleValue = 0;
              for (; j < end; j++) {
                  char b = bytes[j];
                  if (b == '.') {
                      dot++;
                      if (dot > 1) {
                          break;
                      }
                      dotIndex = j;
                  } else if (b >= '0' && b <= '9') {
                      long r = unscaleValue * 10;
                      if ((unscaleValue | 10) >>> 31 == 0L || (r / 10 == unscaleValue)) {
                          unscaleValue = r + (b - '0');
                      } else {
                          unscaleValue = -1;
                          break;
                      }
                  } else {
                      unscaleValue = -1;
                      break;
                  }
              }
              int scale = 0;
              if (unscaleValue >= 0 && dot <= 1) {
                  if (negative) {
                      unscaleValue = -unscaleValue;
                  }
                  if (dotIndex != -1) {
                      scale = len - (dotIndex - off) - 1;
                  }
                  return BigDecimal.valueOf(unscaleValue, scale);
              }
          }
  
          return new BigDecimal(bytes, off, len);
      }
  
      public static BigDecimal parseBigDecimal(byte[] bytes, int off, int len) {
          if (bytes == null || len == 0) {
              return null;
          }
  
          boolean negative = false;
          int j = off;
          if (bytes[off] == '-') {
              negative = true;
              j++;
          }
  
          if (len <= 20 || (negative && len == 21)) {
              int end = off + len;
              int dot = 0;
              int dotIndex = -1;
              long unscaleValue = 0;
              for (; j < end; j++) {
                  byte b = bytes[j];
                  if (b == '.') {
                      dot++;
                      if (dot > 1) {
                          break;
                      }
                      dotIndex = j;
                  } else if (b >= '0' && b <= '9') {
                      long r = unscaleValue * 10;
                      if ((unscaleValue | 10) >>> 31 == 0L || (r / 10 == unscaleValue)) {
                          unscaleValue = r + (b - '0');
                      } else {
                          unscaleValue = -1;
                          break;
                      }
                  } else {
                      unscaleValue = -1;
                      break;
                  }
              }
              int scale = 0;
              if (unscaleValue >= 0 && dot <= 1) {
                  if (negative) {
                      unscaleValue = -unscaleValue;
                  }
                  if (dotIndex != -1) {
                      scale = len - (dotIndex - off) - 1;
                  }
                  return BigDecimal.valueOf(unscaleValue, scale);
              }
          }
  
          char[] chars;
          if (off == 0 && len == bytes.length) {
              chars = X1.TO_CHARS.apply(bytes);
          } else {
              chars = new char[len];
              for (int i = 0; i < len; i++) {
                  chars[i] = (char) bytes[off + i];
              }
          }
  
          return new BigDecimal(chars, 0, chars.length);
      }
  
      public static Integer toInteger(Object value) {
          if (value == null || value instanceof Integer) {
              return (Integer) value;
          }
  
          if (value instanceof Number) {
              return ((Number) value).intValue();
          }
  
          if (value instanceof String) {
              String str = (String) value;
              if (str.isEmpty() || "null".equals(str)) {
                  return null;
              }
              return Integer.parseInt(str);
          }
  
          if (value instanceof Map && ((Map<?, ?>) value).isEmpty()) {
              return null;
          }
  
          if (value instanceof Boolean) {
              return (Boolean) value ? 1 : 0;
          }
  
          throw new JSONException("can not cast to integer");
      }
  
      public static Byte toByte(Object value) {
          if (value == null || value instanceof Byte) {
              return (Byte) value;
          }
  
          if (value instanceof Number) {
              return ((Number) value).byteValue();
          }
  
          if (value instanceof String) {
              String str = (String) value;
              if (str.isEmpty() || "null".equals(str)) {
                  return null;
              }
              return Byte.parseByte(str);
          }
  
          throw new JSONException("can not cast to byte");
      }
  
      public static byte toByteValue(Object value) {
          if (value == null) {
              return 0;
          }
  
          if (value instanceof Byte) {
              return (Byte) value;
          }
  
          if (value instanceof Number) {
              return ((Number) value).byteValue();
          }
  
          if (value instanceof String) {
              String str = (String) value;
              if (str.isEmpty() || "null".equals(str)) {
                  return 0;
              }
              return Byte.parseByte(str);
          }
  
          throw new JSONException("can not cast to byte");
      }
  
      public static Short toShort(Object value) {
          if (value == null || value instanceof Short) {
              return (Short) value;
          }
  
          if (value instanceof Number) {
              return ((Number) value).shortValue();
          }
  
          if (value instanceof String) {
              String str = (String) value;
              if (str.isEmpty() || "null".equals(str)) {
                  return null;
              }
              return Short.parseShort(str);
          }
  
          throw new JSONException("can not cast to byte");
      }
  
      public static short toShortValue(Object value) {
          if (value == null) {
              return 0;
          }
  
          if (value instanceof Short) {
              return (Short) value;
          }
  
          if (value instanceof Number) {
              return (byte) ((Number) value).shortValue();
          }
  
          if (value instanceof String) {
              String str = (String) value;
              if (str.isEmpty() || "null".equals(str)) {
                  return 0;
              }
              return Short.parseShort(str);
          }
  
          throw new JSONException("can not cast to byte");
      }
  
      public static int toIntValue(Object value) {
          if (value == null) {
              return 0;
          }
  
          if (value instanceof Integer) {
              return (Integer) value;
          }
  
          if (value instanceof Number) {
              return ((Number) value).intValue();
          }
  
          if (value instanceof String) {
              String str = (String) value;
              if (str.isEmpty() || "null".equals(str)) {
                  return 0;
              }
  
              try {
                  int lastCommaIndex = str.lastIndexOf(',');
                  if (lastCommaIndex == str.length() - 4 && str.indexOf('.') == -1) {
                      return NumberFormat
                              .getNumberInstance()
                              .parse(str)
                              .intValue();
                  }
              } catch (ParseException ignored) {
                  // ignored
              }
  
              if (IOUtils.isNumber(str)) {
                  return Integer.parseInt(str);
              }
  
              throw new JSONException("parseInt error, " + str);
          }
  
          throw new JSONException("can not cast to int");
      }
  
      public static boolean toBooleanValue(Object value) {
          if (value == null) {
              return false;
          }
  
          if (value instanceof Boolean) {
              return (Boolean) value;
          }
  
          if (value instanceof String) {
              String str = (String) value;
              if (str.isEmpty() || "null".equals(str)) {
                  return false;
              }
              return Boolean.parseBoolean(str);
          }
  
          if (value instanceof Number) {
              int intValue = ((Number) value).intValue();
              if (intValue == 1) {
                  return true;
              }
              if (intValue == 0) {
                  return false;
              }
          }
  
          throw new JSONException("can not cast to boolean");
      }
  
      public static Boolean toBoolean(Object value) {
          if (value == null) {
              return null;
          }
  
          if (value instanceof Boolean) {
              return (Boolean) value;
          }
  
          if (value instanceof String) {
              String str = (String) value;
              if (str.isEmpty() || "null".equals(str)) {
                  return null;
              }
              return Boolean.parseBoolean(str);
          }
  
          if (value instanceof Number) {
              int intValue = ((Number) value).intValue();
              if (intValue == 1) {
                  return true;
              }
              if (intValue == 0) {
                  return false;
              }
          }
  
          throw new JSONException("can not cast to boolean");
      }
  
      public static float toFloatValue(Object value) {
          if (value == null) {
              return 0F;
          }
  
          if (value instanceof Float) {
              return (Float) value;
          }
  
          if (value instanceof Number) {
              return ((Number) value).floatValue();
          }
  
          if (value instanceof String) {
              String str = (String) value;
              if (str.isEmpty() || "null".equals(str)) {
                  return 0;
              }
              return Float.parseFloat(str);
          }
  
          throw new JSONException("can not cast to decimal");
      }
  
      public static Float toFloat(Object value) {
          if (value == null || value instanceof Float) {
              return (Float) value;
          }
  
          if (value instanceof Number) {
              return ((Number) value).floatValue();
          }
  
          if (value instanceof String) {
              String str = (String) value;
              if (str.isEmpty() || "null".equals(str)) {
                  return null;
              }
              return Float.parseFloat(str);
          }
  
          throw new JSONException("can not cast to decimal");
      }
  
      public static double toDoubleValue(Object value) {
          if (value == null) {
              return 0D;
          }
  
          if (value instanceof Double) {
              return (Double) value;
          }
  
          if (value instanceof Number) {
              return ((Number) value).doubleValue();
          }
  
          if (value instanceof String) {
              String str = (String) value;
              if (str.isEmpty() || "null".equals(str)) {
                  return 0D;
              }
              return Double.parseDouble(str);
          }
  
          if ((value instanceof Collection && ((Collection<?>) value).isEmpty())
                  || (value instanceof Map && ((Map<?, ?>) value).isEmpty())) {
              return 0;
          }
  
          if (value instanceof Collection && ((Collection<?>) value).size() == 1) {
              Object first = ((Collection<?>) value).iterator().next();
              if (first instanceof Number) {
                  return ((Number) first).doubleValue();
              } else if (first instanceof String) {
                  return Double.parseDouble((String) first);
              }
          }
  
          throw new JSONException("can not cast to double");
      }
  
      public static Double toDouble(Object value) {
          if (value == null || value instanceof Double) {
              return (Double) value;
          }
  
          if (value instanceof Number) {
              return ((Number) value).doubleValue();
          }
  
          if (value instanceof String) {
              String str = (String) value;
              if (str.isEmpty() || "null".equals(str)) {
                  return null;
              }
              return Double.parseDouble(str);
          }
  
          throw new JSONException("can not cast to double");
      }
  
      public static int compare(Object a, Object b) {
          final Class typeA = a.getClass(), typeB = b.getClass();
  
          if (typeA == typeB) {
              return ((Comparable) a).compareTo(b);
          }
  
          if (typeA == BigDecimal.class) {
              if (typeB == Integer.class || typeB == Long.class) {
                  b = BigDecimal.valueOf(((Number) b).longValue());
              } else if (typeB == Float.class || typeB == Double.class) {
                  b = BigDecimal.valueOf(((Number) b).doubleValue());
              } else if (typeB == BigInteger.class) {
                  b = new BigDecimal((BigInteger) b);
              }
          } else if (typeA == BigInteger.class) {
              if (typeB == Integer.class || typeB == Long.class) {
                  b = BigInteger.valueOf(((Number) b).longValue());
              } else if (typeB == Float.class || typeB == Double.class) {
                  b = BigDecimal.valueOf(((Number) b).doubleValue());
                  a = new BigDecimal((BigInteger) a);
              } else if (typeB == BigDecimal.class) {
                  a = new BigDecimal((BigInteger) a);
              }
          } else if (typeA == Long.class) {
              if (typeB == Integer.class) {
                  return Long.compare((Long) a, ((Integer) b));
              } else if (typeB == BigDecimal.class) {
                  a = BigDecimal.valueOf((Long) a);
              } else if (typeB == Float.class || typeB == Double.class) {
                  return Double.compare((Long) a, ((Number) b).doubleValue());
              } else if (typeB == BigInteger.class) {
                  a = BigInteger.valueOf((Long) a);
              } else if (typeB == String.class) {
                  a = BigDecimal.valueOf((Long) a);
                  b = new BigDecimal((String) b);
              }
          } else if (typeA == Integer.class) {
              if (typeB == Long.class) {
                  return Long.compare((Integer) a, ((Long) b));
              } else if (typeB == BigDecimal.class) {
                  a = BigDecimal.valueOf((Integer) a);
              } else if (typeB == BigInteger.class) {
                  a = BigInteger.valueOf((Integer) a);
              } else if (typeB == Float.class || typeB == Double.class) {
                  return Double.compare((Integer) a, ((Number) b).doubleValue());
              } else if (typeB == String.class) {
                  a = BigDecimal.valueOf((Integer) a);
                  b = new BigDecimal((String) b);
              }
          } else if (typeA == Double.class) {
              if (typeB == Integer.class || typeB == Long.class || typeB == Float.class) {
                  return Double.compare((Double) a, ((Number) b).doubleValue());
              } else if (typeB == BigDecimal.class) {
                  a = BigDecimal.valueOf((Double) a);
              } else if (typeB == String.class) {
                  a = BigDecimal.valueOf((Double) a);
                  b = new BigDecimal((String) b);
              } else if (typeB == BigInteger.class) {
                  a = BigDecimal.valueOf((Double) a);
                  b = new BigDecimal((BigInteger) b);
              }
          } else if (typeA == Float.class) {
              if (typeB == Integer.class || typeB == Long.class || typeB == Double.class) {
                  return Double.compare((Float) a, ((Number) b).doubleValue());
              } else if (typeB == BigDecimal.class) {
                  a = BigDecimal.valueOf((Float) a);
              } else if (typeB == String.class) {
                  a = BigDecimal.valueOf((Float) a);
                  b = new BigDecimal((String) b);
              } else if (typeB == BigInteger.class) {
                  a = BigDecimal.valueOf((Float) a);
                  b = new BigDecimal((BigInteger) b);
              }
          } else if (typeA == String.class) {
              String strA = (String) a;
              if (typeB == Integer.class || typeB == Long.class) {
                  try {
                      long aVal = Long.parseLong(strA);
                      return Long.compare(aVal, ((Number) b).longValue());
                  } catch (NumberFormatException ex) {
                      a = new BigDecimal(strA);
                      b = BigDecimal.valueOf(((Number) b).longValue());
                  }
              } else if (typeB == Float.class || typeB == Double.class) {
                  return Double.compare(Double.parseDouble(strA), ((Number) b).doubleValue());
              } else if (typeB == BigInteger.class) {
                  a = new BigInteger(strA);
              } else if (typeB == BigDecimal.class) {
                  a = new BigDecimal(strA);
              }
          }
  
          return ((Comparable) a).compareTo(b);
      }
  
      public static Object getDefaultValue(Type paramType) {
          if (paramType == int.class) {
              return 0;
          }
  
          if (paramType == long.class) {
              return 0L;
          }
  
          if (paramType == float.class) {
              return 0F;
          }
  
          if (paramType == double.class) {
              return 0D;
          }
  
          if (paramType == boolean.class) {
              return Boolean.FALSE;
          }
  
          if (paramType == short.class) {
              return (short) 0;
          }
  
          if (paramType == byte.class) {
              return (byte) 0;
          }
  
          if (paramType == char.class) {
              return (char) 0;
          }
  
          if (paramType == Optional.class) {
              return Optional.empty();
          }
  
          if (paramType == OptionalInt.class) {
              return OptionalInt.empty();
          }
  
          if (paramType == OptionalLong.class) {
              return OptionalLong.empty();
          }
  
          if (paramType == OptionalDouble.class) {
              return OptionalDouble.empty();
          }
  
          return null;
      }
  
      public static Class loadClass(String className) {
          if (className.length() >= 192) {
              return null;
          }
  
          switch (className) {
              case "O":
              case "Object":
              case "java.lang.Object":
                  return Object.class;
              case "java.util.Collections$EmptyMap":
                  return Collections.emptyMap().getClass();
              case "java.util.Collections$EmptyList":
                  return Collections.emptyList().getClass();
              case "java.util.Collections$EmptySet":
                  return Collections.emptySet().getClass();
              case "java.util.Optional":
                  return Optional.class;
              case "java.util.OptionalInt":
                  return OptionalInt.class;
              case "java.util.OptionalLong":
                  return OptionalLong.class;
              case "List":
              case "java.util.List":
                  return List.class;
              case "A":
              case "ArrayList":
              case "java.util.ArrayList":
                  return ArrayList.class;
              case "LA":
              case "LinkedList":
              case "java.util.LinkedList":
                  return LinkedList.class;
              case "Map":
              case "java.util.Map":
                  return Map.class;
              case "M":
              case "HashMap":
              case "java.util.HashMap":
                  return HashMap.class;
              case "LM":
              case "LinkedHashMap":
              case "java.util.LinkedHashMap":
                  return LinkedHashMap.class;
              case "ConcurrentHashMap":
                  return ConcurrentHashMap.class;
              case "ConcurrentLinkedQueue":
                  return ConcurrentLinkedQueue.class;
              case "ConcurrentLinkedDeque":
                  return ConcurrentLinkedDeque.class;
              case "JSONObject":
                  return JSONObject.class;
              case "JO1":
                  className = "com.alibaba.fastjson.JSONObject";
                  break;
              case "Set":
              case "java.util.Set":
                  return Set.class;
              case "HashSet":
              case "java.util.HashSet":
                  return HashSet.class;
              case "LinkedHashSet":
              case "java.util.LinkedHashSet":
                  return LinkedHashSet.class;
              case "TreeSet":
              case "java.util.TreeSet":
                  return TreeSet.class;
              case "java.lang.Class":
                  return Class.class;
              case "java.lang.Integer":
                  return Integer.class;
              case "java.lang.Long":
                  return Long.class;
              case "String":
              case "java.lang.String":
                  return String.class;
              case "[String":
                  return String[].class;
              case "I":
              case "int":
                  return int.class;
              case "S":
              case "short":
                  return short.class;
              case "J":
              case "long":
                  return long.class;
              case "Z":
              case "boolean":
                  return boolean.class;
              case "B":
              case "byte":
                  return byte.class;
              case "F":
              case "float":
                  return float.class;
              case "D":
              case "double":
                  return double.class;
              case "C":
              case "char":
                  return char.class;
              case "[B":
              case "byte[]":
                  return byte[].class;
              case "[S":
              case "short[]":
                  return short[].class;
              case "[I":
              case "int[]":
                  return int[].class;
              case "[J":
              case "long[]":
                  return long[].class;
              case "[F":
              case "float[]":
                  return float[].class;
              case "[D":
              case "double[]":
                  return double[].class;
              case "[C":
              case "char[]":
                  return char[].class;
              case "[Z":
              case "boolean[]":
                  return boolean[].class;
              case "[O":
                  return Object[].class;
              case "UUID":
                  return UUID.class;
              case "Date":
                  return Date.class;
              case "Calendar":
                  return Calendar.class;
              case "java.io.IOException":
                  return java.io.IOException.class;
              case "java.util.Collections$UnmodifiableRandomAccessList":
                  return CLASS_UNMODIFIABLE_LIST;
              case "java.util.Arrays$ArrayList":
                  return Arrays.asList(1).getClass();
              case "java.util.Collections$SingletonList":
                  return CLASS_SINGLE_LIST;
              case "java.util.Collections$SingletonSet":
                  return CLASS_SINGLE_SET;
              default:
                  break;
          }
  
          Class mapping = TYPE_MAPPINGS.get(className);
          if (mapping != null) {
              return mapping;
          }
  
          if (className.startsWith("java.util.ImmutableCollections$")) {
              try {
                  return Class.forName(className);
              } catch (ClassNotFoundException e) {
                  return CLASS_UNMODIFIABLE_LIST;
              }
          }
  
          if (className.charAt(0) == 'L' && className.charAt(className.length() - 1) == ';') {
              className = className.substring(1, className.length() - 1);
          }
  
          if (className.charAt(0) == '[' || className.endsWith("[]")) {
              String itemClassName = className.charAt(0) == '[' ? className.substring(1) : className.substring(0, className.length() - 2);
              Class itemClass = loadClass(itemClassName);
              if (itemClass == null) {
                  throw new JSONException("load class error " + className);
              }
              return Array.newInstance(itemClass, 0).getClass();
          }
  
          ClassLoader contextClassLoader = Thread.currentThread().getContextClassLoader();
          if (contextClassLoader != null) {
              try {
                  return contextClassLoader.loadClass(className);
              } catch (ClassNotFoundException ignored) {
              }
          }
  
          try {
              return JSON.class.getClassLoader().loadClass(className);
          } catch (ClassNotFoundException ignored) {
          }
  
          try {
              return Class.forName(className);
          } catch (ClassNotFoundException ignored) {
          }
  
          return null;
      }
  
      public static Class<?> getArrayClass(Class componentClass) {
          if (componentClass == int.class) {
              return int[].class;
          }
          if (componentClass == byte.class) {
              return byte[].class;
          }
          if (componentClass == short.class) {
              return short[].class;
          }
          if (componentClass == long.class) {
              return long[].class;
          }
          if (componentClass == String.class) {
              return String[].class;
          }
          if (componentClass == Object.class) {
              return Object[].class;
          }
          return Array.newInstance(componentClass, 1).getClass();
      }
  
      public static Class nonePrimitive(Class type) {
          if (type.isPrimitive()) {
              String name = type.getName();
              switch (name) {
                  case "byte":
                      return Byte.class;
                  case "short":
                      return Short.class;
                  case "int":
                      return Integer.class;
                  case "long":
                      return Long.class;
                  case "float":
                      return Float.class;
                  case "double":
                      return Double.class;
                  case "char":
                      return Character.class;
                  case "boolean":
                      return Boolean.class;
                  default:
                      break;
              }
          }
          return type;
      }
  
      public static Class<?> getClass(Type type) {
          if (type == null) {
              return null;
          }
  
          if (type.getClass() == Class.class) {
              return (Class<?>) type;
          }
  
          if (type instanceof ParameterizedType) {
              return getClass(((ParameterizedType) type).getRawType());
          }
  
          if (type instanceof TypeVariable) {
              Type boundType = ((TypeVariable<?>) type).getBounds()[0];
              if (boundType instanceof Class) {
                  return (Class) boundType;
              }
              return getClass(boundType);
          }
  
          if (type instanceof WildcardType) {
              Type[] upperBounds = ((WildcardType) type).getUpperBounds();
              if (upperBounds.length == 1) {
                  return getClass(upperBounds[0]);
              }
          }
  
          if (type instanceof GenericArrayType) {
              GenericArrayType genericArrayType = (GenericArrayType) type;
              Type componentType = genericArrayType.getGenericComponentType();
              Class<?> componentClass = getClass(componentType);
              return getArrayClass(componentClass);
          }
  
          return Object.class;
      }
  
      public static boolean isProxy(Class<?> clazz) {
          // Check if the class name contains Spring Cloud RefreshScope indicators
          String className = clazz.getName();
          int p = className.indexOf('$');
          if (p != -1
                  && (className.contains("$EnhancerBySpringCGLIB$")
                  || className.contains("$EnhancerByCGLIB$")
                  || className.contains("$FastClassBySpringCGLIB$")
                  || className.contains("$FastClassByCGLIB$")
                  || className.contains("$EnhancerBySpringCGLIB$")
                  || className.contains("$EnhancerByCGLIB$"))) {
              return true;
          }
  
          // Check interfaces for RefreshScope marker or other proxy indicators
          for (Class<?> item : clazz.getInterfaces()) {
              String interfaceName = item.getName();
              switch (interfaceName) {
                  case "org.springframework.cloud.context.config.annotation.RefreshScope":
                  case "org.springframework.cglib.proxy.Factory":
                  case "javassist.util.proxy.ProxyObject":
                  case "org.apache.ibatis.javassist.util.proxy.ProxyObject":
                  case "org.hibernate.proxy.HibernateProxy":
                  case "org.springframework.context.annotation.ConfigurationClassEnhancer$EnhancedConfiguration":
                  case "org.mockito.cglib.proxy.Factory":
                  case "net.sf.cglib.proxy.Factory":
                      return true;
                  default:
                      // Check if interface name contains Spring-related patterns
                      if (interfaceName.startsWith("org.springframework.cloud.context.config.annotation.") &&
                              interfaceName.endsWith("RefreshScope")) {
                          return true;
                      }
                      break;
              }
          }
  
          // Check if class name follows Spring proxy patterns
          if (className.contains("$SpringCGLIB$")
                  || className.contains("$SpringCGLIB$")
                  || className.contains("$EnhancerBySpringCGLIB$")) {
              return true;
          }
  
          return false;
      }
  
      public static Map getInnerMap(Map object) {
          if (CLASS_JSON_OBJECT_1x == null || !CLASS_JSON_OBJECT_1x.isInstance(object) || FIELD_JSON_OBJECT_1x_map == null) {
              return object;
          }
  
          try {
              object = (Map) FIELD_JSON_OBJECT_1x_map.get(object);
          } catch (IllegalAccessException ignore) {
              // ignore
          }
  
          return object;
      }
  
      public static boolean isFunction(Class type) {
          if (type.isInterface()) {
              String typeName = type.getName();
              if (typeName.startsWith("java.util.function.")) {
                  return true;
              }
  
              return type.isAnnotationPresent(FunctionalInterface.class);
          }
  
          return false;
      }
  
      public static boolean isInteger(String str) {
          if (str == null || str.isEmpty()) {
              return false;
          }
  
          char ch = str.charAt(0);
          boolean sign = ch == '-' || ch == '+';
          if (sign) {
              if (str.length() == 1) {
                  return false;
              }
          } else if (ch < '0' || ch > '9') {
              return false;
          }
  
          for (int i = 1; i < str.length(); ++i) {
              ch = str.charAt(i);
              if (ch < '0' || ch > '9') {
                  return false;
              }
          }
          return true;
      }
  
      public static boolean isInteger(byte[] str, int off, int len) {
          if (str == null || len == 0) {
              return false;
          }
  
          char ch = (char) str[off];
          boolean sign = ch == '-' || ch == '+';
          if (sign) {
              if (len == 1) {
                  return false;
              }
          } else if (ch < '0' || ch > '9') {
              return false;
          }
  
          final int end = off + len;
          for (int i = off + 1; i < end; ++i) {
              ch = (char) str[i];
              if (ch < '0' || ch > '9') {
                  return false;
              }
          }
          return true;
      }
  
      public static boolean isInteger(char[] str, int off, int len) {
          if (str == null || len == 0) {
              return false;
          }
  
          char ch = str[off];
          boolean sign = ch == '-' || ch == '+';
          if (sign) {
              if (len == 1) {
                  return false;
              }
          } else if (ch < '0' || ch > '9') {
              return false;
          }
  
          final int end = off + len;
          for (int i = off + 1; i < end; ++i) {
              ch = str[i];
              if (ch < '0' || ch > '9') {
                  return false;
              }
          }
          return true;
      }
  
      public static boolean isNumber(String str) {
          if (str == null || str.isEmpty()) {
              return false;
          }
          char ch = str.charAt(0);
          int offset;
          boolean sign = ch == '-' || ch == '+';
          if (sign) {
              if (str.length() == 1) {
                  return false;
              }
              ch = str.charAt(1);
              offset = 1;
          } else {
              if (ch == '.') {
                  if (str.length() == 1) {
                      return false;
                  }
  
                  offset = 1;
              } else {
                  offset = 0;
              }
          }
  
          int end = str.length();
          boolean dot = ch == '.';
          boolean space = false;
          boolean num = false;
          if (!dot && (ch >= '0' && ch <= '9')) {
              num = true;
              do {
                  if (offset < end) {
                      ch = str.charAt(offset++);
                  } else {
                      return true;
                  }
              } while (!space && ch >= '0' && ch <= '9');
          }
  
          boolean small = false;
          if (ch == '.') {
              small = true;
              if (offset < end) {
                  ch = str.charAt(offset++);
              } else {
                  return true;
              }
  
              if (ch >= '0' && ch <= '9') {
                  do {
                      if (offset < end) {
                          ch = str.charAt(offset++);
                      } else {
                          return true;
                      }
                  } while (!space && ch >= '0' && ch <= '9');
              }
          }
  
          if (!num && !small) {
              return false;
          }
  
          if (ch == 'e' || ch == 'E') {
              if (offset == end) {
                  return true;
              }
  
              ch = str.charAt(offset++);
  
              boolean eSign = false;
              if (ch == '+' || ch == '-') {
                  eSign = true;
                  if (offset < end) {
                      ch = str.charAt(offset++);
                  } else {
                      return false;
                  }
              }
  
              if (ch >= '0' && ch <= '9') {
                  do {
                      if (offset < end) {
                          ch = str.charAt(offset++);
                      } else {
                          return true;
                      }
                  } while (ch >= '0' && ch <= '9');
              } else if (eSign) {
                  return false;
              }
          }
  
          return false;
      }
  
      public static boolean isNumber(byte[] str, int off, int len) {
          if (str == null || len == 0) {
              return false;
          }
  
          char ch = (char) str[off];
          int offset;
          boolean sign = ch == '-' || ch == '+';
          if (sign) {
              if (len == 1) {
                  return false;
              }
              ch = (char) str[off + 1];
              offset = off + 1;
          } else {
              if (ch == '.') {
                  if (len == 1) {
                      return false;
                  }
  
                  offset = off + 1;
              } else {
                  offset = off;
              }
          }
  
          int end = off + len;
          boolean dot = ch == '.';
          boolean num = false;
          if (!dot && (ch >= '0' && ch <= '9')) {
              num = true;
              do {
                  if (offset < end) {
                      ch = (char) str[offset++];
                  } else {
                      return true;
                  }
              } while (ch >= '0' && ch <= '9');
          }
  
          boolean small = false;
          if (ch == '.') {
              small = true;
              if (offset < end) {
                  ch = (char) str[offset++];
              } else {
                  return true;
              }
  
              if (ch >= '0' && ch <= '9') {
                  do {
                      if (offset < end) {
                          ch = (char) str[offset++];
                      } else {
                          return true;
                      }
                  } while (ch >= '0' && ch <= '9');
              }
          }
  
          if (!num && !small) {
              return false;
          }
  
          if (ch == 'e' || ch == 'E') {
              if (offset == end) {
                  return true;
              }
  
              ch = (char) str[offset++];
  
              boolean eSign = false;
              if (ch == '+' || ch == '-') {
                  eSign = true;
                  if (offset < end) {
                      ch = (char) str[offset++];
                  } else {
                      return false;
                  }
              }
  
              if (ch >= '0' && ch <= '9') {
                  do {
                      if (offset < end) {
                          ch = (char) str[offset++];
                      } else {
                          return true;
                      }
                  } while (ch >= '0' && ch <= '9');
              } else if (eSign) {
                  return false;
              }
          }
  
          return false;
      }
  
      public static boolean isNumber(char[] str, int off, int len) {
          if (str == null || len == 0) {
              return false;
          }
  
          char ch = str[off];
          int offset;
          boolean sign = ch == '-' || ch == '+';
          if (sign) {
              if (len == 1) {
                  return false;
              }
              ch = str[off + 1];
              offset = off + 1;
          } else {
              if (ch == '.') {
                  if (len == 1) {
                      return false;
                  }
  
                  offset = off + 1;
              } else {
                  offset = off;
              }
          }
  
          int end = off + len;
          boolean dot = ch == '.';
          boolean space = false;
          boolean num = false;
          if (!dot && (ch >= '0' && ch <= '9')) {
              num = true;
              do {
                  if (offset < end) {
                      ch = str[offset++];
                  } else {
                      return true;
                  }
              } while (!space && ch >= '0' && ch <= '9');
          }
  
          boolean small = false;
          if (ch == '.') {
              small = true;
              if (offset < end) {
                  ch = str[offset++];
              } else {
                  return true;
              }
  
              if (ch >= '0' && ch <= '9') {
                  do {
                      if (offset < end) {
                          ch = str[offset++];
                      } else {
                          return true;
                      }
                  } while (!space && ch >= '0' && ch <= '9');
              }
          }
  
          if (!num && !small) {
              return false;
          }
  
          if (ch == 'e' || ch == 'E') {
              if (offset == end) {
                  return true;
              }
  
              ch = str[offset++];
  
              boolean eSign = false;
              if (ch == '+' || ch == '-') {
                  eSign = true;
                  if (offset < end) {
                      ch = str[offset++];
                  } else {
                      return false;
                  }
              }
  
              if (ch >= '0' && ch <= '9') {
                  do {
                      if (offset < end) {
                          ch = str[offset++];
                      } else {
                          return true;
                      }
                  } while (ch >= '0' && ch <= '9');
              } else if (eSign) {
                  return false;
              }
          }
  
          return false;
      }
  
      public static boolean isUUID(String str) {
          if (str == null) {
              return false;
          }
  
          if (str.length() == 32) {
              for (int i = 0; i < 32; i++) {
                  char ch = str.charAt(i);
                  boolean valid = (ch >= '0' && ch <= '9') || (ch >= 'A' && ch <= 'F') || (ch >= 'a' && ch <= 'f');
                  if (!valid) {
                      return false;
                  }
              }
              return true;
          }
  
          if (str.length() == 36) {
              for (int i = 0; i < 36; i++) {
                  char ch = str.charAt(i);
  
                  if (i == 8 || i == 13 || i == 18 || i == 23) {
                      if (ch != '-') {
                          return false;
                      }
                      continue;
                  }
  
                  boolean valid = (ch >= '0' && ch <= '9') || (ch >= 'A' && ch <= 'F') || (ch >= 'a' && ch <= 'f');
                  if (!valid) {
                      return false;
                  }
              }
              return true;
          }
          return false;
      }
  
      public static boolean validateIPv4(String str) {
          return validateIPv4(str, 0);
      }
  
      static boolean validateIPv4(String str, int off) {
          if (str == null) {
              return false;
          }
  
          int strlen = str.length();
          {
              final int len = strlen - off;
              if (len < 7 || len > 25) {
                  return false;
              }
          }
  
          int start = off;
          int dotCount = 0;
          for (int i = off; i < strlen; i++) {
              char ch = str.charAt(i);
              if (ch == '.' || i == strlen - 1) {
                  int end = ch == '.' ? i : i + 1;
                  int n = end - start;
  
                  char c0, c1, c2;
                  switch (n) {
                      case 1:
                          c0 = str.charAt(end - 1);
                          if (c0 < '0' || c0 > '9') {
                              return false;
                          }
                          break;
                      case 2:
                          c0 = str.charAt(end - 2);
                          c1 = str.charAt(end - 1);
  
                          if (c0 < '0' || c0 > '9') {
                              return false;
                          }
                          if (c1 < '0' || c1 > '9') {
                              return false;
                          }
                          break;
                      case 3:
                          c0 = str.charAt(end - 3);
                          c1 = str.charAt(end - 2);
                          c2 = str.charAt(end - 1);
  
                          if (c0 < '0' || c0 > '2') {
                              return false;
                          }
                          if (c1 < '0' || c1 > '9') {
                              return false;
                          }
                          if (c2 < '0' || c2 > '9') {
                              return false;
                          }
                          int value = (c0 - '0') * 100 + (c1 - '0') * 10 + (c2 - '0');
                          if (value > 255) {
                              return false;
                          }
                          break;
                      default:
                          return false;
                  }
  
                  if (ch == '.') {
                      dotCount++;
                      start = i + 1;
                  }
              }
          }
  
          return dotCount == 3;
      }
  
      public static boolean validateIPv6(String str) {
          if (str == null) {
              return false;
          }
  
          final int len = str.length();
          if (len < 2 || len > 39) {
              return false;
          }
  
          int start = 0;
          int colonCount = 0;
          for (int i = 0; i < len; i++) {
              char ch = str.charAt(i);
              if (ch == '.') {
                  boolean ipV4 = validateIPv4(str, start);
                  if (!ipV4) {
                      return false;
                  }
                  break;
              }
              if (ch == ':' || i == len - 1) {
                  int end = ch == ':' ? i : i + 1;
                  int n = end - start;
  
                  char c0, c1, c2, c3;
                  switch (n) {
                      case 0:
                          break;
                      case 1:
                          c0 = str.charAt(end - 1);
                          if (!(c0 >= '0' && c0 <= '9' || (c0 >= 'A' && c0 <= 'F') || (c0 >= 'a' && c0 <= 'f'))) {
                              return false;
                          }
                          break;
                      case 2:
                          c0 = str.charAt(end - 2);
                          c1 = str.charAt(end - 1);
  
                          if (!(c0 >= '0' && c0 <= '9' || (c0 >= 'A' && c0 <= 'F') || (c0 >= 'a' && c0 <= 'f'))) {
                              return false;
                          }
                          if (!(c1 >= '0' && c1 <= '9' || (c1 >= 'A' && c1 <= 'F') || (c1 >= 'a' && c1 <= 'f'))) {
                              return false;
                          }
                          break;
                      case 3:
                          c0 = str.charAt(end - 3);
                          c1 = str.charAt(end - 2);
                          c2 = str.charAt(end - 1);
  
                          if (!(c0 >= '0' && c0 <= '9' || (c0 >= 'A' && c0 <= 'F') || (c0 >= 'a' && c0 <= 'f'))) {
                              return false;
                          }
                          if (!(c1 >= '0' && c1 <= '9' || (c1 >= 'A' && c1 <= 'F') || (c1 >= 'a' && c1 <= 'f'))) {
                              return false;
                          }
                          if (!(c2 >= '0' && c2 <= '9' || (c2 >= 'A' && c2 <= 'F') || (c2 >= 'a' && c2 <= 'f'))) {
                              return false;
                          }
                          break;
                      case 4:
                          c0 = str.charAt(end - 4);
                          c1 = str.charAt(end - 3);
                          c2 = str.charAt(end - 2);
                          c3 = str.charAt(end - 1);
  
                          if (!(c0 >= '0' && c0 <= '9' || (c0 >= 'A' && c0 <= 'F') || (c0 >= 'a' && c0 <= 'f'))) {
                              return false;
                          }
                          if (!(c1 >= '0' && c1 <= '9' || (c1 >= 'A' && c1 <= 'F') || (c1 >= 'a' && c1 <= 'f'))) {
                              return false;
                          }
                          if (!(c2 >= '0' && c2 <= '9' || (c2 >= 'A' && c2 <= 'F') || (c2 >= 'a' && c2 <= 'f'))) {
                              return false;
                          }
                          if (!(c3 >= '0' && c3 <= '9' || (c3 >= 'A' && c3 <= 'F') || (c3 >= 'a' && c3 <= 'f'))) {
                              return false;
                          }
                          break;
                      default:
                          return false;
                  }
  
                  if (ch == ':') {
                      colonCount++;
                      start = i + 1;
                  }
              }
          }
  
          return colonCount > 0 && colonCount < 8;
      }
  
      private static final int P_D = 53; // Double.PRECISION
      private static final int Q_MIN_D = -1074; //(Double.MIN_EXPONENT - (P_D - 1));
      private static final int Q_MAX_D = 971; // (Double.MAX_EXPONENT - (P_D - 1));
      private static final double L = 3.321928094887362;
      private static final int P_F = 24;
      private static final int Q_MIN_F = -149;
      private static final int Q_MAX_F = 104;
  
      public static double doubleValue(int signNum, long intCompact, int scale) {
          int bitLength = 64 - Long.numberOfLeadingZeros(intCompact);
          long qb = bitLength - (long) Math.ceil(scale * L);
          if (qb < Q_MIN_D - 2) {  // qb < -1_076
              return signNum * 0.0;
          }
          if (qb > Q_MAX_D + P_D + 1) {  // qb > 1_025
              /* If s <= -309 then qb >= 1_027, so these cases all end up here. */
              return signNum * Double.POSITIVE_INFINITY;
          }
  
          if (scale == 0) {
              return signNum * (double) intCompact;
          }
  
          int ql = (int) qb - (P_D + 3);  // narrowing qb to an int is safe
          long i = MutableBigInteger.divideKnuthLong(intCompact, ql, scale);
  
          int dq = (Long.SIZE - (P_D + 2)) - Long.numberOfLeadingZeros(i);
          int eq = (Q_MIN_D - 2) - ql;
          if (dq >= eq) {
              return signNum * Math.scalb((double) (i | 1), ql);
          }
  
          /* Subnormal */
          long mask = (1L << eq) - 1;
          long j = i >> eq | Long.signum(i & mask) | 1;
          return signNum * Math.scalb((double) j, Q_MIN_D - 2);
      }
  
      public static float floatValue(int signNum, long intCompact, int scale) {
          int bitLength = 64 - Long.numberOfLeadingZeros(intCompact);
          long qb = bitLength - (long) Math.ceil(scale * L);
          if (qb < Q_MIN_F - 2) {  // qb < -151
              return signNum * 0.0f;
          }
          if (qb > Q_MAX_F + P_F + 1) {  // qb > 129
              return signNum * Float.POSITIVE_INFINITY;
          }
          if (scale == 0) {
              return signNum * (float) intCompact;
          }
  
          int ql = (int) qb - (P_F + 3);  // narrowing qb to an int is safe
          int i = (int) MutableBigInteger.divideKnuthLong(intCompact, ql, scale);
  
          int sb = intCompact == 0 ? 0 : 1;
          int dq = (Integer.SIZE - (P_F + 2)) - Integer.numberOfLeadingZeros(i);
          int eq = (Q_MIN_F - 2) - ql;
          if (dq >= eq) {
              return signNum * Math.scalb((float) (i | sb), ql);
          }
          int mask = (1 << eq) - 1;
          int j = i >> eq | (Integer.signum(i & mask)) | sb;
          return signNum * Math.scalb((float) j, Q_MIN_F - 2);
      }
  
      public static boolean isJavaScriptSupport(long i) {
          return i >= LONG_JAVASCRIPT_LOW && i <= LONG_JAVASCRIPT_HIGH;
      }
  
      public static boolean isJavaScriptSupport(BigDecimal decimal) {
          boolean jsSupport = decimal.precision() < 16 || isJavaScriptSupport(decimal.unscaledValue());
          if (!jsSupport && decimal.scale() != 0) {
              //Use double for comparison
              //double and javascript number have the same precision
              //In extreme cases, precision loss may occur.
              //There will be a loss of precision between [4.9e-324, 5e-324), which will be converted to 5e-324 by JavaScript.
              //This situation can be ignored
              double doubleValue;
              try {
                  doubleValue = decimal.doubleValue();
              } catch (Exception ex) {
                  return false;
              }
              jsSupport = decimal.compareTo(BigDecimal.valueOf(doubleValue)) == 0;
          }
          return jsSupport;
      }
  
      public static boolean isJavaScriptSupport(BigInteger i) {
          return i.compareTo(BIGINT_JAVASCRIPT_LOW) >= 0 && i.compareTo(BIGINT_JAVASCRIPT_HIGH) <= 0;
      }
  
      public static Type getMapValueType(Type fieldType) {
          if (fieldType instanceof ParameterizedType) {
              ParameterizedType parameterizedType = (ParameterizedType) fieldType;
              Type[] actualTypeArguments = parameterizedType.getActualTypeArguments();
              if (actualTypeArguments.length == 2) {
                  return actualTypeArguments[1];
              }
          }
          return Object.class;
      }
  }
  