package com.qianwen.smart.core.auto.factories;
|
|
|
import java.io.IOException;
|
import java.net.URI;
|
import java.net.URISyntaxException;
|
import java.nio.file.Path;
|
import java.nio.file.Paths;
|
import java.util.List;
|
import java.util.Set;
|
import java.util.stream.Collectors;
|
import javax.annotation.processing.Filer;
|
import javax.annotation.processing.ProcessingEnvironment;
|
import javax.annotation.processing.RoundEnvironment;
|
import javax.annotation.processing.SupportedAnnotationTypes;
|
import javax.annotation.processing.SupportedOptions;
|
import javax.lang.model.element.AnnotationMirror;
|
import javax.lang.model.element.Element;
|
import javax.lang.model.element.ElementKind;
|
import javax.lang.model.element.TypeElement;
|
import javax.lang.model.util.Elements;
|
import javax.tools.FileObject;
|
import javax.tools.StandardLocation;
|
|
import com.qianwen.smart.core.auto.annotation.AutoIgnore;
|
import com.qianwen.smart.core.auto.common.AbstractBladeProcessor;
|
import com.qianwen.smart.core.auto.common.BootAutoType;
|
import com.qianwen.smart.core.auto.common.MultiSetMap;
|
|
|
@SupportedAnnotationTypes({"*"})
|
@SupportedOptions({"debug"})
|
public class AutoFactoriesProcessor extends AbstractBladeProcessor {
|
private static final String FEIGN_CLIENT_ANNOTATION = "org.springframework.cloud.openfeign.FeignClient";
|
private static final String FEIGN_AUTO_CONFIGURE_KEY = "com.qianwen.core.cloud.feign.BladeFeignAutoConfiguration";
|
private static final String FACTORIES_RESOURCE_LOCATION = "META-INF/spring.factories";
|
private static final String DEVTOOLS_RESOURCE_LOCATION = "META-INF/spring-devtools.properties";
|
private final MultiSetMap<String, String> factories = new MultiSetMap<>();
|
private Elements elementUtils;
|
|
|
public synchronized void init(ProcessingEnvironment processingEnv) {
|
super.init(processingEnv);
|
this.elementUtils = processingEnv.getElementUtils();
|
}
|
|
protected boolean processImpl(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
|
if (roundEnv.processingOver()) {
|
generateFactoriesFiles();
|
} else {
|
processAnnotations(annotations, roundEnv);
|
}
|
return false;
|
}
|
|
private void processAnnotations(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
|
log(annotations.toString());
|
Set<? extends Element> elementSet = roundEnv.getRootElements();
|
log("All Element set: " + elementSet.toString());
|
Set<TypeElement> typeElementSet = (Set<TypeElement>)elementSet.stream().filter(this::isClassOrInterface).filter(e -> e instanceof TypeElement).map(e -> (TypeElement)e).collect(Collectors.toSet());
|
if (typeElementSet.isEmpty()) {
|
log("Annotations elementSet is isEmpty");
|
return;
|
}
|
for (TypeElement typeElement : typeElementSet) {
|
if (isAnnotation(this.elementUtils, typeElement, AutoIgnore.class.getName())) {
|
log("Found @AutoIgnore annotationElement: " + typeElement.toString());
|
continue;
|
} else if (isAnnotation(this.elementUtils, typeElement, FEIGN_CLIENT_ANNOTATION)) {
|
|
log("Found @FeignClient Element: " + typeElement.toString());
|
ElementKind elementKind = typeElement.getKind();
|
if (ElementKind.INTERFACE != elementKind) {
|
fatalError("@FeignClient Element " + typeElement.toString() + " 不是接口。");
|
} else {
|
String factoryName = typeElement.getQualifiedName().toString();
|
if (!this.factories.containsVal(factoryName)) {
|
log("读取到新配置 spring.factories factoryName:" + factoryName);
|
this.factories.put(FEIGN_AUTO_CONFIGURE_KEY, factoryName);
|
}
|
}
|
|
}else {
|
for (BootAutoType autoType : BootAutoType.values()) {
|
String annotation = autoType.getAnnotationName();
|
if (isAnnotation(this.elementUtils, typeElement, annotation)) {
|
log("Found @" + annotation + " Element: " + typeElement.toString());
|
String factoryName2 = typeElement.getQualifiedName().toString();
|
if (!this.factories.containsVal(factoryName2)) {
|
log("读取到新配置 spring.factories factoryName:" + factoryName2);
|
this.factories.put(autoType.getConfigureKey(), factoryName2);
|
}
|
}
|
}
|
}
|
|
|
}
|
}
|
|
private void generateFactoriesFiles() {
|
if (this.factories.isEmpty()) {
|
return;
|
}
|
Filer filer = this.processingEnv.getFiler();
|
try {
|
FileObject factoriesFile = filer.createResource(StandardLocation.CLASS_OUTPUT, "", FACTORIES_RESOURCE_LOCATION, new Element[0]);
|
FactoriesFiles.writeFactoriesFile(this.factories, factoriesFile.openOutputStream());
|
String classesPath = factoriesFile.toUri().toString().split("classes")[0];
|
Path projectPath = Paths.get(new URI(classesPath)).getParent();
|
String projectName = projectPath.getFileName().toString();
|
FileObject devToolsFile = filer.createResource(StandardLocation.CLASS_OUTPUT, "", DEVTOOLS_RESOURCE_LOCATION, new Element[0]);
|
FactoriesFiles.writeDevToolsFile(projectName, devToolsFile.openOutputStream());
|
} catch (IOException | URISyntaxException e) {
|
fatalError(e);
|
}
|
|
}
|
|
private boolean isClassOrInterface(Element e) {
|
ElementKind kind = e.getKind();
|
return (kind == ElementKind.CLASS || kind == ElementKind.INTERFACE);
|
}
|
|
private boolean isAnnotation(Elements elementUtils, Element e, String annotationFullName) {
|
List<? extends AnnotationMirror> annotationList = elementUtils.getAllAnnotationMirrors(e);
|
for (AnnotationMirror annotation : annotationList) {
|
if (isAnnotation(annotationFullName, annotation))
|
return true;
|
Element element = annotation.getAnnotationType().asElement();
|
if (element.toString().startsWith("java.lang"))
|
continue;
|
if (isAnnotation(elementUtils, element, annotationFullName))
|
return true;
|
}
|
return false;
|
}
|
|
private boolean isAnnotation(String annotationFullName, AnnotationMirror annotation) {
|
return annotationFullName.equals(annotation.getAnnotationType().toString());
|
}
|
}
|