如何成为T型人才,垂直在一个行业中,必须要有一整套知识体系,在这里,就一个字坚持~
前言
开发过程中,经常会运用到一些设计模式,优秀的架构少不了设计模式使用。工厂设计模式属于创建模式之一,当一个类或者接口有多个子类,并且基于输入返回特定的子类,此时会使用工厂设计模式,这种模式负责从客户端到工厂类的实例化。其实原理我们都懂,那如何通过APT技术实现工厂类?接下来直接代码编码,注解理论知识,请移步到 细聊注解知识点。谢谢~
Contents
一、定义实例化对象注解
@ObjectFactory:该注解标识需要加入工厂类的子类。@Retention(RetentionPolicy.CLASS):表示编译时注解。@Target(ElementType.TYPE): 表示修饰类。注解参数定义type变量,表示工厂类Class对象,key变量,表示注解修饰类在工厂类中的标识。
@Retention(RetentionPolicy.CLASS)
@Target(ElementType.TYPE)
public @interface ObjectFactory {
Class type(); //父类名
String key(); //标识
}
二、自定义注解处理器
不同注解类型,对应不同注解处理器,注解处理器主要作用就是注解解析。在定义编译时注解,我们需要通过继承AbstractProcessor这个类来创建注解处理器,并重写父类方法,一般只需要重新几个重要方法分别:
1、注解初始化
public synchronized void init(ProcessingEnvironment processingEnvironment)
2、注解解析
public boolean process(Set<? extends TypeElement> set, RoundEnvironment roundEnvironment) {
3、注解版本
public SourceVersion getSupportedSourceVersion()
4、解析类型
public Set<String> getSupportedAnnotationTypes()
2.1、注解处理器初始化
AbstractProcessor注解处理器每次初始化只会调用一次init(ProcessingEnvironment processingEnvironment)方法,所以可以用来初始化工具类。
@Override
public synchronized void init(ProcessingEnvironment processingEnvironment) {
super.init(processingEnvironment);
//注解处理器工具类
mProcessorUtils = ProcessorUtils.getInstance(processingEnv);
//根据ObjectFactory.object()类型,存储不同的子类
mGroupedClassesMap = new LinkedHashMap<>();
//生产模板对象
mGenerator = new ObjectFactoryGenerator();
}
2.2、绑定注解到注解处理器
getSupportedAnnotationTypes()方法是注解处理器能够识别注解类型。这里把注解@ObjectFactory存储到LinkedHashSet数据结构中,并返回集合,标识注解处理器识别目标注解对象。
@Override
public Set<String> getSupportedAnnotationTypes() {
LinkedHashSet<String> types = new LinkedHashSet<>(1);
types.add(ObjectFactory.class.getCanonicalName());
return types;
}
2.3、注解解析处理
RoundEnvironment这个类中提供#getElementsAnnotatedWith()方法,可以根据注解类型返回该类型注解所有信息,通过Element可以获取注解信息。Element.getKind返回注解修饰类型,根据不同类型转换为不同Element子类。#checkValidClass() 主要校验注解是否有效,有效数据根据注解type类型进行区分存储,type标识不同工厂类。解析所有注解信息后,存储到LinkedHashMap集合中,最后遍历集合中数据,循环调用 #generator方法,生成样板代码。
@Override
public boolean process(Set<? extends TypeElement> set, RoundEnvironment roundEnvironment) {
Set<? extends Element> factoryElements =
roundEnvironment.getElementsAnnotatedWith(ObjectFactory.class);
for (Element element : factoryElements) {
ObjectFactoryClasses classes = null;
try {
ElementKind kind = element.getKind();
if (kind == ElementKind.CLASS) {
classes = new ObjectFactoryClasses((TypeElement) element);
if (!checkValidClass(classes)) {
return true; //检查不符合要求,进行错误日志输出
}
ObjectFactoryGroupedClasses groupedClasses = mGroupedClassesMap.get(classes.getQualifiedName());
if (groupedClasses == null) {
groupedClasses = new ObjectFactoryGroupedClasses();
mGroupedClassesMap.put(classes.getQualifiedName(), groupedClasses);
}
groupedClasses.addObjectFactoryClasses(classes);
}
} catch (IllegalArgumentException e) {
mProcessorUtils.eLog(e.getMessage());
return true;
} catch (IdAlreadyUsedException e) {
ObjectFactoryClasses existing = e.getExisting();
assert classes != null;
mProcessorUtils.eLog(
"Conflict: The class %s is annotated with @%s with id ='%s' but %s already uses the same id",
classes.getQualifiedName(), ObjectFactory.class.getSimpleName(),
existing.getTypeElement().getQualifiedName().toString());
return true;
}
}
try {
//生成模板代码
for (String objects : mGroupedClassesMap.keySet()) {
mGenerator.generator(objects, mGroupedClassesMap.get(objects), mProcessorUtils, processingEnv);
}
//process()多次调用处理,所以配置信息及时释放
mGroupedClassesMap.clear();
} catch (Exception e) {
mProcessorUtils.eLog(e.getMessage());
}
return true;
}
2.4、注解信息校验
@ObjectFactory注解修饰的类级别,所以主要校验类的限定符,是否抽象类,是否实现同一个父类,这里getQualifiedName()方法通过反射射方式获取共同父类名,在通过不断循环判断是否实现同个父类,同时对构造函数限定符,参数校验。
/**
* 类型校验
* @param classes
* @return
*/
private boolean checkValidClass(ObjectFactoryClasses classes) {
TypeElement typeElement = classes.getTypeElement();
//检查该类限定符
if (!typeElement.getModifiers().contains(Modifier.PUBLIC)) {
mProcessorUtils.eLog("The class $s not public",
classes.getQualifiedName());
return false;
}
//检查是否是一个抽象类
if (typeElement.getModifiers().contains(Modifier.ABSTRACT)) {
mProcessorUtils.eLog("The class $s is abstract," +
"You can't annotate abstract classes with @%s",
classes.getQualifiedName(), ObjectFactory.class.getSimpleName());
return false;
}
//检查继承关系,必须是@ObjectFactory.object()类型子类
TypeElement superTypeElement = mProcessorUtils.processorElementUtils().
getTypeElement(classes.getQualifiedName());
//检查是否为接口类型
if (superTypeElement.getKind() == ElementKind.INTERFACE) {
if (!typeElement.getInterfaces().contains(superTypeElement.asType())) {
mProcessorUtils.eLog("The class %s annotated with @%s must implement the interface %s",
typeElement.getQualifiedName().toString(), ObjectFactory.class.getSimpleName(),
classes.getQualifiedName());
return false;
} else {
TypeElement currentClass = typeElement;
while (true) {
TypeMirror superclassType = currentClass.getSuperclass();
if (superclassType.getKind() == TypeKind.NONE) {
// 到达了基本类型(java.lang.Object), 所以退出
mProcessorUtils.eLog("The class %s annotated with @%s must inherit from %s",
typeElement.getQualifiedName().toString(), ObjectFactory.class.getSimpleName(),
classes.getQualifiedName());
return false;
}
if (superclassType.toString().equals(classes.getQualifiedName())) {
break;
}
currentClass = (TypeElement) mProcessorUtils.processorTypeUtils().asElement(superclassType);
}
}
}
for (Element element : typeElement.getEnclosedElements()) {
if (element.getKind() == ElementKind.CONSTRUCTOR) {
ExecutableElement constructorElement = (ExecutableElement) element;
if (constructorElement.getParameters().size() == 0 && constructorElement.getModifiers().contains(Modifier.PUBLIC)) {
return true;
}
}
}
// 没有找到默认构造函数
mProcessorUtils.eLog("The class %s must provide an public empty default constructor",
classes.getQualifiedName());
return false;
}
三、解析注解信息,生成样板代码
3.1、解析注解信息
在上文roundEnvironment.getElementsAnnotatedWith()获取到@ObjectFactory注解TypeElement对象,通过TypeElement可以获取到注解参数信息。
/**
* @Author: WeiShuai
* @Time: 2020/5/12
* @Description: TypeElements包装类,
*/
public class ObjectFactoryClasses {
private TypeElement mTypeElement;
private String mQualifiedName;
private String mSimpleName;
private String mKey;
public ObjectFactoryClasses(TypeElement typeElement) {
this.mTypeElement = typeElement;
ObjectFactory factory = mTypeElement.getAnnotation(ObjectFactory.class);
this.mKey = factory.key();
if ("".equals(mKey)) {
throw new IllegalArgumentException(
String.format("key() in @%s for class %s is null or empty! that's not allowed",
ObjectFactory.class.getSimpleName(), mTypeElement.getQualifiedName().toString()));
}
try {
Class<?> clazz = factory.type();
mQualifiedName = clazz.getCanonicalName();
mSimpleName = clazz.getSimpleName();
} catch (MirroredTypeException mte) {
DeclaredType classTypeMirror = (DeclaredType) mte.getTypeMirror();
TypeElement classTypeElement = (TypeElement) classTypeMirror.asElement();
mQualifiedName = classTypeElement.getQualifiedName().toString();
mSimpleName = classTypeElement.getSimpleName().toString();
}
}
/**
* 获取在{@link ObjectFactory#key()}指定的类型合法全名
*
* @return
*/
public String getQualifiedName() {
return mQualifiedName;
}
/**
* 获取在 {@link ObjectFactory#key()} 中指定的类型的简单名字
*
* @return qualified name
*/
public String getSimpleName() {
return mSimpleName;
}
/**
* 返回TypeElement
*
* @return
*/
public TypeElement getTypeElement() {
return mTypeElement;
}
/**
* 获取对象标识
*
* @return
*/
public String getKey() {
return mKey;
}
}
3.2、封装注解信息
根据注解@ObjectFactory参数key字段,key表示注解修饰类标识,通过该标识来封装注解信息。
/**
* @Author: WeiShuai
* @Time: 2020/5/12
* @Description: 保存TypeElements对象信息
*/
public class ObjectFactoryGroupedClasses {
private LinkedHashMap<String, ObjectFactoryClasses> mObjectFactoryMaps = new
LinkedHashMap<>();
/**
* 保存ObjectFactory对象
*/
public void addObjectFactoryClasses(ObjectFactoryClasses classes) throws IdAlreadyUsedException {
ObjectFactoryClasses objectFactoryClasses = mObjectFactoryMaps.get(classes.getKey());
if (objectFactoryClasses != null) {
throw new IdAlreadyUsedException(objectFactoryClasses);
}
mObjectFactoryMaps.put(classes.getKey(), classes);
}
/**
* 获取ObjectFactory对象
*
* @param key
*/
public ObjectFactoryClasses getObjectFactoryClasses(String key) {
return mObjectFactoryMaps.get(key);
}
/**
* 获取注解信息
*
* @return
*/
public LinkedHashMap<String, ObjectFactoryClasses> getObjectFactoryClassesMaps() {
return mObjectFactoryMaps;
}
}
3.3、生成样板代码
public class ObjectFactoryGenerator {
public void generator(String clazzType,
ObjectFactoryGroupedClasses groupedClasses,
ProcessorUtils processorUtils,
ProcessingEnvironment processingEnv) {
if ("".equals(clazzType)) {
throw new NullPointerException(
String.format("getQualifiedName() is null or empty! that's not allowed"));
}
TypeElement superTypeElement = processorUtils.processorElementUtils().
getTypeElement(clazzType);
String classes = superTypeElement.getSimpleName().toString();
MethodSpec.Builder methodBuilder = MethodSpec.methodBuilder(Constant.METHOD_FACTORY)
.addModifiers(Modifier.PUBLIC)
.returns(TypeName.get(superTypeElement.asType()));
//根据FactoryObject.key()获取对象
methodBuilder.addParameter(String.class, "id");
//LinkedHashMap<K,V>,K:注解标识,V:使用注解对应对象信息
LinkedHashMap<String, ObjectFactoryClasses> classesMaps =
groupedClasses.getObjectFactoryClassesMaps();
TypeElement typeElement = null;
for (String key : classesMaps.keySet()) {
typeElement = classesMaps.get(key).getTypeElement();
methodBuilder.addStatement("if( \"" + key + "\".equals(id)){");
methodBuilder.addStatement("return new " + typeElement.getQualifiedName().toString() + "()");
methodBuilder.addStatement("}");
}
methodBuilder.addStatement("return null");
if (typeElement != null) {
processorUtils.writeToFile(classes + Constant.FACTORY_SUFFIX,
processorUtils.getPackageName(typeElement),
methodBuilder.build(), processingEnv, null);
}
}
}
四、功能点测试
4.1、测试代码
- 创建抽象BaseFragment类作为共同父类,在HomeFragment、MineFragment类继承父类BaseFragment,实现父类未实现方法。
public abstract class BaseFragment extends Fragment {
@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
View rootView = inflater.inflate(getLayoutId(), null);
return rootView;
}
public abstract int getLayoutId();
}
- 创建HomeFragment、MineFragment类这里必须实现共同父类BaseFragment,因为@ObjectFactory注解校验规则限定,注解参数定义type=父类.class,key="类标识"。
@ObjectFactory(type = BaseFragment.class, key = "Home")
public class HomeFragment extends BaseFragment {
@Override
public int getLayoutId() {
return R.layout.fragment_home;
}
}
@ObjectFactory(type = BaseFragment.class, key = "Mine")
public class MineFragment extends BaseFragment {
@Override
public int getLayoutId() {
return R.layout.fragment_mine;
}
}
4.2、样板代码
通过解析指定注解信息,通过APT技术构建类、方法、字段,并生成java文件。
public final class BaseFragment$Factory {
public BaseFragment objectFactory(String id) {
if( "Home".equals(id)){;
return new com.linwei.annotation.compile.HomeFragment();
};
if( "Mine".equals(id)){;
return new com.linwei.annotation.compile.MineFragment();
};
return null;
}
}
About me
-
Email:linwei9605@gmail.com
-
Blog: offer.github.io/
-
Github: github.com/WeiShuaiDev