blob: cdb529365315546434279e10a0add76542392460 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.rocketmq.streams.common.utils;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.math.BigDecimal;
import java.sql.Timestamp;
import java.sql.Types;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.apache.rocketmq.streams.common.configurable.IConfigurable;
import org.apache.rocketmq.streams.common.datatype.ArrayDataType;
import org.apache.rocketmq.streams.common.datatype.BaseDataType;
import org.apache.rocketmq.streams.common.datatype.BooleanDataType;
import org.apache.rocketmq.streams.common.datatype.ByteDataType;
import org.apache.rocketmq.streams.common.datatype.ConfigurableDataType;
import org.apache.rocketmq.streams.common.datatype.DataType;
import org.apache.rocketmq.streams.common.datatype.DateDataType;
import org.apache.rocketmq.streams.common.datatype.DateTimeDataType;
import org.apache.rocketmq.streams.common.datatype.DoubleDataType;
import org.apache.rocketmq.streams.common.datatype.FloatDataType;
import org.apache.rocketmq.streams.common.datatype.GenericParameterDataType;
import org.apache.rocketmq.streams.common.datatype.HllDataType;
import org.apache.rocketmq.streams.common.datatype.IJsonable;
import org.apache.rocketmq.streams.common.datatype.IntDataType;
import org.apache.rocketmq.streams.common.datatype.JavaBeanDataType;
import org.apache.rocketmq.streams.common.datatype.JsonableDataType;
import org.apache.rocketmq.streams.common.datatype.ListDataType;
import org.apache.rocketmq.streams.common.datatype.LongDataType;
import org.apache.rocketmq.streams.common.datatype.MapDataType;
import org.apache.rocketmq.streams.common.datatype.NotSupportDataType;
import org.apache.rocketmq.streams.common.datatype.NumberDataType;
import org.apache.rocketmq.streams.common.datatype.SerializableDataType;
import org.apache.rocketmq.streams.common.datatype.SetDataType;
import org.apache.rocketmq.streams.common.datatype.ShortDataType;
import org.apache.rocketmq.streams.common.datatype.StringDataType;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@SuppressWarnings("rawtypes")
public class DataTypeUtil {
private static final Logger LOG = LoggerFactory.getLogger(DataTypeUtil.class);
private static final List<DataType> dataTypes = new ArrayList<>();
/**
* 基础类型的名字映射
*/
private static final Map<String, DataType> baseTypeDataTypeMap = new HashMap<>();
private static final Map<Class, DataType> class2DataTypeMap = new HashMap<>();
private static final Map<String, DataType> dbType2DataTypeMap = new HashMap<>();
private static final Map<Integer, DataType> typeCode2DataType = new HashMap<>();
static {
register(new HllDataType());
register(new StringDataType());
register(new IntDataType());
register(new LongDataType());
register(new BooleanDataType());
register(new DateDataType());
register(new DoubleDataType());
register(new FloatDataType());
register(new ByteDataType());
register(new ShortDataType());
register(new NumberDataType());
register(new ListDataType());
register(new SetDataType());
register(new ArrayDataType());
register(new MapDataType());
register(new ConfigurableDataType());
register(new JsonableDataType());
register(new DateTimeDataType());
register(new JavaBeanDataType());
register(new SerializableDataType());
register(new NotSupportDataType());
}
public static void register(DataType dataType) {
dataTypes.add(dataType);
/*
对于class是固定的直接放到map中,对于变化的放到dataTypes列表中,可以减少循环次数
*/
baseTypeDataTypeMap.put(dataType.getDataTypeName(), dataType);
if (dataType instanceof BaseDataType) {
BaseDataType baseDataType = (BaseDataType) dataType;
Class[] classes = baseDataType.getSupportClasses();
if (classes != null) {
for (Class c : classes) {
class2DataTypeMap.put(c, dataType);
}
}
}
switch (dataType.getDataTypeName()) {
case "string": {
dbType2DataTypeMap.put("VARCHAR", dataType);
typeCode2DataType.put(Types.VARCHAR, dataType);
break;
}
case "int": {
dbType2DataTypeMap.put("INTEGER", dataType);
typeCode2DataType.put(Types.INTEGER, dataType);
break;
}
case "long": {
dbType2DataTypeMap.put("BIGINT", dataType);
dbType2DataTypeMap.put("BIGINT UNSIGNED", dataType);
typeCode2DataType.put(Types.BIGINT, dataType);
break;
}
case "boolean": {
dbType2DataTypeMap.put("BOOLEAN", dataType);
typeCode2DataType.put(Types.BOOLEAN, dataType);
break;
}
case "Date": {
dbType2DataTypeMap.put("DATE", dataType);
typeCode2DataType.put(Types.DATE, dataType);
break;
}
case "double": {
dbType2DataTypeMap.put("DOUBLE", dataType);
typeCode2DataType.put(Types.DOUBLE, dataType);
break;
}
case "float": {
dbType2DataTypeMap.put("FLOAT", dataType);
typeCode2DataType.put(Types.FLOAT, dataType);
break;
}
case "short": {
dbType2DataTypeMap.put("SMALLINT", dataType);
typeCode2DataType.put(Types.SMALLINT, dataType);
break;
}
case "array": {
dbType2DataTypeMap.put("ARRAY", dataType);
break;
}
case "datetime": {
dbType2DataTypeMap.put("DATETIME", dataType);
break;
}
}
}
/**
* 通过class获取datatype
*
* @param clazz 类
* @return DataType
*/
public static DataType getDataTypeFromClass(Class clazz) {
DataType type = class2DataTypeMap.get(clazz);
if (type != null) {
return type;
}
for (DataType dataType : dataTypes) {
if (dataType.matchClass(clazz)) {
DataType dataType1 = dataType.create();
dataType1.setDataClazz(clazz);
return dataType1;
}
}
return null;
}
/**
* 通过datatype name获取datatype
*
* @param dataTypeName dataType 名称
* @return DataType
*/
public static DataType getDataType(String dataTypeName) {
return baseTypeDataTypeMap.get(dataTypeName);
}
/**
* 把序列化后的datatype还原为datatype
*
* @param dataTypeJson dataType JSON 信息
* @return DataType
*/
public static DataType createDataType(String dataTypeJson) {
JSONObject jsonObject = JSON.parseObject(dataTypeJson);
String className = jsonObject.getString(DataType.DATA_TYPE_CLASS_NAME);
Class clazz = null;
try {
clazz = Class.forName(className);
DataType dataType = getDataTypeFromClass(clazz);
if (dataType != null) {
dataType.toObject(dataTypeJson);
}
return dataType;
} catch (ClassNotFoundException e) {
LOG.error("create dataType error. the detail is " + dataTypeJson);
throw new RuntimeException("class not find " + className, e);
}
}
public static DataType createDataTypeByDbType(String dbType) {
return dbType2DataTypeMap.get(dbType);
}
public static DataType createDataTypeByDbType(int dbType) {
return typeCode2DataType.get(dbType);
}
/**
* 根据类和范型的名称创建DataType,
*
* @param clazz 类
* @param genericParameter 范型内容为java.util.Map<String,List<String>,包含类自身的类名
* @return DataType
*/
public static DataType createDataType(Class clazz, String genericParameter) {
DataType dataType = getDataTypeFromClass(clazz);
if (GenericParameterDataType.class.isInstance(dataType)) {
GenericParameterDataType genericParamterDataType = (GenericParameterDataType) dataType;
genericParamterDataType.parseGenericParameter(genericParameter);
}
return dataType;
}
public static boolean matchClass(Class<?>[] parameterTypes, Class[] classes) {
if (parameterTypes == null && classes == null) {
return true;
}
if (parameterTypes == null) {
return false;
}
if (classes == null) {
return false;
}
if (parameterTypes.length != classes.length) {
return false;
}
for (int i = 0; i < parameterTypes.length; i++) {
Class parameterType = parameterTypes[i];
DataType dataType = DataTypeUtil.getDataTypeFromClass(parameterType);
if (dataType != null && !dataType.matchClass(classes[i])) {
return false;
}
}
return true;
}
/**
* 根据类和范型的名称创建DataType,
*
* @param genericParameter 泛型参数
* @param genericParameter 范型内容为java.util.Map<String,List<String>,包含类自身的类名
* @return DataType
*/
public static DataType createDataTypeByGenericClass(String genericParameter) {
try {
String className = genericParameter;
int classNameIndex = genericParameter.indexOf("<");
if (classNameIndex != -1) {
className = genericParameter.substring(0, classNameIndex);
}
Class clazz = Class.forName(className);
return createDataType(clazz, genericParameter);
} catch (Exception e) {
LOG.error("create dataType error. the detail is " + genericParameter);
throw new RuntimeException("createDataTypeByGenericClass error " + genericParameter);
}
}
/**
* 根据类和范型的名称创建DataType,
*
* @param clazz 类
* @param genericParameter 范型内容为java.util.Map<String,List<String>,包含类自身的类名
* @param lazyCheck 当不发现不支持的类型的时候,不直接抛错,在后续使用的时候抛出。在某种场景下创建的类型可能不会被使用
* @return DataType
*/
@Deprecated
public static DataType createDataType(Class clazz, String genericParameter, boolean lazyCheck) {
DataType dataType = createDataType(clazz, genericParameter);
if (dataType != null) {
return dataType;
}
if (lazyCheck) {
return new NotSupportDataType(clazz);
} else {
throw new RuntimeException(
"can not support data type " + clazz + " , genericParameterType:" + genericParameter.toString());
}
}
/**
* 对一个方法的参数做datatype转化
*
* @param method 方法
* @return DataType
*/
public static DataType[] createDataType(Method method) {
Type[] types = method.getGenericParameterTypes();
Class[] classes = method.getParameterTypes();
DataType[] dataTypes = new DataType[classes.length];
for (int i = 0; i < classes.length; i++) {
String typeString = types[i].toString();
if (typeString.startsWith("class [L")) {
typeString = typeString.replace("class [L", "").replace(";", "");
if (!typeString.endsWith("[]")) {
typeString += "[]";
}
} else if (typeString.startsWith("class ")) {
typeString = null;
}
DataType dataType = createDataType(classes[i], typeString);
dataTypes[i] = dataType;
}
return dataTypes;
}
/**
* 创建某个对象的字段对应的datatype,字段必须有get方法,否则会抛错
*
* @param object 实例
* @param fieldName 字段名称
* @return DataType
*/
public static DataType createFieldDataType(Object object, String fieldName) {
Class clazz = object.getClass();
return createFieldDataType(clazz, fieldName);
}
/**
* 创建某个对象的字段对应的datatype,字段必须有get方法,否则会抛错
*
* @param clazz 类
* @param fieldName 字段名称
* @return DataType
*/
public static DataType createFieldDataType(Class clazz, String fieldName) {
Method method = ReflectUtil.getGetMethod(clazz, fieldName);
Type type = null;
String typeString = null;
if (method == null) {
try {
Field field = clazz.getDeclaredField(fieldName);
type = field.getType();
} catch (NoSuchFieldException e) {
throw new RuntimeException(clazz.getName() + "." + fieldName + " not exist get method, please create get/set method for the field");
}
} else {
type = method.getGenericReturnType();
typeString = type.toString();
if (typeString.startsWith("class ")) {
typeString = null;
}
}
return createDataType(ReflectUtil.getBeanFieldType(clazz, fieldName), typeString);
}
public static String convertGenericParameterString(String type) {
if (type == null) {
return null;
}
String typeString = type;
if (typeString.startsWith("class ")) {
typeString = null;
}
return typeString;
}
public static String convertGenericParameterString(Type type) {
if (type == null) {
return null;
}
return convertGenericParameterString(type.toString());
}
public static boolean isJsonAble(Class clazz) {
DataType dataType = getDataTypeFromClass(IJsonable.class);
return dataType != null && dataType.matchClass(clazz);
}
public static boolean isNumber(Class clazz) {
return isInt(clazz) || isLong(clazz) || isDouble(clazz) || isFloat(clazz);
}
public static boolean isNumber(DataType dataType) {
return dataType instanceof DoubleDataType || dataType instanceof IntDataType || dataType instanceof LongDataType || dataType instanceof FloatDataType;
}
public static boolean isDate(Class clazz) {
DataType dataType = getDataTypeFromClass(Date.class);
return dataType != null && dataType.matchClass(clazz);
}
public static boolean isByte(Class clazz) {
DataType dataType = getDataTypeFromClass(Byte.class);
return dataType != null && dataType.matchClass(clazz);
}
public static boolean isShort(Class clazz) {
DataType dataType = getDataTypeFromClass(Short.class);
return dataType != null && dataType.matchClass(clazz);
}
public static boolean isTimestamp(Class clazz) {
DataType dataType = getDataTypeFromClass(Timestamp.class);
return dataType != null && dataType.matchClass(clazz);
}
public static boolean isInt(Class clazz) {
DataType dataType = getDataTypeFromClass(Integer.class);
return dataType != null && dataType.matchClass(clazz);
}
public static boolean isLong(Class clazz) {
DataType dataType = getDataTypeFromClass(Long.class);
return dataType != null && dataType.matchClass(clazz);
}
public static boolean isDouble(Class clazz) {
DataType dataType = getDataTypeFromClass(Double.class);
return dataType != null && dataType.matchClass(clazz);
}
public static boolean isFloat(Class clazz) {
DataType dataType = getDataTypeFromClass(Float.class);
return dataType != null && dataType.matchClass(clazz);
}
public static boolean isString(Class clazz) {
DataType dataType = getDataTypeFromClass(String.class);
return dataType != null && dataType.matchClass(clazz);
}
public static boolean isBigDecimal(Class clazz) {
DataType dataType = getDataTypeFromClass(BigDecimal.class);
return dataType != null && dataType.matchClass(clazz);
}
public static boolean isBoolean(Class clazz) {
DataType dataType = getDataTypeFromClass(Boolean.class);
return dataType != null && dataType.matchClass(clazz);
}
public static boolean isArray(Class clazz) {
return clazz.isArray();
}
public static boolean isJavaBean(DataType dataType) {
return JavaBeanDataType.class.isInstance(dataType);
}
public static boolean isJavaBean(Class clazz) {
JavaBeanDataType javaBeanDataType = new JavaBeanDataType();
return javaBeanDataType != null && javaBeanDataType.matchClass(clazz);
}
public static boolean isList(Class clazz) {
DataType dataType = getDataTypeFromClass(List.class);
return dataType != null && dataType.matchClass(clazz);
}
public static boolean isMap(Class clazz) {
DataType dataType = getDataTypeFromClass(Map.class);
return dataType != null && dataType.matchClass(clazz);
}
public static boolean isConfigurable(Class clazz) {
DataType dataType = getDataTypeFromClass(IConfigurable.class);
return dataType != null && dataType.matchClass(clazz);
}
/**
* 获取包装类型的基本类型
*
* @param o 实例
* @return 实例
*/
@Deprecated
public static Object getBaseType(Object o) {
if (o == null) {
return null;
}
Class c = o.getClass();
if (isInt(c)) {
return o;
} else if (isLong(c)) {
return o;
} else if (isDouble(c)) {
return o;
} else if (isFloat(c)) {
return o;
} else if (isBoolean(c)) {
return o;
} else if (isDate(c)) {
return o;
} else if (isString(c)) {
return o;
} else if (isBigDecimal(c)) {
return o;
} else if (isByte(c)) {
return o;
} else if (isShort(c)) {
return o;
} else if (isTimestamp(c)) {
return o;
}
return o;
}
public static boolean isBoolean(DataType dataType) {
return dataType instanceof BooleanDataType;
}
public static boolean isDate(DataType dataType) {
return dataType instanceof DateDataType;
}
public static void main(String[] args) {
BooleanDataType booleanDataType = new BooleanDataType();
boolean result = DataTypeUtil.isDate(booleanDataType);
System.out.println(Map.class.getSimpleName());
}
public static boolean isString(DataType dataType) {
return dataType instanceof StringDataType;
}
/**
* Gets the Datatype based on the fields of the class
*
* @param field
* @return
*/
public static DataType createDataTypeByField(Object object, Field field) {
return createDataTypeByFieldFromClass(object.getClass(), field);
}
/**
* Gets the Datatype based on the fields of the class
*
* @param field
* @return
*/
public static DataType createDataTypeByFieldFromClass(Class cal, Field field) {
Class clazz = field.getType();
Method method = null;
try {
method = ReflectUtil.getGetMethod(cal, field.getName());
} catch (Exception e) {
//todo nothing,if not has get/is method, use fieldDirectly
}
if (method != null) {
clazz = method.getReturnType();
}
DataType dataType = DataTypeUtil.getDataTypeFromClass(clazz);
String genericTypeStr = null;
if (field.getGenericType() != null) {
genericTypeStr = field.getGenericType().toString();
}
if (NotSupportDataType.class.isInstance(dataType)) {
Class fieldClass = ReflectUtil.getBeanFieldType(cal, field.getName());
dataType = DataTypeUtil.getDataTypeFromClass(fieldClass);
if (genericTypeStr != null) {
int startIndex = genericTypeStr.indexOf("<");
if (startIndex > -1) {
genericTypeStr = dataType.getDataClass().getName() + genericTypeStr.substring(startIndex);
}
}
}
if (NotSupportDataType.class.isInstance(dataType)) {
return null;
}
ReflectUtil.setDataTypeParadigmType(dataType, genericTypeStr, ParameterizedType.class.isInstance(field.getGenericType()));
return dataType;
}
}