publicclassPizzaStore{publicMealorder(StringmealName){if(mealName==null){thrownewIllegalArgumentException("Name of the meal is null!");}if("Margherita".equals(mealName)){returnnewMargheritaPizza();}if("Calzone".equals(mealName)){returnnewCalzonePizza();}if("Tiramisu".equals(mealName)){returnnewTiramisu();}thrownewIllegalArgumentException("Unknown meal '"+mealName+"'");}publicstaticvoidmain(String[]args)throwsIOException{PizzaStorepizzaStore=newPizzaStore();Mealmeal=pizzaStore.order(readConsole());System.out.println("Bill: $"+meal.getPrice());}}
publicclassMealFactory{publicMealcreate(Stringid){if(id==null){thrownewIllegalArgumentException("id is null!");}if("Calzone".equals(id)){returnnewCalzonePizza();}if("Tiramisu".equals(id)){returnnewTiramisu();}if("Margherita".equals(id)){returnnewMargheritaPizza();}thrownewIllegalArgumentException("Unknown id = "+id);}}
TypeElementfooClass=...;for(Elemente:fooClass.getEnclosedElements()){// iterate over children Elementparent=e.getEnclosingElement();// parent == fooClass}
publicbooleanprocess(Set<?extendsTypeElement>annotations,RoundEnvironmentroundEnv){for(ElementannotatedElement:roundEnv.getElementsAnnotatedWith(Factory.class)){// 检查被注解为@Factory的元素是否是一个类if(annotatedElement.getKind()!=ElementKind.CLASS){error(annotatedElement,"Only classes can be annotated with @%s",Factory.class.getSimpleName());returntrue;// 退出处理}...}privatevoiderror(Elemente,Stringmsg,Object...args){messager.printMessage(Diagnostic.Kind.ERROR,String.format(msg,args),e);}}
publicclassFactoryAnnotatedClass{privateTypeElementannotatedClassElement;privateStringqualifiedSuperClassName;privateStringsimpleTypeName;privateStringid;publicFactoryAnnotatedClass(TypeElementclassElement)throwsIllegalArgumentException{this.annotatedClassElement=classElement;Factoryannotation=classElement.getAnnotation(Factory.class);id=annotation.id();if(StringUtils.isEmpty(id)){thrownewIllegalArgumentException(String.format("id() in @%s for class %s is null or empty! that's not allowed",Factory.class.getSimpleName(),classElement.getQualifiedName().toString()));}// Get the full QualifiedTypeNametry{Class<?>clazz=annotation.type();qualifiedSuperClassName=clazz.getCanonicalName();simpleTypeName=clazz.getSimpleName();}catch(MirroredTypeExceptionmte){DeclaredTypeclassTypeMirror=(DeclaredType)mte.getTypeMirror();TypeElementclassTypeElement=(TypeElement)classTypeMirror.asElement();qualifiedSuperClassName=classTypeElement.getQualifiedName().toString();simpleTypeName=classTypeElement.getSimpleName().toString();}}/** * 获取在{@link Factory#id()}中指定的id * return the id */publicStringgetId(){returnid;}/** * 获取在{@link Factory#type()}指定的类型合法全名 * * @return qualified name */publicStringgetQualifiedFactoryGroupName(){returnqualifiedSuperClassName;}/** * 获取在 {@link Factory#type()} 中指定的类型的简单名字 * * @return qualified name */publicStringgetSimpleFactoryGroupName(){returnsimpleTypeName;}/** * 获取被@Factory注解的原始元素 */publicTypeElementgetTypeElement(){returnannotatedClassElement;}}
Factoryannotation=classElement.getAnnotation(Factory.class);id=annotation.id();// Read the id value (like "Calzone" or "Tiramisu")if(StringUtils.isEmpty(id)){thrownewIllegalArgumentException(String.format("id() in @%s for class %s is null or empty! that's not allowed",Factory.class.getSimpleName(),classElement.getQualifiedName().toString()));}
publicclassFactoryProcessorextendsAbstractProcessor{@Overridepublicbooleanprocess(Set<?extendsTypeElement>annotations,RoundEnvironmentroundEnv){for(ElementannotatedElement:roundEnv.getElementsAnnotatedWith(Factory.class)){...// 因为我们已经知道它是ElementKind.CLASS类型,所以可以直接强制转换TypeElementtypeElement=(TypeElement)annotatedElement;try{FactoryAnnotatedClassannotatedClass=newFactoryAnnotatedClass(typeElement);// throws IllegalArgumentExceptionif(!isValidClass(annotatedClass)){returntrue;// 已经打印了错误信息,退出处理过程}}catch(IllegalArgumentExceptione){// @Factory.id()为空error(typeElement,e.getMessage());returntrue;}...}privatebooleanisValidClass(FactoryAnnotatedClassitem){// 转换为TypeElement, 含有更多特定的方法TypeElementclassElement=item.getTypeElement();if(!classElement.getModifiers().contains(Modifier.PUBLIC)){error(classElement,"The class %s is not public.",classElement.getQualifiedName().toString());returnfalse;}// 检查是否是一个抽象类if(classElement.getModifiers().contains(Modifier.ABSTRACT)){error(classElement,"The class %s is abstract. You can't annotate abstract classes with @%",classElement.getQualifiedName().toString(),Factory.class.getSimpleName());returnfalse;}// 检查继承关系: 必须是@Factory.type()指定的类型子类TypeElementsuperClassElement=elementUtils.getTypeElement(item.getQualifiedFactoryGroupName());if(superClassElement.getKind()==ElementKind.INTERFACE){// 检查接口是否实现了 if(!classElement.getInterfaces().contains(superClassElement.asType())) {error(classElement,"The class %s annotated with @%s must implement the interface %s",classElement.getQualifiedName().toString(),Factory.class.getSimpleName(),item.getQualifiedFactoryGroupName());returnfalse;}}else{// 检查子类TypeElementcurrentClass=classElement;while(true){TypeMirrorsuperClassType=currentClass.getSuperclass();if(superClassType.getKind()==TypeKind.NONE){// 到达了基本类型(java.lang.Object), 所以退出error(classElement,"The class %s annotated with @%s must inherit from %s",classElement.getQualifiedName().toString(),Factory.class.getSimpleName(),item.getQualifiedFactoryGroupName());returnfalse;}if(superClassType.toString().equals(item.getQualifiedFactoryGroupName())){// 找到了要求的父类break;}// 在继承树上继续向上搜寻currentClass=(TypeElement)typeUtils.asElement(superClassType);}}// 检查是否提供了默认公开构造函数for(Elementenclosed:classElement.getEnclosedElements()){if(enclosed.getKind()==ElementKind.CONSTRUCTOR){ExecutableElementconstructorElement=(ExecutableElement)enclosed;if(constructorElement.getParameters().size()==0&&constructorElement.getModifiers().contains(Modifier.PUBLIC)){// 找到了默认构造函数returntrue;}}}// 没有找到默认构造函数error(classElement,"The class %s must provide an public empty default constructor",classElement.getQualifiedName().toString());returnfalse;}}
publicclassFactoryProcessorextendsAbstractProcessor{privateMap<String,FactoryGroupedClasses>factoryClasses=newLinkedHashMap<String,FactoryGroupedClasses>();@Overridepublicbooleanprocess(Set<?extendsTypeElement>annotations,RoundEnvironmentroundEnv){...try{FactoryAnnotatedClassannotatedClass=newFactoryAnnotatedClass(typeElement);// throws IllegalArgumentExceptionif(!isValidClass(annotatedClass)){returntrue;// 错误信息被打印,退出处理流程}// 所有检查都没有问题,所以可以添加了FactoryGroupedClassesfactoryClass=factoryClasses.get(annotatedClass.getQualifiedFactoryGroupName());if(factoryClass==null){StringqualifiedGroupName=annotatedClass.getQualifiedFactoryGroupName();factoryClass=newFactoryGroupedClasses(qualifiedGroupName);factoryClasses.put(qualifiedGroupName,factoryClass);}// 如果和其他的@Factory标注的类的id相同冲突,// 抛出IdAlreadyUsedException异常factoryClass.add(annotatedClass);}catch(IllegalArgumentExceptione){// @Factory.id()为空 --> 打印错误信息error(typeElement,e.getMessage());returntrue;}catch(IdAlreadyUsedExceptione){FactoryAnnotatedClassexisting=e.getExisting();// 已经存在error(annotatedElement,"Conflict: The class %s is annotated with @%s with id ='%s' but %s already uses the same id",typeElement.getQualifiedName().toString(),Factory.class.getSimpleName(),existing.getTypeElement().getQualifiedName().toString());returntrue;}}...}
publicclassFactoryGroupedClasses{/** * 将被添加到生成的工厂类的名字中 */privatestaticfinalStringSUFFIX="Factory";privateStringqualifiedClassName;privateMap<String,FactoryAnnotatedClass>itemsMap=newLinkedHashMap<String,FactoryAnnotatedClass>();...publicvoidgenerateCode(ElementselementUtils,Filerfiler)throwsIOException{TypeElementsuperClassName=elementUtils.getTypeElement(qualifiedClassName);StringfactoryClassName=superClassName.getSimpleName()+SUFFIX;JavaFileObjectjfo=filer.createSourceFile(qualifiedClassName+SUFFIX);Writerwriter=jfo.openWriter();JavaWriterjw=newJavaWriter(writer);// 写包名PackageElementpkg=elementUtils.getPackageOf(superClassName);if(!pkg.isUnnamed()){jw.emitPackage(pkg.getQualifiedName().toString());jw.emitEmptyLine();}else{jw.emitPackage("");}jw.beginType(factoryClassName,"class",EnumSet.of(Modifier.PUBLIC));jw.emitEmptyLine();jw.beginMethod(qualifiedClassName,"create",EnumSet.of(Modifier.PUBLIC),"String","id");jw.beginControlFlow("if (id == null)");jw.emitStatement("throw new IllegalArgumentException(\"id is null!\")");jw.endControlFlow();for(FactoryAnnotatedClassitem:itemsMap.values()){jw.beginControlFlow("if (\"%s\".equals(id))",item.getId());jw.emitStatement("return new %s()",item.getTypeElement().getQualifiedName().toString());jw.endControlFlow();jw.emitEmptyLine();}jw.emitStatement("throw new IllegalArgumentException(\"Unknown id = \" + id)");jw.endMethod();jw.endType();jw.close();}}
请注意的是,在FactoryProcessor代码中有一些缺陷和陷阱。这些“错误”是我故意放进去的,是为了演示一些在开发过程中的常见错误(例如“Attempt to recreate a file”)。如果你想基于FactoryProcessor写你自己注解处理器,请**不要**直接拷贝粘贴这些陷阱过去,你应该从最开始就避免它们。