code: protected static int getNumberType(Number value) {
          if (value.getClass() == Double.TYPE ||
              value instanceof Double ||
              value instanceof BigDecimal) {
              return TYPE_DOUBLE;
          }
          else if (value.getClass() == Float.TYPE ||
                   value instanceof Float) {
              return TYPE_FLOAT;
          }
          else if (value.getClass() == Long.TYPE ||
                   value instanceof Long ||
                   value instanceof AtomicLong ||
                   value instanceof BigInteger) {
              return TYPE_LONG;
          }
          else if (value.getClass() == Integer.TYPE ||
                   value.getClass() == Short.TYPE ||
                   value.getClass() == Byte.TYPE ||
                   value instanceof Integer ||
                   value instanceof AtomicInteger ||
                   value instanceof Short ||
                   value instanceof Byte) {
              return TYPE_INT;
          }
          else {
              return TYPE_DOUBLE;
          }
      }
docs: Get the type of number for a given numerical value. This returns a given
  constant based on the type of number including atomic values such as
  {@link AtomicInteger} and {@link AtomicLong} and the big data values such
  as {@link BigDecimal} and {@link BigInteger}.  Numbers with the same
  number type are more directly comparable using a given primitive type.
  For example, {@link Long} and {@link AtomicLong} are both types of
  {@link #TYPE_LONG} and comparable via {@link Number#longValue()}.  If the
  type is undefined or an unknown subclass of {@link Number}, then
  {@link #TYPE_DOUBLE} is assumed in order to be most compatible without
  losing potential values.
  
  @param value The value to check
  
  @return {@link #TYPE_DOUBLE}, {@link #TYPE_FLOAT}, {@link #TYPE_LONG},
  or {@link #TYPE_INT} based on the data type