注解提炼与别名
EggG 通过 Handler 机制将注解解析逻辑集中管理。注册 Handler 后,元数据创建时会自动调用,结果随元数据一起缓存。
1、问题场景
假设你在开发一个 JSON 序列化框架,用户类如下:
public class User {
@ONodeAttr(alias = "user_name")
private String userName;
@ONodeAttr(alias = "created_at")
private Date createdAt;
}
需要把 userName 字段序列化为 "user_name"。传统做法是在每个使用点写 if-else + getAnnotation():
ONodeAttr attr = field.getAnnotation(ONodeAttr.class);
String alias = (attr != null) ? attr.alias() : field.getName();
字段和注解类型一多,逻辑就散落在各处,维护成本上升。类似的问题也出现在依赖注入(读 @Inject)、ORM(读 @Column)等场景。
EggG 通过 DigestHandler 和 AliasHandler 将这个逻辑统一收拢:编写一次解析规则,所有元数据自动处理。
2、Handler 体系
DigestHandler — 提炼处理器
DigestHandler 是一个函数式接口,在元数据创建时自动调用,从注解中提炼出自定义信息:
@FunctionalInterface
public interface DigestHandler {
Object apply(ClassEggg classEggg, AnnotatedEggg source, Object defaultValue);
}
参数说明: - classEggg:当前类的元数据(提供类级别上下文) - source:当前正在处理的注解元素,可能是 FieldEggg、MethodEggg、ParamEggg 等 - defaultValue:默认值(通常为 null)
返回值是提炼出的自定义对象,后续通过 source.getDigest() 获取。
AliasHandler — 别名处理器
AliasHandler 是函数式接口,用于为字段、参数、属性生成别名:
@FunctionalInterface
public interface AliasHandler {
String apply(ClassEggg classEggg, AnnotatedEggg source, String defaultValue);
}
参数说明: - classEggg:当前类的元数据 - source:当前正在处理的注解元素 - defaultValue:默认别名(通常是字段/参数的原始名称)
返回值是最终的别名。注解没有指定别名时返回 defaultValue,有指定时返回注解中的值。
3、注册 Handler
在创建 Eggg 实例时通过 withXxxHandler 方法注册:
Eggg eggg = new Eggg()
.withDigestHandler(this::doDigestHandle)
.withAliasHandler(this::doAliasHandle)
.withReflectHandler(new CustomReflectHandler());
注册后,每次创建 FieldEggg、MethodEggg、ParamEggg 等元数据时,Handler 会自动被调用,结果直接缓存。
4、实战:Snack4 集成示例
以下代码展示了在 JSON 库 Snack4 中,用 EggG 统一处理 @ONodeAttr 注解:
public class EgggUtil {
private static final Eggg eggg = new Eggg()
.withCreatorClass(ONodeCreator.class)
.withDigestHandler(EgggUtil::doDigestHandle)
.withAliasHandler(EgggUtil::doAliasHandle);
/**
* 别名处理器:从 Digest 中提取别名
*/
private static String doAliasHandle(ClassEggg cw, AnnotatedEggg s, String ref) {
if (s.getDigest() instanceof ONodeAttrHolder) {
return ((ONodeAttrHolder) s.getDigest()).getAlias();
} else {
return ref;
}
}
/**
* 提炼处理器:从注解生成 ONodeAttrHolder
*/
private static Object doDigestHandle(ClassEggg cw, AnnotatedEggg s, Object ref) {
ONodeAttr attr = s.getElement().getAnnotation(ONodeAttr.class);
if (attr == null && ref != null) {
return ref;
}
if (s instanceof FieldEggg) {
return new ONodeAttrHolder(attr, ((Field) s.getElement()).getName());
} else if (s instanceof PropertyMethodEggg) {
return new ONodeAttrHolder(attr,
Property.resolvePropertyName(((Method) s.getElement()).getName()));
} else if (s instanceof ParamEggg) {
return new ONodeAttrHolder(attr, ((Parameter) s.getElement()).getName());
} else {
return null;
}
}
public static TypeEggg getTypeEggg(Type type) {
return eggg.getTypeEggg(type);
}
}
在业务代码中读取提炼结果:
TypeEggg typeEggg = EgggUtil.getTypeEggg(clazz);
for (FieldEggg fw : typeEggg.getClassEggg().getAllFieldEgggs()) {
if (fw.isStatic()) {
continue;
}
// 获取提炼物
ONodeAttrHolder holder = fw.getDigest();
// 获取泛型信息
TypeEggg fieldType = fw.getTypeEggg();
// 获取别名
String alias = fw.getAlias();
}
5、实战:Solon 框架集成示例
以下代码展示了 Solon 框架如何通过 DigestHandler 将字段和参数统一封装为 FieldSpec / ParamSpec:
public class EgggUtil {
private static final Eggg eggg = new Eggg()
.withAliasHandler(EgggUtil::doAliasHandle)
.withDigestHandler(EgggUtil::doDigestHandle)
.withReflectHandler(new EgggReflectHandler());
private static String doAliasHandle(ClassEggg cw, AnnotatedEggg s, String ref) {
if (s.getDigest() instanceof VarSpec) {
return s.<VarSpec>getDigest().getName();
}
return ref;
}
private static Object doDigestHandle(ClassEggg cw, AnnotatedEggg s, Object ref) {
if (s instanceof FieldEggg) {
return new FieldSpec((FieldEggg) s);
} else if (s instanceof ParamEggg) {
return new ParamSpec((ParamEggg) s);
}
return ref;
}
public static TypeEggg getTypeEggg(Type type) {
return eggg.getTypeEggg(type);
}
public static ClassEggg getClassEggg(Type type) {
return getTypeEggg(type).getClassEggg();
}
}
6、Creator 机制
除了 Digest 和 Alias,EggG 还支持 Creator(创造器)机制,用于指定哪个构造器或静态工厂方法负责创建对象。
注解方式
通过 withCreatorClass 注册一个注解类,被该注解标注的构造器或静态方法将被视为创造器:
Eggg eggg = new Eggg()
.withCreatorClass(ONodeCreator.class);
自定义匹配方式
通过 withCreatorMatcher 注册自定义的匹配规则:
Eggg eggg = new Eggg()
.withCreatorMatcher((eggg, executable) -> {
return executable.isAnnotationPresent(MyCreator.class);
});
获取创造器
ClassEggg cw = eggg.getTypeEggg(MyClass.class).getClassEggg();
ConstrEggg creator = cw.getCreator();
MyClass obj = creator.newInstance();
7、Handler 执行时机
从调用 getTypeEggg 开始,Handler 在元数据创建时自动执行:
Eggg.getTypeEggg(type)
└→ 创建 TypeEggg
└→ 获取 ClassEggg 时触发
├→ 创建 FieldEggg → 自动触发 DigestHandler → 自动触发 AliasHandler
├→ 创建 MethodEggg → 自动触发 DigestHandler
├→ 创建 ConstrEggg → 自动触发 DigestHandler
└→ 创建 ParamEggg → 自动触发 DigestHandler → 自动触发 AliasHandler
Handler 结果缓存在对应的元数据对象中,后续通过 getDigest() 和 getAlias() 直接获取。
8、设计特点
| 特点 | 说明 |
|---|---|
| 统一入口 | 所有注解解析逻辑集中在 Handler 中 |
| 一次注册 | 不需要在每个使用点重复写解析代码 |
| 可组合 | Digest + Alias + Creator 三个维度独立配置 |
| 可扩展 | 通过 ReflectHandler 可自定义反射策略 |
| 缓存友好 | Handler 结果随元数据一起缓存,不重复计算 |