io.dinject.javalin.generator.ControllerReader Maven / Gradle / Ivy
package io.dinject.javalin.generator;
import io.dinject.controller.Path;
import io.dinject.controller.Produces;
import io.swagger.v3.oas.annotations.Hidden;
import javax.lang.model.element.Element;
import javax.lang.model.element.ElementKind;
import javax.lang.model.element.ExecutableElement;
import javax.lang.model.element.TypeElement;
import javax.lang.model.type.DeclaredType;
import javax.lang.model.type.ExecutableType;
import javax.lang.model.type.TypeKind;
import javax.lang.model.type.TypeMirror;
import javax.lang.model.util.ElementFilter;
import javax.validation.Valid;
import java.lang.annotation.Annotation;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import java.util.TreeSet;
import static io.dinject.javalin.generator.Constants.JAVALIN2_ROLES;
import static io.dinject.javalin.generator.Constants.JAVALIN3_ROLES;
/**
* Reads the type information for the Controller (bean).
*/
class ControllerReader {
private final ProcessingContext ctx;
private final TypeElement beanType;
private final List interfaces;
private final List interfaceMethods;
private final List roles;
private final List methods = new ArrayList<>();
private final Set staticImportTypes = new TreeSet<>();
private final Set importTypes = new TreeSet<>();
/**
* The produces media type for the controller. Null implies JSON.
*/
private final String produces;
private boolean docHidden;
private final boolean includeValidator;
ControllerReader(TypeElement beanType, ProcessingContext ctx) {
this.beanType = beanType;
this.ctx = ctx;
this.interfaces = initInterfaces();
this.interfaceMethods = initInterfaceMethods();
this.roles = Util.findRoles(beanType);
final String generated = ctx.getGeneratedAnnotation();
if (generated != null) {
importTypes.add(generated);
}
if (ctx.isOpenApiAvailable()) {
docHidden = initDocHidden();
}
includeValidator = initIncludeValidator();
importTypes.add(Constants.SINGLETON);
importTypes.add(Constants.API_BUILDER);
importTypes.add(Constants.IMPORT_CONTROLLER);
importTypes.add(beanType.getQualifiedName().toString());
if (includeValidator) {
importTypes.add(Constants.VALIDATOR);
}
this.produces = initProduces();
}
private List initInterfaces() {
List interfaces = new ArrayList<>();
for (TypeMirror anInterface : beanType.getInterfaces()) {
final Element ifaceElement = ctx.asElement(anInterface);
if (ifaceElement.getAnnotation(Path.class) != null) {
interfaces.add(ifaceElement);
}
}
return interfaces;
}
private List initInterfaceMethods() {
List ifaceMethods = new ArrayList<>();
for (Element anInterface : interfaces) {
ifaceMethods.addAll(ElementFilter.methodsIn(anInterface.getEnclosedElements()));
}
return ifaceMethods;
}
private A findAnnotation(Class type) {
A annotation = beanType.getAnnotation(type);
if (annotation != null) {
return annotation;
}
for (Element anInterface : interfaces) {
annotation = anInterface.getAnnotation(type);
if (annotation != null) {
return annotation;
}
}
return null;
}
A findMethodAnnotation(Class type, ExecutableElement element) {
for (ExecutableElement interfaceMethod : interfaceMethods) {
if (matchMethod(interfaceMethod, element)) {
final A annotation = interfaceMethod.getAnnotation(type);
if (annotation != null) {
return annotation;
}
}
}
return null;
}
private boolean matchMethod(ExecutableElement interfaceMethod, ExecutableElement element) {
return interfaceMethod.toString().equals(element.toString());
}
private String initProduces() {
final Produces produces = findAnnotation(Produces.class);
return (produces == null) ? null : produces.value();
}
private boolean initDocHidden() {
return findAnnotation(Hidden.class) != null;
}
private boolean initIncludeValidator() {
return findAnnotation(Valid.class) != null;
}
String getProduces() {
return produces;
}
TypeElement getBeanType() {
return beanType;
}
boolean isDocHidden() {
return docHidden;
}
boolean isIncludeValidator() {
return includeValidator;
}
void read() {
if (!roles.isEmpty()) {
addStaticImportType(ctx.isJavalin3() ? JAVALIN3_ROLES : JAVALIN2_ROLES);
for (String role : roles) {
addStaticImportType(role);
}
}
for (Element element : beanType.getEnclosedElements()) {
if (element.getKind() == ElementKind.METHOD) {
readMethod((ExecutableElement) element);
}
}
readSuper(beanType);
}
/**
* Read methods from superclasses taking into account generics.
*/
private void readSuper(TypeElement beanType) {
TypeMirror superclass = beanType.getSuperclass();
if (superclass.getKind() != TypeKind.NONE) {
DeclaredType declaredType = (DeclaredType) superclass;
final Element superElement = ctx.asElement(superclass);
if (!"java.lang.Object".equals(superElement.toString())) {
for (Element element : superElement.getEnclosedElements()) {
if (element.getKind() == ElementKind.METHOD) {
readMethod((ExecutableElement) element, declaredType);
}
}
if (superElement instanceof TypeElement) {
readSuper((TypeElement) superElement);
}
}
}
}
private void readMethod(ExecutableElement element) {
readMethod(element, null);
}
private void readMethod(ExecutableElement method, DeclaredType declaredType) {
ExecutableType actualExecutable = null;
if (declaredType != null) {
// actual taking into account generics
actualExecutable = (ExecutableType) ctx.asMemberOf(declaredType, method);
}
MethodReader methodReader = new MethodReader(this, method, actualExecutable, ctx);
if (methodReader.isWebMethod()) {
methodReader.read();
methods.add(methodReader);
}
}
List getRoles() {
return roles;
}
List getMethods() {
return methods;
}
String getPath() {
Path path = findAnnotation(Path.class);
if (path == null) {
return null;
}
return Util.trimPath(path.value());
}
void addImportType(String rawType) {
importTypes.add(rawType);
}
void addStaticImportType(String rawType) {
staticImportTypes.add(rawType);
}
Set getStaticImportTypes() {
return staticImportTypes;
}
Set getImportTypes() {
return importTypes;
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy