package net.karneim.pojobuilder.analysis;
import java.util.HashSet;
import java.util.Set;
import javax.lang.model.element.Element;
import javax.lang.model.element.ElementKind;
import javax.lang.model.element.ExecutableElement;
import javax.lang.model.element.Modifier;
import javax.lang.model.element.TypeElement;
import javax.lang.model.type.DeclaredType;
import javax.lang.model.type.TypeMirror;
import javax.lang.model.util.Types;
public class InputFactory {
private final DirectivesFactory directivesFactory;
private final Types types;
public InputFactory(Types types, DirectivesFactory directivesFactory) {
this.types = types;
this.directivesFactory = directivesFactory;
}
public Input getInput(Element annotatedElement) {
if (annotatedElement.getKind() == ElementKind.CLASS) {
TypeElement typeEl = (TypeElement) annotatedElement;
if (typeEl.getModifiers().contains(Modifier.PRIVATE)) {
throw new InvalidElementException(String.format("Pojo %s must not be private!", annotatedElement),
annotatedElement);
}
if (typeEl.getEnclosingElement().getKind() == ElementKind.CLASS
&& !typeEl.getModifiers().contains(Modifier.STATIC)) {
throw new InvalidElementException(String.format("Pojo %s must not be a non-static inner class!",
annotatedElement), annotatedElement);
}
return getInputForAnnotatedPojo(typeEl);
} else if (annotatedElement.getKind() == ElementKind.CONSTRUCTOR) {
ExecutableElement constrEl = (ExecutableElement) annotatedElement;
if (constrEl.getModifiers().contains(Modifier.PRIVATE)) {
throw new InvalidElementException(String.format("Constructor %s must not be private!", annotatedElement),
annotatedElement);
}
TypeElement typeEl = (TypeElement) constrEl.getEnclosingElement();
if (typeEl.getModifiers().contains(Modifier.PRIVATE)) {
throw new InvalidElementException(String.format("Pojo %s must not be private!", typeEl), annotatedElement);
}
if (typeEl.getEnclosingElement().getKind() == ElementKind.CLASS
&& !typeEl.getModifiers().contains(Modifier.STATIC)) {
throw new InvalidElementException(String.format("Pojo %s must not be a non-static inner class!", typeEl),
annotatedElement);
}
return getInputForAnnotatedConstructor(constrEl);
} else if (annotatedElement.getKind() == ElementKind.METHOD) {
ExecutableElement methodEl = (ExecutableElement) annotatedElement;
// TODO add support for non-static and non-public factory methods
if (!methodEl.getModifiers().contains(Modifier.STATIC)) {
throw new InvalidElementException(String.format("Factory method %s must be static!", annotatedElement),
annotatedElement);
}
if (!methodEl.getModifiers().contains(Modifier.PUBLIC)) {
throw new InvalidElementException(String.format("Factory method %s must be public!", annotatedElement),
annotatedElement);
}
return getInputForAnnotatedFactoryMethod(methodEl);
} else {
throw new InvalidElementException(String.format("Unexpected type %s!", annotatedElement), annotatedElement);
}
}
private Input getInputForAnnotatedFactoryMethod(ExecutableElement methodEl) {
TypeMirror pojoTypeMirror = methodEl.getReturnType();
TypeElement pojoTypeEl = (TypeElement) types.asElement(pojoTypeMirror);
Set<Element> orginatingElements = new HashSet<Element>();
Directives directives = directivesFactory.getDirectives(methodEl, orginatingElements);
return new Input(methodEl, pojoTypeEl, (DeclaredType) pojoTypeMirror, directives, orginatingElements);
}
private Input getInputForAnnotatedConstructor(ExecutableElement constrEl) {
TypeElement pojoTypeEl = (TypeElement) constrEl.getEnclosingElement();
TypeMirror pojoTypeMirror = pojoTypeEl.asType();
Set<Element> orginatingElements = new HashSet<Element>();
Directives directives = directivesFactory.getDirectives(constrEl, orginatingElements);
return new Input(constrEl, pojoTypeEl, (DeclaredType) pojoTypeMirror, directives, orginatingElements);
}
private Input getInputForAnnotatedPojo(TypeElement pojoTypeEl) {
TypeMirror pojoTypeMirror = pojoTypeEl.asType();
Set<Element> orginatingElements = new HashSet<Element>();
Directives directives = directivesFactory.getDirectives(pojoTypeEl, orginatingElements);
return new Input(pojoTypeEl, pojoTypeEl, (DeclaredType) pojoTypeMirror, directives, orginatingElements);
}
}