com.gitee.qdbp.staticize.parse.AttrSetter Maven / Gradle / Ivy
package com.gitee.qdbp.staticize.parse;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import com.gitee.qdbp.able.beans.KeyValue;
import com.gitee.qdbp.staticize.annotation.AttrRequired;
import com.gitee.qdbp.staticize.annotation.DynamicAttrSupport;
import com.gitee.qdbp.staticize.annotation.TryEvalString;
import com.gitee.qdbp.staticize.exception.TagException;
import com.gitee.qdbp.staticize.tags.base.ITag;
import com.gitee.qdbp.tools.utils.ConvertTools;
import com.gitee.qdbp.tools.utils.VerifyTools;
/**
* 属性Setter方法调用工具类
*
* @author zhaohuihua
* @version 20200929
*/
public class AttrSetter {
private static final String SET = "set";
/** 单实例 **/
public static final AttrSetter instance = new AttrSetter();
public void setAttrValue(ITag tag, String attrName, Object attrValue) {
MethodInfo methodInfo = getMethodInfo(tag.getClass(), attrName);
if (methodInfo == null) {
return;
}
Object realValue = attrValue == null ? null : doConvertAttrValue(methodInfo, attrName, attrValue);
if (realValue == null) {
if (methodInfo.required) {
String msg = String.format("Missing a required attribute '%s'.", attrName);
throw new TagException(msg);
}
} else {
// 参数值与目标类型不符
// 有可能是根据表达式从上下文动态获取到的对象
if (!methodInfo.paramType.isAssignableFrom(realValue.getClass())) {
String src = realValue.getClass().getSimpleName();
String dest = methodInfo.paramType.getSimpleName();
String msg = String.format("Attribute %s(%s) not of type '%s'.", attrName, src, dest);
throw new TagException(msg);
}
}
try {
methodInfo.setterMethod.invoke(tag, realValue);
} catch (Exception e) {
Throwable cause = e.getCause();
if (e instanceof TagException) {
throw (TagException) e;
} else if (cause instanceof TagException) {
throw (TagException) cause;
} else {
throw new TagException("Failed to setting attribute '" + attrName + "'.", e);
}
}
}
private Object doConvertAttrValue(MethodInfo methodInfo, String attrName, Object attrValue) {
// 参数值已经是目标类型了, 不需要转换
if (methodInfo.paramType.isAssignableFrom(attrValue.getClass())) {
return attrValue;
}
if (methodInfo.paramType == String.class) {
// JDK7下集合转字符串有问题, 数据看不见
if (attrValue instanceof Collection) {
return ConvertTools.joinToString((Collection>) attrValue, ", ", true);
} else if (attrValue.getClass().isArray()) {
return ConvertTools.joinToString((Object[]) attrValue, ", ", true);
}
}
// 调用目标类型的静态方法valueOf()将值转换为目标类型
try {
return ValueOf.instance.eval(methodInfo.paramType, attrValue);
} catch (TagException e) {
e.prependMessage("Attribute " + attrName);
throw e;
} catch (Exception e) {
String name = methodInfo.paramType.getSimpleName();
String msg = String.format("Attribute '%s' error converting to type '%s'.", attrName, name);
throw new TagException(msg, e);
}
}
/** 校验必选字段 **/
public void validAttrRequireds(Class extends ITag> tagType, List attributes) {
initCacheSetterMethods(tagType);
// 校验必选字段
List requireds = cachedRequiredFields.get(tagType);
if (requireds == null || requireds.isEmpty()) {
return;
}
// 遍历必选字段, 如果属性中没有就报错
Map map = KeyValue.toMap(attributes);
for (String item : requireds) {
Object value = map.get(item);
if (VerifyTools.isNotBlank(value)) {
continue; // 属性表有这个字段了
}
throw new TagException(String.format("Missing a required attribute '%s'.", item));
}
}
/** 获取动态参数的容器名称 **/
public String getDynamicName(Class extends ITag> tagType) {
initCacheSetterMethods(tagType);
return cachedDynamicNames.get(tagType);
}
public MethodInfo getMethodInfo(Class extends ITag> tagType, String attrName) {
initCacheSetterMethods(tagType);
boolean throwOnSetterNotFound = !cachedDynamicNames.containsKey(tagType);
String key = tagType.getName() + '.' + attrName;
MethodInfo methodInfo = this.cachedMethods.get(key);
if (methodInfo == null && throwOnSetterNotFound) {
throw new TagException("Attribute '" + attrName + "' not supported.");
}
return methodInfo;
}
public static class MethodInfo {
private final Method setterMethod;
private final Class> paramType;
private final boolean required;
/** String类型的属性值要不要尝试作为表达式解析 **/
private final boolean tryEvalString;
public MethodInfo(Method setterMethod, Class> paramType, boolean required, boolean tryEvalString) {
this.setterMethod = setterMethod;
this.paramType = paramType;
this.required = required;
this.tryEvalString = tryEvalString;
}
public Class> getParamType() {
return paramType;
}
public boolean isRequired() {
return required;
}
public boolean isTryEvalString() {
return tryEvalString;
}
}
private final Map, ?> initedTypes = new HashMap<>();
private final Map cachedMethods = new HashMap<>();
private final Map, List> cachedRequiredFields = new HashMap<>();
private final Map, String> cachedDynamicNames = new HashMap<>();
private void initCacheSetterMethods(Class extends ITag> tagType) {
if (!initedTypes.containsKey(tagType)) {
doInitCacheSetterMethods(tagType);
}
}
private synchronized void doInitCacheSetterMethods(Class extends ITag> tagType) {
if (initedTypes.containsKey(tagType)) {
return;
}
DynamicAttrSupport dynamicAttr = tagType.getAnnotation(DynamicAttrSupport.class);
if (dynamicAttr != null && VerifyTools.isNotBlank(dynamicAttr.value())) {
cachedDynamicNames.put(tagType, dynamicAttr.value());
}
List requiredFields = new ArrayList<>();
Class> clazz = tagType;
for (; clazz != null; clazz = clazz.getSuperclass()) {
Method[] methods = clazz.getDeclaredMethods();
for (Method method : methods) {
// 去掉静态方法
if (Modifier.isStatic(method.getModifiers())) {
continue;
}
// 去掉非公有方法
if (!Modifier.isPublic(method.getModifiers())) {
continue;
}
// 去掉方法名小于3位的
String name = method.getName();
if (name.length() <= SET.length()) {
continue;
}
// 去掉不是set开头的
if (!name.startsWith(SET)) {
continue;
}
// 去掉参数不只一个的
Class>[] paramTypes = method.getParameterTypes();
if (paramTypes.length != 1) {
continue;
}
Class> paramType = paramTypes[0];
// 首字母小写
char first = Character.toLowerCase(name.charAt(SET.length()));
String suffix = name.substring(SET.length() + 1);
String fieldName = first + suffix;
AttrRequired attrRequired = method.getAnnotation(AttrRequired.class);
boolean required = attrRequired != null;
if (required) {
requiredFields.add(fieldName);
}
// 检查@TryEvalString注解
boolean tryEvalStringEnabled = true;
TryEvalString tryEvalStringAnnotation = method.getAnnotation(TryEvalString.class);
if (tryEvalStringAnnotation != null) {
tryEvalStringEnabled = tryEvalStringAnnotation.enabled();
}
String key = tagType.getName() + '.' + fieldName;
if (!this.cachedMethods.containsKey(key)) {
this.cachedMethods.put(key, new MethodInfo(method, paramType, required, tryEvalStringEnabled));
}
}
}
cachedRequiredFields.put(tagType, requiredFields.isEmpty() ? null : requiredFields);
initedTypes.put(tagType, null);
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy