com.github.liuanxin.api.util.Tools Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of api-document Show documentation
Show all versions of api-document Show documentation
Collect api document, support to spring mvc
The newest version!
package com.github.liuanxin.api.util;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.ObjectWriter;
import com.github.liuanxin.api.constant.ApiConst;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.multipart.MultipartFile;
import java.io.IOException;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;
@SuppressWarnings({"unchecked", "rawtypes"})
public class Tools {
private static final Logger LOGGER = LoggerFactory.getLogger(Tools.class);
/** enum info */
private static final Map ENUM_MAP = maps();
/** just basic type: int long double array etc... */
private static final Map> BASIC_CLAZZ_MAP = maps(
boolean.class.getSimpleName(), boolean.class,
Boolean.class.getSimpleName(), boolean.class,
byte.class.getSimpleName(), byte.class,
Byte.class.getSimpleName(), byte.class,
char.class.getSimpleName(), char.class,
Character.class.getSimpleName(), char.class,
short.class.getSimpleName(), short.class,
Short.class.getSimpleName(), short.class,
int.class.getSimpleName(), int.class,
Integer.class.getSimpleName(), int.class,
long.class.getSimpleName(), long.class,
Long.class.getSimpleName(), long.class,
float.class.getSimpleName(), float.class,
Float.class.getSimpleName(), float.class,
double.class.getSimpleName(), double.class,
Double.class.getSimpleName(), double.class,
BigInteger.class.getSimpleName(), long.class,
BigDecimal.class.getSimpleName(), double.class,
String.class.getSimpleName(), String.class,
Date.class.getSimpleName(), Date.class,
// up type, down array type
boolean[].class.getSimpleName(), boolean[].class,
Boolean[].class.getSimpleName(), boolean[].class,
byte[].class.getSimpleName(), byte[].class,
Byte[].class.getSimpleName(), byte[].class,
char[].class.getSimpleName(), char[].class,
Character[].class.getSimpleName(), char[].class,
short[].class.getSimpleName(), short[].class,
Short[].class.getSimpleName(), short[].class,
int[].class.getSimpleName(), int[].class,
Integer[].class.getSimpleName(), int[].class,
long[].class.getSimpleName(), long[].class,
Long[].class.getSimpleName(), long[].class,
float[].class.getSimpleName(), float[].class,
Float[].class.getSimpleName(), float[].class,
double[].class.getSimpleName(), double[].class,
Double[].class.getSimpleName(), double[].class,
BigInteger[].class.getSimpleName(), long[].class,
BigDecimal[].class.getSimpleName(), double[].class,
String[].class.getSimpleName(), String[].class,
Date[].class.getSimpleName(), Date[].class
);
/** { basic-type : default-value } */
private static final Map BASIC_TYPE_VALUE_MAP = maps(
boolean.class.getSimpleName(), false,
Boolean.class.getSimpleName(), false,
byte.class.getSimpleName(), (byte) 0,
Byte.class.getSimpleName(), (byte) 0,
char.class.getSimpleName(), (char) 0,
Character.class.getSimpleName(), (char) 0,
short.class.getSimpleName(), (short) 0,
Short.class.getSimpleName(), (short) 0,
int.class.getSimpleName(), 0,
Integer.class.getSimpleName(), 0,
long.class.getSimpleName(), 0L,
Long.class.getSimpleName(), 0L,
float.class.getSimpleName(), 0F,
Float.class.getSimpleName(), 0F,
double.class.getSimpleName(), 0D,
Double.class.getSimpleName(), 0D,
BigInteger.class.getSimpleName(), BigInteger.ZERO,
BigDecimal.class.getSimpleName(), BigDecimal.ZERO,
String.class.getSimpleName(), ApiConst.EMPTY,
Date.class.getSimpleName(), ApiConst.NOW,
// up type, down array type
boolean[].class.getSimpleName(), new boolean[] { false },
Boolean[].class.getSimpleName(), new Boolean[] { false },
byte[].class.getSimpleName(), new byte[] { (byte) 0 },
Byte[].class.getSimpleName(), new Byte[] { (byte) 0 },
char[].class.getSimpleName(), new char[] { (char) 0 },
Character[].class.getSimpleName(), new Character[] { (char) 0 },
short[].class.getSimpleName(), new short[] { (short) 0 },
Short[].class.getSimpleName(), new Short[] { (short) 0 },
int[].class.getSimpleName(), new int[] { 0 },
Integer[].class.getSimpleName(), new Integer[] { 0 },
long[].class.getSimpleName(), new long[] { 0L },
Long[].class.getSimpleName(), new Long[] { 0L },
float[].class.getSimpleName(), new float[] { 0F },
Float[].class.getSimpleName(), new Float[] { 0F },
double[].class.getSimpleName(), new double[] { 0D },
Double[].class.getSimpleName(), new Double[] { 0D },
BigInteger[].class.getSimpleName(), new BigInteger[] { BigInteger.ZERO },
BigDecimal[].class.getSimpleName(), new BigDecimal[] { BigDecimal.ZERO },
String[].class.getSimpleName(), new String[] { ApiConst.EMPTY },
Date[].class.getSimpleName(), new Date[] { ApiConst.NOW }
);
private static final Map DEFAULT_MAP_KEY = maps(
Boolean.class.getSimpleName(), false,
Byte.class.getSimpleName(), (byte) 0,
Character.class.getSimpleName(), (char) 0,
Short.class.getSimpleName(), (short) 0,
Integer.class.getSimpleName(), 0,
Long.class.getSimpleName(), 0L,
Float.class.getSimpleName(), 0F,
Double.class.getSimpleName(), 0D,
BigInteger.class.getSimpleName(), BigInteger.ZERO,
BigDecimal.class.getSimpleName(), BigDecimal.ZERO,
String.class.getSimpleName(), "?"
);
// ========== string ==========
public static boolean isNull(Object obj) {
return obj == null;
}
public static boolean isNotNull(Object obj) {
return !isNull(obj);
}
public static boolean isEmpty(Object obj) {
return isNull(obj) || obj.toString().trim().isEmpty();
}
public static boolean isNotEmpty(Object obj) {
return !isEmpty(obj);
}
private static String toStr(Object obj) {
return isNull(obj) ? ApiConst.EMPTY : obj.toString();
}
// ========== date ==========
private static Date parseDate(String source) {
if (isNotNull(source)) {
source = source.trim();
for (DateType type : DateType.values()) {
try {
Date date = new SimpleDateFormat(type.getValue()).parse(source);
if (Tools.isNotNull(date)) {
return date;
}
} catch (ParseException | IllegalArgumentException ignore) {
}
}
}
return ApiConst.NOW;
}
// ========== json ==========
private static final ObjectMapper RENDER = new ObjectMapper();
private static final ObjectWriter PRETTY_RENDER = RENDER.writerWithDefaultPrettyPrinter();
public static String toJson(Object obj) {
if (isEmpty(obj)) {
return ApiConst.EMPTY;
}
try {
return RENDER.writeValueAsString(obj);
} catch (Exception e) {
if (LOGGER.isErrorEnabled()) {
LOGGER.error(String.format("obj(%s) to json exception", obj.toString()), e);
}
return ApiConst.EMPTY;
}
}
public static T toObject(String json, Class clazz) {
if (isEmpty(json)) {
return null;
}
try {
return RENDER.readValue(json, clazz);
} catch (Exception e) {
if (LOGGER.isErrorEnabled()) {
LOGGER.error(String.format("json(%s) to Object(%s) exception", json, clazz.getName()), e);
}
return null;
}
}
public static String toPrettyJson(String json) {
if (isEmpty(json)) {
return ApiConst.EMPTY;
}
try {
return PRETTY_RENDER.writeValueAsString(RENDER.readValue(json, Object.class));
} catch (IOException e) {
if (LOGGER.isErrorEnabled()) {
LOGGER.error(String.format("str(%s) to pretty json exception", json), e);
}
return ApiConst.EMPTY;
}
}
// ========== array map ==========
public static boolean isEmpty(T[] array) {
return isNull(array) || array.length == 0;
}
public static boolean isNotEmpty(T[] array) {
return !isEmpty(array);
}
public static boolean isEmpty(Collection collection) {
return isNull(collection) || collection.isEmpty();
}
public static boolean isNotEmpty(Collection collection) {
return !isEmpty(collection);
}
private static boolean isEmpty(Map map) {
return isNull(map) || map.isEmpty();
}
public static boolean isNotEmpty(Map map) {
return !isEmpty(map);
}
public static T first(T[] array) {
return isEmpty(array) ? null : array[0];
}
// ========== list map ==========
static List lists(Object... values) {
return isEmpty(values) ? new ArrayList() : new ArrayList(Arrays.asList(values));
}
public static Set sets() {
return new HashSet<>();
}
public static HashMap newHashMap() {
return new HashMap<>();
}
public static HashMap newLinkedHashMap() {
return new LinkedHashMap<>();
}
public static HashMap maps(Object... keysAndValues) {
return (HashMap) maps(newHashMap(), keysAndValues);
}
private static Map maps(Map result, Object... keysAndValues) {
if (isNotEmpty(keysAndValues)) {
for (int i = 0; i < keysAndValues.length; i += 2) {
if (keysAndValues.length > (i + 1)) {
result.put((K) keysAndValues[i], (V) keysAndValues[i + 1]);
}
}
}
return result;
}
// ========== method ==========
private static Object getMethod(Object obj, String method) {
if (isNotEmpty(method)) {
try {
return obj.getClass().getDeclaredMethod(method).invoke(obj);
} catch (IllegalAccessException | InvocationTargetException | NoSuchMethodException e) {
// ignore
}
try {
return obj.getClass().getMethod(method).invoke(obj);
} catch (IllegalAccessException | InvocationTargetException | NoSuchMethodException e1) {
// ignore
}
}
return null;
}
// ========== enum ==========
private static Object toEnum(Class> clazz, Object obj) {
if (isNotNull(clazz) && clazz.isEnum()) {
Object[] constants = clazz.getEnumConstants();
if (isNotEmpty(constants)) {
if (isNotEmpty(obj)) {
String source = obj.toString().trim();
for (Object em : constants) {
if (source.equalsIgnoreCase(((Enum) em).name())) {
return em;
}
Object code = getMethod(em, "getCode");
if (isNotNull(code) && source.equalsIgnoreCase(code.toString().trim())) {
return em;
}
Object value = getMethod(em, "getValue");
if (isNotNull(value) && source.equalsIgnoreCase(value.toString().trim())) {
return em;
}
}
}
return constants[0];
}
}
return null;
}
static String descInfo(Class> clazz, String desc) {
if (clazz.isArray()) {
clazz = clazz.getComponentType();
}
// enum append (code:value)
String enumInfo = collectEnumInfo(clazz);
if (isNotEmpty(enumInfo)) {
return isEmpty(desc) ? enumInfo : String.format("%s(%s)", desc, enumInfo);
} else {
return isEmpty(desc) ? ApiConst.EMPTY : desc;
}
}
private static String collectEnumInfo(Class> clazz) {
if (isNotNull(clazz) && clazz.isEnum()) {
Enum[] constants = (Enum[]) clazz.getEnumConstants();
if (isNotEmpty(constants)) {
StringBuilder sbd = new StringBuilder();
String split = ApiConst.SPLIT + ApiConst.SPACE;
// enum info, maybe Map or maybe List
Map map = newHashMap();
List list = lists();
for (Enum em : constants) {
// has getCode
Object code = getMethod(em, "getCode");
String name = em.name();
if (isNotEmpty(code)) {
String key = toStr(code);
Object value = getMethod(em, "getValue");
// has getValue return
// no getValue return
Object obj = isNotEmpty(value) ? value : name;
sbd.append(key).append(":").append(obj);
map.put(key, obj);
} else {
// no getCode return
// sbd.append(em.ordinal()).append(":");
sbd.append(name);
list.add(name);
}
sbd.append(split);
}
// just one rule, mix rule will use
ENUM_MAP.put(clazz.getSimpleName(), (isEmpty(map) ? list : map));
int len = split.length();
if (sbd.length() > len) {
return sbd.delete(sbd.length() - len, sbd.length()).toString();
}
}
}
return ApiConst.EMPTY;
}
public static Map allEnumInfo() {
return ENUM_MAP;
}
// ========== type ==========
static Class> getBasicType(String name) {
return BASIC_CLAZZ_MAP.get(name);
}
static boolean hasInDepth(String showDataType, Class> parameterType) {
if (!notShowByBasicType(showDataType)) {
return false;
}
if (basicType(parameterType)) {
return false;
}
return !MultipartFile.class.isAssignableFrom(parameterType)
&& !Collection.class.isAssignableFrom(parameterType)
&& !Map.class.isAssignableFrom(parameterType);
}
private static boolean notShowByBasicType(String dataType) {
if (isNotEmpty(dataType)) {
for (String key : BASIC_TYPE_VALUE_MAP.keySet()) {
if (key.equalsIgnoreCase(dataType)) {
return false;
}
}
}
return true;
}
private static Object getTypeDefaultValue(Class> clazz) {
return BASIC_TYPE_VALUE_MAP.get(clazz.getSimpleName());
}
static boolean basicType(Class> clazz) {
if (isNull(clazz)) {
return false;
}
if (isNotNull(getTypeDefaultValue(clazz))) {
return true;
}
// include enum
return clazz.isEnum();
}
static boolean notBasicType(Class> clazz) {
return !basicType(clazz);
}
static boolean innerType(Type type) {
if (type instanceof ParameterizedType) {
Type rawType = ((ParameterizedType) type).getRawType();
if (rawType instanceof Class>) {
Class> clazz = (Class>) rawType;
if (Collection.class.isAssignableFrom(clazz)) {
Type[] types = ((ParameterizedType) type).getActualTypeArguments();
return (types[0] instanceof Class) && notBasicType((Class>) types[0]);
} else if (Map.class.isAssignableFrom(clazz)) {
Type[] types = ((ParameterizedType) type).getActualTypeArguments();
if ((types[0] instanceof Class) && notBasicType((Class>) types[0])) {
return true;
}
return (types[1] instanceof Class) && notBasicType((Class>) types[1]);
} else {
return true;
}
}
}
return false;
}
static boolean innerType(Class> clazz) {
if (basicType(clazz)) {
return false;
}
if (clazz == Object.class) {
return true;
}
List fieldList = new ArrayList<>();
fieldList.addAll(Arrays.asList(clazz.getFields()));
fieldList.addAll(Arrays.asList(clazz.getDeclaredFields()));
for (Field field : fieldList) {
Class> fieldType = field.getType();
if (notBasicType(fieldType)) {
if (Collection.class.isAssignableFrom(fieldType)) {
Type[] types = ((ParameterizedType) field.getGenericType()).getActualTypeArguments();
if ((types[0] instanceof Class) && notBasicType((Class>) types[0])) {
return true;
}
} else if (Map.class.isAssignableFrom(fieldType)) {
Type[] types = ((ParameterizedType) field.getGenericType()).getActualTypeArguments();
if ((types[0] instanceof Class) && notBasicType((Class>) types[0])) {
return true;
}
if ((types[1] instanceof Class) && notBasicType((Class>) types[1])) {
return true;
}
} else {
return true;
}
}
}
return false;
}
static Object mapKeyDefault(Class> clazz) {
Object keyDefault = DEFAULT_MAP_KEY.get(clazz.getSimpleName());
if (isNotEmpty(keyDefault)) {
return keyDefault;
} else if (clazz.isEnum()) {
return first(clazz.getEnumConstants());
} else {
return null;
}
}
static boolean hasFileInput(String fileType) {
return ApiConst.FILE_TYPE.equals(fileType);
}
static String getInputType(Class> type) {
if (isNull(type)) {
return ApiConst.EMPTY;
}
if (type.isArray()) {
return getType(type.getComponentType()) + "[]";
} else {
return getType(type);
}
}
private static String getType(Class> type) {
// upload file
if (MultipartFile.class.isAssignableFrom(type)) {
return ApiConst.FILE_TYPE;
}
String paramType = type.getSimpleName();
Class> basicClass = getBasicType(paramType);
if (isNotEmpty(basicClass)) {
return basicClass.getSimpleName();
} else if (type.isEnum()) {
return "Enum(" + paramType + ")";
} else {
// String, String[], List, Set, Map... etc
return paramType;
}
}
static Object getReturnType(Class> clazz) {
if (isNull(clazz)) {
return null;
}
Object defaultValue = getTypeDefaultValue(clazz);
if (isNotNull(defaultValue)) {
return defaultValue;
} else if (clazz.isEnum()) {
// Enum return first
return first(clazz.getEnumConstants());
} else {
return null;
}
}
private static final List TRUE_LIST = Arrays.asList("true", "on", "yes", "1", "✓", "✔", "☑");
static Object getReturnTypeExample(Class> clazz, String example) {
if (isNull(clazz)) {
return null;
}
if (clazz.isEnum()) {
return toEnum(clazz, example);
}
Object defaultObj = getTypeDefaultValue(clazz);
if (isNull(example)) {
return defaultObj;
}
if (clazz == String.class) {
return isEmpty(example) ? defaultObj.toString() : example;
}
else if (clazz == boolean.class || clazz == Boolean.class) {
return TRUE_LIST.contains(example.trim().toLowerCase());
}
else if (clazz == byte.class || clazz == Byte.class) {
try {
return isHexNumber(example) ? Byte.decode(example) : Byte.valueOf(example);
} catch (NumberFormatException e) {
return defaultObj;
}
}
else if (clazz == char.class || clazz == Character.class) {
try {
return example.charAt(0);
} catch (NumberFormatException e) {
return defaultObj;
}
}
else if (clazz == short.class || clazz == Short.class) {
try {
return isHexNumber(example) ? Short.decode(example) : Short.valueOf(example);
} catch (NumberFormatException e) {
return defaultObj;
}
}
else if (clazz == int.class || clazz == Integer.class) {
try {
return isHexNumber(example) ? Integer.decode(example) : Integer.valueOf(example);
} catch (NumberFormatException e) {
return defaultObj;
}
}
else if (clazz == long.class || clazz == Long.class) {
try {
return isHexNumber(example) ? Long.decode(example) : Long.valueOf(example);
} catch (NumberFormatException e) {
return defaultObj;
}
}
else if (clazz == float.class || clazz == Float.class) {
try {
return Float.valueOf(example);
} catch (NumberFormatException e) {
return defaultObj;
}
}
else if (clazz == double.class || clazz == Double.class) {
try {
return Double.valueOf(example);
} catch (NumberFormatException e) {
return defaultObj;
}
}
else if (clazz == Date.class) {
return Tools.parseDate(example);
}
else if (clazz == BigInteger.class) {
try {
return isHexNumber(example) ? decodeBigInteger(example) : new BigInteger(example);
} catch (NumberFormatException e) {
return defaultObj;
}
}
else if (clazz == BigDecimal.class) {
try {
return new BigDecimal(example);
} catch (NumberFormatException e) {
return defaultObj;
}
}
// up type, down array type
else if (clazz == String[].class) {
String str = isEmpty(example) ? defaultObj.toString() : example;
return new String[] { str };
}
else if (clazz == boolean[].class) {
return new boolean[] { TRUE_LIST.contains(example.trim().toLowerCase()) };
} else if (clazz == Boolean[].class) {
return new Boolean[] { TRUE_LIST.contains(example.trim().toLowerCase()) };
}
else if (clazz == byte[].class) {
try {
return new byte[] { isHexNumber(example) ? Byte.decode(example) : Byte.valueOf(example) };
} catch (NumberFormatException e) {
return defaultObj;
}
} else if (clazz == Byte[].class) {
try {
return new Byte[] { isHexNumber(example) ? Byte.decode(example) : Byte.valueOf(example) };
} catch (NumberFormatException e) {
return defaultObj;
}
}
else if (clazz == char[].class) {
try {
return new char[] { example.charAt(0) };
} catch (NumberFormatException e) {
return defaultObj;
}
} else if (clazz == Character[].class) {
try {
return new Character[] { example.charAt(0) };
} catch (NumberFormatException e) {
return defaultObj;
}
}
else if (clazz == short[].class) {
try {
return new short[] { isHexNumber(example) ? Short.decode(example) : Short.valueOf(example) };
} catch (NumberFormatException e) {
return defaultObj;
}
} else if (clazz == Short[].class) {
try {
return new Short[] { isHexNumber(example) ? Short.decode(example) : Short.valueOf(example) };
} catch (NumberFormatException e) {
return defaultObj;
}
}
else if (clazz == int[].class) {
try {
return new int[] { isHexNumber(example) ? Integer.decode(example) : Integer.valueOf(example) };
} catch (NumberFormatException e) {
return defaultObj;
}
} else if (clazz == Integer[].class) {
try {
return new Integer[] { isHexNumber(example) ? Integer.decode(example) : Integer.valueOf(example) };
} catch (NumberFormatException e) {
return defaultObj;
}
}
else if (clazz == long[].class) {
try {
return new long[] { isHexNumber(example) ? Long.decode(example) : Long.valueOf(example) };
} catch (NumberFormatException e) {
return defaultObj;
}
} else if (clazz == Long[].class) {
try {
return new Long[] { isHexNumber(example) ? Long.decode(example) : Long.valueOf(example) };
} catch (NumberFormatException e) {
return defaultObj;
}
}
else if (clazz == float[].class) {
try {
return new float[] { Float.parseFloat(example) };
} catch (NumberFormatException e) {
return defaultObj;
}
} else if (clazz == Float[].class) {
try {
return new Float[] { Float.valueOf(example) };
} catch (NumberFormatException e) {
return defaultObj;
}
}
else if (clazz == double[].class) {
try {
return new double[] { Double.parseDouble(example) };
} catch (NumberFormatException e) {
return defaultObj;
}
} else if (clazz == Double[].class) {
try {
return new Double[] { Double.valueOf(example) };
} catch (NumberFormatException e) {
return defaultObj;
}
}
else if (clazz == Date[].class) {
return new Date[] { Tools.parseDate(example) };
}
else if (clazz == BigInteger[].class) {
try {
return new BigInteger[] { isHexNumber(example) ? decodeBigInteger(example) : new BigInteger(example) };
} catch (NumberFormatException e) {
return defaultObj;
}
}
else if (clazz == BigDecimal[].class) {
try {
return new BigDecimal[] { new BigDecimal(example) };
} catch (NumberFormatException e) {
return defaultObj;
}
}
else {
return defaultObj;
}
}
private static boolean isHexNumber(String value) {
int index = value.startsWith("-") ? 1 : 0;
return value.startsWith("0x", index) || value.startsWith("0X", index) || value.startsWith("#", index);
}
private static BigInteger decodeBigInteger(String value) {
int radix;
int index = 0;
boolean negative;
if (value.startsWith("-")) {
negative = true;
index++;
} else {
negative = false;
}
if (value.startsWith("0x", index) || value.startsWith("0X", index)) {
index += 2;
radix = 16;
} else if (value.startsWith("#", index)) {
index++;
radix = 16;
} else if (value.startsWith("0", index) && value.length() > 1 + index) {
index++;
radix = 8;
} else {
radix = 10;
}
BigInteger result = new BigInteger(value.substring(index), radix);
return (negative ? result.negate() : result);
}
public static String escape(String str) {
if (isNotNull(str)) {
Map map = maps(
"\"", """, // """,
"'", "'", // "'",
"&", "&", // "&",
"<", "<", // "<",
">", ">" // ">"
);
for (Map.Entry entry : map.entrySet()) {
str = str.replace(entry.getKey(), entry.getValue());
}
}
return str;
}
}