com.aiwiown.face.internal.mapping.Converters Maven / Gradle / Ivy
package com.aiwiown.face.internal.mapping;
import com.aiwiown.face.ApiConstants;
import com.aiwiown.face.ApiException;
import com.aiwiown.face.ApiResponse;
import com.aiwiown.face.internal.util.StringUtils;
import java.beans.BeanInfo;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
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.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* 转换工具类。
*
* @author carver.gu
* @since 1.0, Apr 11, 2010
*/
public class Converters {
private static Pattern pattern = Pattern.compile("(\\\\u(\\p{XDigit}{4}))");
// 是否对JSON返回的数据类型进行校验,默认不校验。给内部测试JSON返回时用的开关。
//规则:返回的"基本"类型只有String,Long,Boolean,Date,采取严格校验方式,如果类型不匹配,报错
public static boolean isCheckJsonType = false;
private static final Set baseFields = new HashSet();
private static final Set excludeFields = new HashSet();
/**
* 被子类覆盖的属性
*/
private static final Set overideFields = new HashSet();
static {
baseFields.add("error");
baseFields.add("body");
baseFields.add("params");
baseFields.add("timeUsed");
baseFields.add("requestId");
baseFields.add("errorMessage");
baseFields.add("paramsByteArr");
}
static {
/**
* lite gettoken 和app-gettbiztoken不是同期的产品,所以error这块略有不同。
* lite gettoken 错误信息会返回到error上
* app-gettbiztoken 错误信息会返回到 error_message
* 不需要过滤 errorMessage ,否则会导致解析错误
*/
// excludeFields.add("errorMessage");
excludeFields.add("code");
excludeFields.add("message");
}
static {
overideFields.add("code");
overideFields.add("msg");
}
private Converters() {
}
/**
* 使用指定 的读取器去转换字符串为对象。
*
* @param 领域泛型
* @param clazz 领域类型
* @param reader 读取器
* @return 领域对象
* @throws ApiException
*/
public static T convert(Class clazz, Reader reader) throws ApiException {
T rsp = null;
try {
rsp = clazz.newInstance();
BeanInfo beanInfo = Introspector.getBeanInfo(clazz);
PropertyDescriptor[] pds = beanInfo.getPropertyDescriptors();
boolean isResponseClazz = ApiResponse.class.isAssignableFrom(clazz);
for (PropertyDescriptor pd : pds) {
Method writeMethod = pd.getWriteMethod();
if (writeMethod == null) {
continue;
}
String itemName = pd.getName();
String listName = null;
// 之前errorCode的属性要剔除掉
if (isResponseClazz && excludeFields.contains(itemName)) {
continue;
}
List faceFieldMethods = new ArrayList();
if (baseFields.contains(itemName) && isResponseClazz) {
Field field = ApiResponse.class.getDeclaredField(itemName);
ApiMethod faceFieldMethod = new ApiMethod();
faceFieldMethod.setField(field);
// writeMethod属于父类,则直接使用
if (writeMethod.getDeclaringClass().getName().contains("ApiResponse")) {
faceFieldMethod.setMethod(writeMethod);
} else {
// 否则从父类再取一次
writeMethod = tryGetSetMethod(ApiResponse.class, field,
writeMethod.getName());
if (writeMethod == null) {
continue;
}
faceFieldMethod.setMethod(writeMethod);
}
faceFieldMethods.add(faceFieldMethod);
// 如果被子类覆盖的,则从尝试从子类中获取
if (overideFields.contains(itemName)) {
field = tryGetFieldWithoutExp(clazz, itemName);
// 属性存在则需要重新从子类获取访问方法
if (field != null) {
writeMethod = tryGetSetMethod(clazz, field, writeMethod.getName());
if (writeMethod == null) {
continue;
}
faceFieldMethod = new ApiMethod();
faceFieldMethod.setField(field);
faceFieldMethod.setMethod(writeMethod);
faceFieldMethods.add(faceFieldMethod);
}
}
} else {
Field field = clazz.getDeclaredField(itemName);
ApiMethod faceFieldMethod = new ApiMethod();
faceFieldMethod.setField(field);
faceFieldMethod.setMethod(writeMethod);
faceFieldMethods.add(faceFieldMethod);
}
// 迭代设置属性
for (ApiMethod faceFieldMethod : faceFieldMethods) {
Field field = faceFieldMethod.getField();
Method method = faceFieldMethod.getMethod();
ApiField jsonField = field.getAnnotation(ApiField.class);
if (jsonField != null) {
itemName = jsonField.value();
}
ApiListField jsonListField = field.getAnnotation(ApiListField.class);
if (jsonListField != null) {
listName = jsonListField.value();
}
if (!reader.hasReturnField(itemName)) {
if (listName == null || !reader.hasReturnField(listName)) {
continue; // ignore non-return field
}
}
Class> typeClass = field.getType();
if (String.class.isAssignableFrom(typeClass)) {
Object value = reader.getPrimitiveObject(itemName);
if (value instanceof String) {
method.invoke(rsp, value.toString());
} else {
if (isCheckJsonType && value != null) {
throw new ApiException(itemName + " is not a String");
}
if (value != null) {
method.invoke(rsp, value.toString());
} else {
method.invoke(rsp, "");
}
}
} else if (Long.class.isAssignableFrom(typeClass)) {
Object value = reader.getPrimitiveObject(itemName);
if (value instanceof Long) {
method.invoke(rsp, (Long) value);
} else {
if (isCheckJsonType && value != null) {
throw new ApiException(itemName + " is not a Number(Long)");
}
if (StringUtils.isNumeric(value)) {
method.invoke(rsp, Long.valueOf(value.toString()));
}
}
} else if (Integer.class.isAssignableFrom(typeClass)) {
Object value = reader.getPrimitiveObject(itemName);
if (value instanceof Integer) {
method.invoke(rsp, (Integer) value);
} else {
if (isCheckJsonType && value != null) {
throw new ApiException(itemName + " is not a Number(Integer)");
}
if (StringUtils.isNumeric(value)) {
method.invoke(rsp, Integer.valueOf(value.toString()));
}
}
} else if (Boolean.class.isAssignableFrom(typeClass)) {
Object value = reader.getPrimitiveObject(itemName);
if (value instanceof Boolean) {
method.invoke(rsp, (Boolean) value);
} else {
if (isCheckJsonType && value != null) {
throw new ApiException(itemName + " is not a Boolean");
}
if (value != null) {
method.invoke(rsp, Boolean.valueOf(value.toString()));
}
}
} else if (Double.class.isAssignableFrom(typeClass)) {
Object value = reader.getPrimitiveObject(itemName);
if (value instanceof Double) {
method.invoke(rsp, (Double) value);
} else {
if (isCheckJsonType && value != null) {
throw new ApiException(itemName + " is not a Double");
}
}
} else if (Number.class.isAssignableFrom(typeClass)) {
Object value = reader.getPrimitiveObject(itemName);
if (value instanceof Number) {
if (BigDecimal.class.isAssignableFrom(typeClass)) {
method.invoke(rsp, new BigDecimal(String.valueOf(value)));
} else {
method.invoke(rsp, (Number) value);
}
} else {
if (isCheckJsonType && value != null) {
throw new ApiException(itemName + " is not a Number");
}
}
} else if (Date.class.isAssignableFrom(typeClass)) {
DateFormat format = new SimpleDateFormat(ApiConstants.DATE_TIME_FORMAT);
format.setTimeZone(TimeZone.getTimeZone(ApiConstants.DATE_TIMEZONE));
Object value = reader.getPrimitiveObject(itemName);
if (value instanceof String) {
method.invoke(rsp, format.parse(value.toString()));
}
} else if (List.class.isAssignableFrom(typeClass)) {
Type fieldType = field.getGenericType();
if (fieldType instanceof ParameterizedType) {
ParameterizedType paramType = (ParameterizedType) fieldType;
Type[] genericTypes = paramType.getActualTypeArguments();
if (genericTypes != null && genericTypes.length > 0) {
if (genericTypes[0] instanceof Class>) {
Class> subType = (Class>) genericTypes[0];
List> listObjs = reader.getListObjects(listName, itemName,
subType);
if (listObjs != null) {
method.invoke(rsp, listObjs);
}
}
}
}
} else {
Object obj = reader.getObject(itemName, typeClass);
if (obj != null) {
method.invoke(rsp, obj);
}
}
}
}
} catch (Exception e) {
throw new ApiException(e);
}
return rsp;
}
/**
* 尝试获取属性
*
* 不会抛出异常,不存在则返回null
*
* @param clazz
* @param itemName
* @return
*/
private static Field tryGetFieldWithoutExp(Class> clazz, String itemName) {
try {
return clazz.getDeclaredField(itemName);
} catch (Exception e) {
return null;
}
}
/**
* 获取属性设置属性
*
* @param clazz
* @param field
* @return
*/
private static Method tryGetSetMethod(Class clazz, Field field, String methodName) {
try {
return clazz.getDeclaredMethod(methodName, field.getType());
} catch (Exception e) {
return null;
}
}
/**
* unicode编码转换为汉字
*
* @param unicodeStr 待转化的编码
* @return 返回转化后的汉子
*/
public static String UnicodeToCN(String unicodeStr) {
Matcher matcher = pattern.matcher(unicodeStr);
char ch;
while (matcher.find()) {
//group
String group = matcher.group(2);
//ch:'李四'
ch = (char) Integer.parseInt(group, 16);
//group1
String group1 = matcher.group(1);
unicodeStr = unicodeStr.replace(group1, ch + "");
}
return unicodeStr.replace("\\", "").trim();
}
}