package net.karneim.pojobuilder.analysis;
import java.util.List;
import javax.lang.model.element.Element;
import javax.lang.model.element.ExecutableElement;
import javax.lang.model.element.TypeElement;
import javax.lang.model.element.VariableElement;
import javax.lang.model.type.DeclaredType;
import javax.lang.model.type.ExecutableType;
import javax.lang.model.type.TypeMirror;
import javax.lang.model.util.ElementFilter;
import javax.lang.model.util.Elements;
import net.karneim.pojobuilder.model.FieldAccessM;
import net.karneim.pojobuilder.model.MethodM;
import net.karneim.pojobuilder.model.PropertyM;
import net.karneim.pojobuilder.model.SetterMethodM;
import net.karneim.pojobuilder.model.TypeM;
public class PojoPropertiesScanner {
private final Elements elements;
private final JavaModelAnalyzerUtil javaModelAnalyzerUtil;
private final TypeMFactory typeMFactory;
public PojoPropertiesScanner(Elements elements, JavaModelAnalyzerUtil javaModelAnalyzerUtil, TypeMFactory typeMFactory) {
this.elements = elements;
this.javaModelAnalyzerUtil = javaModelAnalyzerUtil;
this.typeMFactory = typeMFactory;
}
public void scan(Input input, Output output) {
scanFields(input, output);
scanSetterMethods(input, output);
scanGetterMethods(input, output);
}
private void scanSetterMethods(Input input, Output output) {
TypeElement pojoTypeEl = input.getPojoElement();
DeclaredType pojoClassType = (DeclaredType) pojoTypeEl.asType();
List<? extends Element> memberEls = elements.getAllMembers(pojoTypeEl);
// loop over all setter methods
List<ExecutableElement> methodEls = ElementFilter.methodsIn(memberEls);
for (ExecutableElement methodEl : methodEls) {
if (!javaModelAnalyzerUtil.isStatic(methodEl) && javaModelAnalyzerUtil.isSetterMethod(methodEl)
&& !javaModelAnalyzerUtil.isDeclaredInObject(methodEl)
&& javaModelAnalyzerUtil.isAccessibleForBuilder(methodEl, output.getBuilderModel())) {
String propertyName = javaModelAnalyzerUtil.getPropertyName(methodEl);
ExecutableType execType = (ExecutableType) javaModelAnalyzerUtil.getType(pojoClassType, methodEl);
TypeMirror propertyTypeMirror = execType.getParameterTypes().get(0);
TypeM propertyType = typeMFactory.getTypeM(propertyTypeMirror);
output
.getBuilderModel()
.getProperties()
.getOrCreate(propertyName, propertyType)
.writableVia(
new SetterMethodM(methodEl.getSimpleName().toString(), methodEl.getModifiers()).withVarArgs(
methodEl.isVarArgs()).declaredIn(typeMFactory.getTypeM(input.getPojoType())));
output.getInput().getOrginatingElements().add(javaModelAnalyzerUtil.getCompilationUnit(methodEl));
}
}
}
private void scanFields(Input input, Output output) {
TypeElement pojoTypeEl = input.getPojoElement();
List<? extends Element> memberEls = elements.getAllMembers(pojoTypeEl);
// loop over all fields
List<VariableElement> fieldEls = ElementFilter.fieldsIn(memberEls);
for (VariableElement fieldEl : fieldEls) {
if (!javaModelAnalyzerUtil.isStatic(fieldEl) && !javaModelAnalyzerUtil.isDeclaredInObject(fieldEl)
&& javaModelAnalyzerUtil.isAccessibleForBuilder(fieldEl, output.getBuilderModel())) {
DeclaredType declType = (DeclaredType) pojoTypeEl.asType();
TypeM propertyType = typeMFactory.getTypeM(javaModelAnalyzerUtil.getType(declType, fieldEl));
output
.getBuilderModel()
.getProperties()
.getOrCreate(fieldEl.getSimpleName().toString(), propertyType)
.accessibleVia(
new FieldAccessM(fieldEl.getModifiers()).declaredIn(typeMFactory.getTypeM(input.getPojoType())));
output.getInput().getOrginatingElements().add(javaModelAnalyzerUtil.getCompilationUnit(fieldEl));
}
}
}
private void scanGetterMethods(Input input, Output output) {
TypeElement pojoTypeEl = input.getPojoElement();
DeclaredType pojoClassType = (DeclaredType) pojoTypeEl.asType();
List<? extends Element> memberEls = elements.getAllMembers(pojoTypeEl);
// loop over all setter methods
List<ExecutableElement> methodsEls = ElementFilter.methodsIn(memberEls);
for (ExecutableElement methodEl : methodsEls) {
if (!javaModelAnalyzerUtil.isStatic(methodEl) && javaModelAnalyzerUtil.isGetterMethod(methodEl)
&& !javaModelAnalyzerUtil.isDeclaredInObject(methodEl)
&& javaModelAnalyzerUtil.isAccessibleForBuilder(methodEl, output.getBuilderModel())) {
String propertyName = javaModelAnalyzerUtil.getPropertyName(methodEl);
ExecutableType execType = (ExecutableType) javaModelAnalyzerUtil.getType(pojoClassType, methodEl);
TypeMirror propertyTypeMirror = execType.getReturnType();
TypeM propertyType = typeMFactory.getTypeM(propertyTypeMirror);
PropertyM prop = output.getBuilderModel().getProperties().get(propertyName, propertyType);
if (prop != null) {
prop.readableVia(new MethodM(methodEl.getSimpleName().toString(), methodEl.getModifiers())
.declaredIn(typeMFactory.getTypeM(input.getPojoType())));
}
output.getInput().getOrginatingElements().add(javaModelAnalyzerUtil.getCompilationUnit(methodEl));
}
}
}
}