package io.vertx.codegen;
import io.vertx.codegen.annotations.ModuleGen;
import io.vertx.codegen.format.Case;
import io.vertx.codegen.format.KebabCase;
import io.vertx.codegen.type.TypeNameTranslator;
import javax.lang.model.element.AnnotationValue;
import javax.lang.model.element.PackageElement;
import javax.lang.model.element.TypeElement;
import javax.lang.model.element.TypeParameterElement;
import javax.lang.model.type.DeclaredType;
import javax.lang.model.type.TypeKind;
import javax.lang.model.type.TypeMirror;
import javax.lang.model.util.Elements;
import javax.lang.model.util.Types;
import java.lang.reflect.Method;
import java.util.Collections;
import java.util.List;
import java.util.Set;
import java.util.function.BiFunction;
public class ModuleInfo {
private final String packageName;
private final String name;
private final String groupPackage;
public ModuleInfo(String packageName, String name, String groupPackage) {
this.packageName = packageName;
this.name = name;
this.groupPackage = groupPackage;
}
private static final BiFunction<Elements, String, Set<PackageElement>> getPackageElementJava8 = (elts, fqn) -> {
PackageElement elt = elts.getPackageElement(fqn);
return elt != null ? Collections.singleton(elt) : Collections.emptySet();
};
private static final BiFunction<Elements, String, Set<PackageElement>> getPackageElement;
static {
BiFunction<Elements, String, Set<PackageElement>> result = getPackageElementJava8;
try {
Method method = Elements.class.getDeclaredMethod("getAllPackageElements", CharSequence.class);
result = (elts, fqn) -> {
try {
return (Set<PackageElement>) method.invoke(elts, fqn);
} catch (Exception e) {
return getPackageElementJava8.apply(elts, fqn);
}
};
} catch (NoSuchMethodException e) {
}
getPackageElement = result;
}
public static ModuleInfo resolve(Elements elementUtils, PackageElement pkgElt) {
PackageElement result = resolveFirstModuleGenAnnotatedPackageElement(elementUtils, pkgElt);
if (result != null) {
ModuleGen annotation = result.getAnnotation(ModuleGen.class);
return new ModuleInfo(result.getQualifiedName().toString(), annotation.name(), annotation.groupPackage());
} else return null;
}
public static DeclaredType resolveJsonMapper(Elements elementUtils, Types typeUtils, PackageElement pkgElt, DeclaredType javaType) {
PackageElement result = resolveFirstModuleGenAnnotatedPackageElement(elementUtils, pkgElt);
if (result != null) {
TypeElement jsonMapperElt = elementUtils.getTypeElement("io.vertx.core.spi.json.JsonMapper");
TypeParameterElement typeParamElt = jsonMapperElt.getTypeParameters().get(0);
return elementUtils
.getAllAnnotationMirrors(pkgElt)
.stream()
.filter(am -> am.getAnnotationType().toString().equals(ModuleGen.class.getName()))
.flatMap(am -> am.getElementValues().entrySet().stream())
.filter(e -> e.getKey().getSimpleName().toString().equals("mappers"))
.flatMap(e -> ((List<AnnotationValue>) e.getValue().getValue()).stream())
.map(annotationValue -> (DeclaredType) annotationValue.getValue())
.filter(dt -> {
TypeMirror mapperType = Helper.resolveTypeParameter(typeUtils, dt, typeParamElt);
return mapperType != null && mapperType.getKind() == TypeKind.DECLARED && typeUtils.isSameType(mapperType, javaType);
})
.findFirst()
.orElse(null);
}
return null;
}
public static PackageElement resolveFirstModuleGenAnnotatedPackageElement(Elements elementUtils, PackageElement pkgElt) {
if (pkgElt == null) return null;
String pkgQN = pkgElt.getQualifiedName().toString();
while (true) {
if (pkgElt != null) {
ModuleGen annotation = pkgElt.getAnnotation(ModuleGen.class);
if (annotation != null) {
return pkgElt;
}
}
int pos = pkgQN.lastIndexOf('.');
if (pos == -1) {
break;
} else {
pkgQN = pkgQN.substring(0, pos);
Set<PackageElement> pkgElts = getPackageElement.apply(elementUtils, pkgQN);
pkgElt = pkgElts.isEmpty() ? null : pkgElts.iterator().next();
}
}
return null;
}
public String getGroupPackage() {
return groupPackage;
}
public String getPackageName() {
return packageName;
}
public String translatePackageName(String lang) {
return translateQualifiedName(packageName, lang);
}
public String translateQualifiedName(String qualifiedName, String lang) {
return TypeNameTranslator.hierarchical(lang).translate(this, qualifiedName);
}
public String getName() {
return name;
}
public String getName(Case _case) {
return _case.format(KebabCase.INSTANCE.parse(name));
}
}